mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-04 01:34:27 +00:00 
			
		
		
		
	Fix incorrect checkbox behaviors in the dashboard repolist's filter (#23147)
Co-author: yp05327 , this PR is based on yp05327's #22813. The problems of the old DashboardRepoList / repolist.tmpl: * It mixes many different frameworks together * It "just works", bug on bug * It uses many anti-pattern of Vue This PR: * Fix bugs and close #22800 * Decouple the "checkbox" elements from Fomantic UI (only use CSS styles) * Simplify the HTML layout * Simplify JS logic * Make it easier to refactor the DashboardRepoList into a pure Vue component in the future. ### Screenshots #### Default  #### Click "Archived" to make it checked  #### Click "Archived" to make it intermediate  #### Click "Archived" to make it unchecked  --------- Co-authored-by: yp05327 <576951401@qq.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
		@@ -46,49 +46,32 @@
 | 
			
		||||
					<div class="ui dropdown icon button" title="{{.locale.Tr "home.filter"}}">
 | 
			
		||||
						<i class="icon gt-df gt-ac gt-jc gt-m-0">{{svg "octicon-filter" 16}}</i>
 | 
			
		||||
						<div class="menu">
 | 
			
		||||
							<div class="item">
 | 
			
		||||
								<a @click="toggleArchivedFilter()">
 | 
			
		||||
									<div class="ui checkbox" id="archivedFilterCheckbox" title="{{.locale.Tr "home.show_both_archived_unarchived"}}" v-if="archivedFilter === 'both'">
 | 
			
		||||
										<input type="checkbox">
 | 
			
		||||
										<label>
 | 
			
		||||
											{{svg "octicon-archive" 16 "gt-mr-2"}}
 | 
			
		||||
											{{.locale.Tr "home.show_archived"}}
 | 
			
		||||
										</label>
 | 
			
		||||
									</div>
 | 
			
		||||
									<div class="ui checkbox" id="archivedFilterCheckbox" title="{{.locale.Tr "home.show_only_unarchived"}}" v-if="archivedFilter === 'unarchived'">
 | 
			
		||||
										<input type="checkbox">
 | 
			
		||||
										<label>
 | 
			
		||||
											{{svg "octicon-archive" 16 "gt-mr-2"}}
 | 
			
		||||
											{{.locale.Tr "home.show_archived"}}
 | 
			
		||||
										</label>
 | 
			
		||||
									</div>
 | 
			
		||||
									<div class="ui checkbox" id="archivedFilterCheckbox" title="{{.locale.Tr "home.show_only_archived"}}" v-if="archivedFilter === 'archived'">
 | 
			
		||||
										<input type="checkbox">
 | 
			
		||||
							<a class="item" @click="toggleArchivedFilter()">
 | 
			
		||||
								<div class="ui checkbox"
 | 
			
		||||
											ref="checkboxArchivedFilter"
 | 
			
		||||
											data-title-both="{{.locale.Tr "home.show_both_archived_unarchived"}}"
 | 
			
		||||
											data-title-unarchived="{{.locale.Tr "home.show_only_unarchived"}}"
 | 
			
		||||
											data-title-archived="{{.locale.Tr "home.show_only_archived"}}"
 | 
			
		||||
											:title="checkboxArchivedFilterTitle"
 | 
			
		||||
								>
 | 
			
		||||
									<!--the "hidden" is necessary to make the checkbox work without Fomantic UI js,
 | 
			
		||||
											otherwise if the "input" handles click event for intermediate status, it breaks the internal state-->
 | 
			
		||||
									<input type="checkbox" class="hidden" v-bind.prop="checkboxArchivedFilterProps">
 | 
			
		||||
									<label>
 | 
			
		||||
										{{svg "octicon-archive" 16 "gt-mr-2"}}
 | 
			
		||||
										{{.locale.Tr "home.show_archived"}}
 | 
			
		||||
									</label>
 | 
			
		||||
								</div>
 | 
			
		||||
							</a>
 | 
			
		||||
							</div>
 | 
			
		||||
							<div class="item">
 | 
			
		||||
								<a @click="togglePrivateFilter()">
 | 
			
		||||
									<div class="ui checkbox" id="privateFilterCheckbox" title="{{.locale.Tr "home.show_both_private_public"}}" v-if="privateFilter === 'both'">
 | 
			
		||||
										<input type="checkbox">
 | 
			
		||||
										<label>
 | 
			
		||||
											{{svg "octicon-lock" 16 "gt-mr-2"}}
 | 
			
		||||
											{{.locale.Tr "home.show_private"}}
 | 
			
		||||
										</label>
 | 
			
		||||
									</div>
 | 
			
		||||
									<div class="ui checkbox" id="privateFilterCheckbox" title="{{.locale.Tr "home.show_only_public"}}" v-if="privateFilter === 'public'">
 | 
			
		||||
										<input type="checkbox">
 | 
			
		||||
										<label>
 | 
			
		||||
											{{svg "octicon-lock" 16 "gt-mr-2"}}
 | 
			
		||||
											{{.locale.Tr "home.show_private"}}
 | 
			
		||||
										</label>
 | 
			
		||||
									</div>
 | 
			
		||||
									<div class="ui checkbox" id="privateFilterCheckbox" title="{{.locale.Tr "home.show_only_private"}}" v-if="privateFilter === 'private'">
 | 
			
		||||
										<input type="checkbox">
 | 
			
		||||
							<a class="item" @click="togglePrivateFilter()">
 | 
			
		||||
								<div class="ui checkbox"
 | 
			
		||||
											ref="checkboxPrivateFilter"
 | 
			
		||||
											data-title-both="{{.locale.Tr "home.show_both_private_public"}}"
 | 
			
		||||
											data-title-public="{{.locale.Tr "home.show_only_public"}}"
 | 
			
		||||
											data-title-private="{{.locale.Tr "home.show_only_private"}}"
 | 
			
		||||
											:title="checkboxPrivateFilterTitle"
 | 
			
		||||
								>
 | 
			
		||||
									<input type="checkbox" class="hidden" v-bind.prop="checkboxPrivateFilterProps">
 | 
			
		||||
									<label>
 | 
			
		||||
										{{svg "octicon-lock" 16 "gt-mr-2"}}
 | 
			
		||||
										{{.locale.Tr "home.show_private"}}
 | 
			
		||||
