Also adds a change-service, which maintains the change model. The new router model is maintained by gr-router, which will eventually be moved and renamed to router-service. Change-Id: I15fcf39d1de21dea975a687fb6efb6823d658c22
		
			
				
	
	
		
			257 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			257 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
/**
 | 
						|
 * @license
 | 
						|
 * Copyright (C) 2018 The Android Open Source Project
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
import {
 | 
						|
  GerritNav,
 | 
						|
  RepoDetailView,
 | 
						|
  GroupDetailView,
 | 
						|
} from '../elements/core/gr-navigation/gr-navigation';
 | 
						|
import {
 | 
						|
  RepoName,
 | 
						|
  GroupId,
 | 
						|
  AccountDetailInfo,
 | 
						|
  AccountCapabilityInfo,
 | 
						|
} from '../types/common';
 | 
						|
import {MenuLink} from '../elements/plugins/gr-admin-api/gr-admin-api';
 | 
						|
import {hasOwnProperty} from './common-util';
 | 
						|
import {GerritView} from '../services/router/router-model';
 | 
						|
 | 
						|
const ADMIN_LINKS: NavLink[] = [
 | 
						|
  {
 | 
						|
    name: 'Repositories',
 | 
						|
    noBaseUrl: true,
 | 
						|
    url: '/admin/repos',
 | 
						|
    view: 'gr-repo-list',
 | 
						|
    viewableToAll: true,
 | 
						|
  },
 | 
						|
  {
 | 
						|
    name: 'Groups',
 | 
						|
    section: 'Groups',
 | 
						|
    noBaseUrl: true,
 | 
						|
    url: '/admin/groups',
 | 
						|
    view: 'gr-admin-group-list',
 | 
						|
  },
 | 
						|
  {
 | 
						|
    name: 'Plugins',
 | 
						|
    capability: 'viewPlugins',
 | 
						|
    section: 'Plugins',
 | 
						|
    noBaseUrl: true,
 | 
						|
    url: '/admin/plugins',
 | 
						|
    view: 'gr-plugin-list',
 | 
						|
  },
 | 
						|
];
 | 
						|
 | 
						|
export interface AdminLink {
 | 
						|
  url: string;
 | 
						|
  text: string;
 | 
						|
  capability: string | null;
 | 
						|
  noBaseUrl: boolean;
 | 
						|
  view: null;
 | 
						|
  viewableToAll: boolean;
 | 
						|
  target: '_blank' | null;
 | 
						|
}
 | 
						|
 | 
						|
export interface AdminLinks {
 | 
						|
  links: NavLink[];
 | 
						|
  expandedSection?: SubsectionInterface;
 | 
						|
}
 | 
						|
 | 
						|
export function getAdminLinks(
 | 
						|
  account: AccountDetailInfo | undefined,
 | 
						|
  getAccountCapabilities: () => Promise<AccountCapabilityInfo>,
 | 
						|
  getAdminMenuLinks: () => MenuLink[],
 | 
						|
  options?: AdminNavLinksOption
 | 
						|
): Promise<AdminLinks> {
 | 
						|
  if (!account) {
 | 
						|
    return Promise.resolve(
 | 
						|
      _filterLinks(link => !!link.viewableToAll, getAdminMenuLinks, options)
 | 
						|
    );
 | 
						|
  }
 | 
						|
  return getAccountCapabilities().then(capabilities =>
 | 
						|
    _filterLinks(
 | 
						|
      link => !link.capability || hasOwnProperty(capabilities, link.capability),
 | 
						|
      getAdminMenuLinks,
 | 
						|
      options
 | 
						|
    )
 | 
						|
  );
 | 
						|
}
 | 
						|
 | 
						|
function _filterLinks(
 | 
						|
  filterFn: (link: NavLink) => boolean,
 | 
						|
  getAdminMenuLinks: () => MenuLink[],
 | 
						|
  options?: AdminNavLinksOption
 | 
						|
): AdminLinks {
 | 
						|
  let links: NavLink[] = ADMIN_LINKS.slice(0);
 | 
						|
  let expandedSection: SubsectionInterface | undefined = undefined;
 | 
						|
 | 
						|
  const isExternalLink = (link: MenuLink) => link.url[0] !== '/';
 | 
						|
 | 
						|
  // Append top-level links that are defined by plugins.
 | 
						|
  links.push(
 | 
						|
    ...getAdminMenuLinks().map((link: MenuLink) => {
 | 
						|
      return {
 | 
						|
        url: link.url,
 | 
						|
        name: link.text,
 | 
						|
        capability: link.capability || undefined,
 | 
						|
        noBaseUrl: !isExternalLink(link),
 | 
						|
        view: null,
 | 
						|
        viewableToAll: !link.capability,
 | 
						|
        target: isExternalLink(link) ? '_blank' : null,
 | 
						|
      };
 | 
						|
    })
 | 
						|
  );
 | 
						|
 | 
						|
  links = links.filter(filterFn);
 | 
						|
 | 
						|
  const filteredLinks: NavLink[] = [];
 | 
						|
  const repoName = options && options.repoName;
 | 
						|
  const groupId = options && options.groupId;
 | 
						|
  const groupName = options && options.groupName;
 | 
						|
  const groupIsInternal = options && options.groupIsInternal;
 | 
						|
  const isAdmin = options && options.isAdmin;
 | 
						|
  const groupOwner = options && options.groupOwner;
 | 
						|
 | 
						|
  // Don't bother to get sub-navigation items if only the top level links
 | 
						|
  // are needed. This is used by the main header dropdown.
 | 
						|
  if (!repoName && !groupId) {
 | 
						|
    return {links, expandedSection};
 | 
						|
  }
 | 
						|
 | 
						|
  // Otherwise determine the full set of links and return both the full
 | 
						|
  // set in addition to the subsection that should be displayed if it
 | 
						|
  // exists.
 | 
						|
  for (const link of links) {
 | 
						|
    const linkCopy = {...link};
 | 
						|
    if (linkCopy.name === 'Repositories' && repoName) {
 | 
						|
      linkCopy.subsection = getRepoSubsections(repoName);
 | 
						|
      expandedSection = linkCopy.subsection;
 | 
						|
    } else if (linkCopy.name === 'Groups' && groupId && groupName) {
 | 
						|
      linkCopy.subsection = getGroupSubsections(
 | 
						|
        groupId,
 | 
						|
        groupName,
 | 
						|
        groupIsInternal,
 | 
						|
        isAdmin,
 | 
						|
        groupOwner
 | 
						|
      );
 | 
						|
      expandedSection = linkCopy.subsection;
 | 
						|
    }
 | 
						|
    filteredLinks.push(linkCopy);
 | 
						|
  }
 | 
						|
  return {links: filteredLinks, expandedSection};
 | 
						|
}
 | 
						|
 | 
						|
export function getGroupSubsections(
 | 
						|
  groupId: GroupId,
 | 
						|
  groupName: string,
 | 
						|
  groupIsInternal?: boolean,
 | 
						|
  isAdmin?: boolean,
 | 
						|
  groupOwner?: boolean
 | 
						|
) {
 | 
						|
  const children: SubsectionInterface[] = [];
 | 
						|
  const subsection: SubsectionInterface = {
 | 
						|
    name: groupName,
 | 
						|
    view: GerritNav.View.GROUP,
 | 
						|
    url: GerritNav.getUrlForGroup(groupId),
 | 
						|
    children,
 | 
						|
  };
 | 
						|
  if (groupIsInternal) {
 | 
						|
    children.push({
 | 
						|
      name: 'Members',
 | 
						|
      detailType: GerritNav.GroupDetailView.MEMBERS,
 | 
						|
      view: GerritNav.View.GROUP,
 | 
						|
      url: GerritNav.getUrlForGroupMembers(groupId),
 | 
						|
    });
 | 
						|
  }
 | 
						|
  if (groupIsInternal && (isAdmin || groupOwner)) {
 | 
						|
    children.push({
 | 
						|
      name: 'Audit Log',
 | 
						|
      detailType: GerritNav.GroupDetailView.LOG,
 | 
						|
      view: GerritNav.View.GROUP,
 | 
						|
      url: GerritNav.getUrlForGroupLog(groupId),
 | 
						|
    });
 | 
						|
  }
 | 
						|
  return subsection;
 | 
						|
}
 | 
						|
 | 
						|
export function getRepoSubsections(repoName: RepoName) {
 | 
						|
  return {
 | 
						|
    name: repoName,
 | 
						|
    view: GerritNav.View.REPO,
 | 
						|
    url: GerritNav.getUrlForRepo(repoName),
 | 
						|
    children: [
 | 
						|
      {
 | 
						|
        name: 'Access',
 | 
						|
        view: GerritNav.View.REPO,
 | 
						|
        detailType: GerritNav.RepoDetailView.ACCESS,
 | 
						|
        url: GerritNav.getUrlForRepoAccess(repoName),
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: 'Commands',
 | 
						|
        view: GerritNav.View.REPO,
 | 
						|
        detailType: GerritNav.RepoDetailView.COMMANDS,
 | 
						|
        url: GerritNav.getUrlForRepoCommands(repoName),
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: 'Branches',
 | 
						|
        view: GerritNav.View.REPO,
 | 
						|
        detailType: GerritNav.RepoDetailView.BRANCHES,
 | 
						|
        url: GerritNav.getUrlForRepoBranches(repoName),
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: 'Tags',
 | 
						|
        view: GerritNav.View.REPO,
 | 
						|
        detailType: GerritNav.RepoDetailView.TAGS,
 | 
						|
        url: GerritNav.getUrlForRepoTags(repoName),
 | 
						|
      },
 | 
						|
      {
 | 
						|
        name: 'Dashboards',
 | 
						|
        view: GerritNav.View.REPO,
 | 
						|
        detailType: GerritNav.RepoDetailView.DASHBOARDS,
 | 
						|
        url: GerritNav.getUrlForRepoDashboards(repoName),
 | 
						|
      },
 | 
						|
    ],
 | 
						|
  };
 | 
						|
}
 | 
						|
 | 
						|
export interface SubsectionInterface {
 | 
						|
  name: string;
 | 
						|
  view: GerritView;
 | 
						|
  detailType?: RepoDetailView | GroupDetailView;
 | 
						|
  url: string;
 | 
						|
  children?: SubsectionInterface[];
 | 
						|
}
 | 
						|
 | 
						|
export interface AdminNavLinksOption {
 | 
						|
  repoName?: RepoName;
 | 
						|
  groupId?: GroupId;
 | 
						|
  groupName?: string;
 | 
						|
  groupIsInternal?: boolean;
 | 
						|
  isAdmin?: boolean;
 | 
						|
  groupOwner?: boolean;
 | 
						|
}
 | 
						|
 | 
						|
export interface NavLink {
 | 
						|
  name: string;
 | 
						|
  noBaseUrl: boolean;
 | 
						|
  url: string;
 | 
						|
  view: string | null;
 | 
						|
  viewableToAll?: boolean;
 | 
						|
  section?: string;
 | 
						|
  capability?: string;
 | 
						|
  target?: string | null;
 | 
						|
  subsection?: SubsectionInterface;
 | 
						|
}
 |