@@ -98,7 +81,6 @@
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="ui secondary tiny pointing borderless menu center grid repos-filter">
 | 
			
		||||
					<a class="item" :class="{active: reposFilter === 'all'}" @click="changeReposFilter('all')">
 | 
			
		||||
						{{.locale.Tr "all"}}
 | 
			
		||||
 
 | 
			
		||||
@@ -87,6 +87,7 @@ function initVueComponents(app) {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        hasMounted: false, // accessing $refs in computed() need to wait for mounted
 | 
			
		||||
        tab,
 | 
			
		||||
        repos: [],
 | 
			
		||||
        reposTotalCount: 0,
 | 
			
		||||
@@ -134,7 +135,19 @@ function initVueComponents(app) {
 | 
			
		||||
      },
 | 
			
		||||
      repoTypeCount() {
 | 
			
		||||
        return this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`];
 | 
			
		||||
      }
 | 
			
		||||
      },
 | 
			
		||||
      checkboxArchivedFilterTitle() {
 | 
			
		||||
        return this.hasMounted && this.$refs.checkboxArchivedFilter?.getAttribute(`data-title-${this.archivedFilter}`);
 | 
			
		||||
      },
 | 
			
		||||
      checkboxArchivedFilterProps() {
 | 
			
		||||
        return {checked: this.archivedFilter === 'archived', indeterminate: this.archivedFilter === 'both'};
 | 
			
		||||
      },
 | 
			
		||||
      checkboxPrivateFilterTitle() {
 | 
			
		||||
        return this.hasMounted && this.$refs.checkboxPrivateFilter?.getAttribute(`data-title-${this.privateFilter}`);
 | 
			
		||||
      },
 | 
			
		||||
      checkboxPrivateFilterProps() {
 | 
			
		||||
        return {checked: this.privateFilter === 'private', indeterminate: this.privateFilter === 'both'};
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    mounted() {
 | 
			
		||||
@@ -144,10 +157,11 @@ function initVueComponents(app) {
 | 
			
		||||
        initTooltip(elTooltip);
 | 
			
		||||
      }
 | 
			
		||||
      $(el).find('.dropdown').dropdown();
 | 
			
		||||
      this.setCheckboxes();
 | 
			
		||||
      nextTick(() => {
 | 
			
		||||
        this.$refs.search.focus();
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      this.hasMounted = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    methods: {
 | 
			
		||||
@@ -156,39 +170,6 @@ function initVueComponents(app) {
 | 
			
		||||
        this.updateHistory();
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      setCheckboxes() {
 | 
			
		||||
        switch (this.archivedFilter) {
 | 
			
		||||
          case 'unarchived':
 | 
			
		||||
            $('#archivedFilterCheckbox').checkbox('set unchecked');
 | 
			
		||||
            break;
 | 
			
		||||
          case 'archived':
 | 
			
		||||
            $('#archivedFilterCheckbox').checkbox('set checked');
 | 
			
		||||
            break;
 | 
			
		||||
          case 'both':
 | 
			
		||||
            $('#archivedFilterCheckbox').checkbox('set indeterminate');
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
            this.archivedFilter = 'unarchived';
 | 
			
		||||
            $('#archivedFilterCheckbox').checkbox('set unchecked');
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        switch (this.privateFilter) {
 | 
			
		||||
          case 'public':
 | 
			
		||||
            $('#privateFilterCheckbox').checkbox('set unchecked');
 | 
			
		||||
            break;
 | 
			
		||||
          case 'private':
 | 
			
		||||
            $('#privateFilterCheckbox').checkbox('set checked');
 | 
			
		||||
            break;
 | 
			
		||||
          case 'both':
 | 
			
		||||
            $('#privateFilterCheckbox').checkbox('set indeterminate');
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
            this.privateFilter = 'both';
 | 
			
		||||
            $('#privateFilterCheckbox').checkbox('set indeterminate');
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      changeReposFilter(filter) {
 | 
			
		||||
        this.reposFilter = filter;
 | 
			
		||||
        this.repos = [];
 | 
			
		||||
@@ -245,45 +226,29 @@ function initVueComponents(app) {
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      toggleArchivedFilter() {
 | 
			
		||||
        switch (this.archivedFilter) {
 | 
			
		||||
          case 'both':
 | 
			
		||||
            this.archivedFilter = 'unarchived';
 | 
			
		||||
            break;
 | 
			
		||||
          case 'unarchived':
 | 
			
		||||
        if (this.archivedFilter === 'unarchived') {
 | 
			
		||||
          this.archivedFilter = 'archived';
 | 
			
		||||
            break;
 | 
			
		||||
          case 'archived':
 | 
			
		||||
        } else if (this.archivedFilter === 'archived') {
 | 
			
		||||
          this.archivedFilter = 'both';
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
        } else { // including both
 | 
			
		||||
          this.archivedFilter = 'unarchived';
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        this.page = 1;
 | 
			
		||||
        this.repos = [];
 | 
			
		||||
        this.setCheckboxes();
 | 
			
		||||
        this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
 | 
			
		||||
        this.searchRepos();
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      togglePrivateFilter() {
 | 
			
		||||
        switch (this.privateFilter) {
 | 
			
		||||
          case 'both':
 | 
			
		||||
        if (this.privateFilter === 'both') {
 | 
			
		||||
          this.privateFilter = 'public';
 | 
			
		||||
            break;
 | 
			
		||||
          case 'public':
 | 
			
		||||
        } else if (this.privateFilter === 'public') {
 | 
			
		||||
          this.privateFilter = 'private';
 | 
			
		||||
            break;
 | 
			
		||||
          case 'private':
 | 
			
		||||
        } else { // including private
 | 
			
		||||
          this.privateFilter = 'both';
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
            this.privateFilter = 'both';
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        this.page = 1;
 | 
			
		||||
        this.repos = [];
 | 
			
		||||
        this.setCheckboxes();
 | 
			
		||||
        this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
 | 
			
		||||
        this.searchRepos();
 | 
			
		||||
      },
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user