Skip to content

Commit

Permalink
Allow plugins to specify nav sections and specify their order
Browse files Browse the repository at this point in the history
  • Loading branch information
jeff-phillips-18 committed Nov 20, 2020
1 parent 33f3773 commit 94ce8db
Show file tree
Hide file tree
Showing 18 changed files with 354 additions and 82 deletions.
122 changes: 122 additions & 0 deletions frontend/__tests__/components/nav/perspective-nav.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { getSortedNavItems } from '@console/internal/components/nav/perspective-nav';
import { LoadedExtension, NavItem, NavSection, SeparatorNavItem } from '@console/plugin-sdk/src';

const mockNavItems: LoadedExtension<NavSection | NavItem | SeparatorNavItem>[] = [
{
type: 'Nav/Section',
properties: {
id: 'test1',
},
pluginID: 'test-plugin-id',
pluginName: 'test-plugin-name',
uid: 'test-plugin-uid',
},
{
type: 'Nav/Section',
properties: {
id: 'test2',
},
pluginID: 'test-plugin-id',
pluginName: 'test-plugin-name',
uid: 'test-plugin-uid',
},
{
type: 'Nav/Section',
properties: {
id: 'test3',
},
pluginID: 'test-plugin-id',
pluginName: 'test-plugin-name',
uid: 'test-plugin-uid',
},
{
type: 'Nav/Section',
properties: {
id: 'test4',
},
pluginID: 'test-plugin-id',
pluginName: 'test-plugin-name',
uid: 'test-plugin-uid',
},
{
type: 'Nav/Section',
properties: {
id: 'test5',
},
pluginID: 'test-plugin-id',
pluginName: 'test-plugin-name',
uid: 'test-plugin-uid',
},
{
type: 'Nav/Section',
properties: {
id: 'test6',
},
pluginID: 'test-plugin-id',
pluginName: 'test-plugin-name',
uid: 'test-plugin-uid',
},
{
type: 'NavItem/Separator',
properties: {
id: 'test7',
componentProps: {
testID: 'test-sep',
},
},
pluginID: 'test-plugin-id',
pluginName: 'test-plugin-name',
uid: 'test-plugin-uid',
},
];

describe('perspective-nav insertPositionedItems', () => {
it('should order items that are not positioned', () => {
const sortedItems = getSortedNavItems(mockNavItems);
expect(sortedItems.map((i) => i.properties.id)).toEqual(
mockNavItems.map((i) => i.properties.id),
);
});

it('should order items that are positioned', () => {
mockNavItems[0].properties.insertAfter = 'test2';
let sortedItems = getSortedNavItems(mockNavItems);
expect(sortedItems.map((i) => i.properties.id).indexOf('test1')).toBe(1);

delete mockNavItems[0].properties.insertAfter;
mockNavItems[0].properties.insertBefore = 'test5';
sortedItems = getSortedNavItems(mockNavItems);
expect(sortedItems.map((i) => i.properties.id).indexOf('test1')).toBe(3);

delete mockNavItems[0].properties.insertBefore;
mockNavItems[0].properties.insertAfter = ['x', 'y', 'test3', 'z'];
sortedItems = getSortedNavItems(mockNavItems);
expect(sortedItems.map((i) => i.properties.id).indexOf('test1')).toBe(2);

delete mockNavItems[0].properties.insertAfter;
mockNavItems[0].properties.insertBefore = ['x', 'y', 'test3', 'z'];
sortedItems = getSortedNavItems(mockNavItems);
expect(sortedItems.map((i) => i.properties.id).indexOf('test1')).toBe(1);

// Before takes precedence
mockNavItems[0].properties.insertAfter = 'test6';
sortedItems = getSortedNavItems(mockNavItems);
expect(sortedItems.map((i) => i.properties.id).indexOf('test1')).toBe(1);
});

it('should order items that are positioned on positioned items', () => {
delete mockNavItems[0].properties.insertBefore;
mockNavItems[0].properties.insertAfter = 'test6';
mockNavItems[5].properties.insertAfter = 'test4';
let sortedItems = getSortedNavItems(mockNavItems);
expect(sortedItems.map((i) => i.properties.id).indexOf('test6')).toBe(3);
expect(sortedItems.map((i) => i.properties.id).indexOf('test1')).toBe(4);
expect(sortedItems.map((i) => i.properties.id).indexOf('test7')).toBe(6);

mockNavItems[6].properties.insertBefore = 'test1';
sortedItems = getSortedNavItems(mockNavItems);
expect(sortedItems.map((i) => i.properties.id).indexOf('test6')).toBe(3);
expect(sortedItems.map((i) => i.properties.id).indexOf('test1')).toBe(5);
expect(sortedItems.map((i) => i.properties.id).indexOf('test7')).toBe(4);
});
});
4 changes: 2 additions & 2 deletions frontend/packages/console-app/src/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ const plugin: Plugin<ConsumedExtensions> = [
{
type: 'NavItem/ResourceCluster',
properties: {
id: 'storage',
section: 'Storage',
id: 'volumesnapshots',
section: 'storage',
componentProps: {
name: 'Volume Snapshot Contents',
resource: referenceForModel(VolumeSnapshotContentModel),
Expand Down
26 changes: 21 additions & 5 deletions frontend/packages/console-demo-plugin/src/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
ResourceListPage,
ResourceDetailsPage,
Perspective,
NavSection,
YAMLTemplate,
RoutePage,
DashboardsOverviewHealthPrometheusSubsystem,
Expand Down Expand Up @@ -43,6 +44,7 @@ type ConsumedExtensions =
| ResourceListPage
| ResourceDetailsPage
| Perspective
| NavSection
| YAMLTemplate
| RoutePage
| DashboardsOverviewHealthPrometheusSubsystem
Expand Down Expand Up @@ -73,10 +75,17 @@ const plugin: Plugin<ConsumedExtensions> = [
},
},
{
type: 'NavItem/Href',
type: 'Nav/Section',
properties: {
id: 'home',
section: 'Home',
name: 'Home',
},
},
{
type: 'NavItem/Href',
properties: {
id: 'testhreflink',
section: 'home',
componentProps: {
name: 'Test Href Link',
href: '/test',
Expand All @@ -90,7 +99,7 @@ const plugin: Plugin<ConsumedExtensions> = [
type: 'NavItem/ResourceNS',
properties: {
id: 'testresourcens',
section: 'Home',
section: 'home',
componentProps: {
name: 'Test ResourceNS Link',
resource: 'pods',
Expand All @@ -104,7 +113,7 @@ const plugin: Plugin<ConsumedExtensions> = [
type: 'NavItem/ResourceCluster',
properties: {
id: 'testresourcecluster',
section: 'Home',
section: 'home',
componentProps: {
name: 'Test ResourceCluster Link',
resource: 'projects',
Expand Down Expand Up @@ -191,12 +200,19 @@ const plugin: Plugin<ConsumedExtensions> = [
},
},
},
{
type: 'Nav/Section',
properties: {
id: 'advanced',
name: 'Advanced',
},
},
{
type: 'NavItem/ResourceCluster',
properties: {
id: 'testprojects',
perspective: 'test',
section: 'Advanced',
section: 'advanced',
componentProps: {
name: 'Test Projects',
resource: 'projects',
Expand Down
1 change: 1 addition & 0 deletions frontend/packages/console-plugin-sdk/src/typings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from './features';
export * from './kebab-actions';
export * from './models';
export * from './nav-items';
export * from './nav-section';
export * from './overview';
export * from './pages';
export * from './perspectives';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ namespace ExtensionProperties {
id: string;
/** Perspective id to which this item belongs to. If not specified, use the default perspective. */
perspective?: string;
/** Nav section to which this item belongs to.If not specified, render item as top-level link. */
/** Nav section to which this item belongs to. If not specified, render item as top-level link. */
section?: string;
/** Nav group to which this item belongs to. Add items to a grouping with a separator above */
group?: string;
/** Props to pass to the corresponding `NavLink` component. */
componentProps: Pick<NavLinkProps, 'name' | 'startsWith' | 'testID' | 'data-tour-id'>;
/*
Expand Down
24 changes: 24 additions & 0 deletions frontend/packages/console-plugin-sdk/src/typings/nav-section.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Extension } from './base';

namespace ExtensionProperties {
export interface NavSection {
/** Section id, should be unique for all sections (and top level items) */
id: string;
/** Perspective id to which this section belongs to. If not specified, use the default perspective. */
perspective?: string;
/** Title for the section, if none only a separator will be shown above the section */
name?: string;
/** Nav section before which this section should be placed. For arrays, first one found in order is used */
insertBefore?: string | string[];
/** Nav section after which this section should be placed (before takes precedence). For arrays, first one found in order is used */
insertAfter?: string | string[];
}
}

export interface NavSection extends Extension<ExtensionProperties.NavSection> {
type: 'Nav/Section';
}

export const isNavSection = (e: Extension): e is NavSection => {
return e.type === 'Nav/Section';
};
2 changes: 1 addition & 1 deletion frontend/packages/container-security/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const plugin: Plugin<ConsumedExtensions> = [
properties: {
id: 'imagevulnerabilities',
perspective: 'admin',
section: 'Administration',
section: 'administration',
insertBefore: 'customresourcedefinitions',
componentProps: {
name: 'Image Vulnerabilities',
Expand Down
32 changes: 24 additions & 8 deletions frontend/packages/dev-console/src/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
ModelDefinition,
ModelFeatureFlag,
KebabActions,
NavSection,
HrefNavItem,
ResourceNSNavItem,
ResourceClusterNavItem,
Expand Down Expand Up @@ -67,6 +68,7 @@ import { CatalogConsumedExtensions, catalogPlugin } from './components/catalog/c
type ConsumedExtensions =
| ModelDefinition
| ModelFeatureFlag
| NavSection
| HrefNavItem
| ResourceClusterNavItem
| ResourceNSNavItem
Expand Down Expand Up @@ -107,12 +109,26 @@ const plugin: Plugin<ConsumedExtensions> = [
flag: FLAG_OPENSHIFT_GITOPS,
},
},
{
type: 'Nav/Section',
properties: {
id: 'top',
perspective: 'dev',
},
},
{
type: 'Nav/Section',
properties: {
id: 'resources',
perspective: 'dev',
},
},
{
type: 'NavItem/Href',
properties: {
id: 'add',
perspective: 'dev',
group: 'top',
section: 'top',
componentProps: {
name: '+Add',
href: '/add',
Expand All @@ -125,7 +141,7 @@ const plugin: Plugin<ConsumedExtensions> = [
properties: {
id: 'topology',
perspective: 'dev',
group: 'top',
section: 'top',
componentProps: {
name: 'Topology',
href: '/topology',
Expand All @@ -141,7 +157,7 @@ const plugin: Plugin<ConsumedExtensions> = [
properties: {
id: 'monitoring',
perspective: 'dev',
group: 'top',
section: 'top',
componentProps: {
name: 'Monitoring',
href: '/dev-monitoring',
Expand All @@ -158,7 +174,7 @@ const plugin: Plugin<ConsumedExtensions> = [
properties: {
id: 'search',
perspective: 'dev',
group: 'top',
section: 'top',
componentProps: {
name: 'Search',
href: '/search',
Expand All @@ -172,7 +188,7 @@ const plugin: Plugin<ConsumedExtensions> = [
properties: {
id: 'builds',
perspective: 'dev',
group: 'resources',
section: 'resources',
componentProps: {
name: 'Builds',
resource: 'buildconfigs',
Expand All @@ -188,7 +204,7 @@ const plugin: Plugin<ConsumedExtensions> = [
properties: {
id: 'applicationstages',
perspective: 'dev',
group: 'resources',
section: 'resources',
componentProps: {
name: 'Application Stages',
href: '/applicationstages',
Expand All @@ -204,7 +220,7 @@ const plugin: Plugin<ConsumedExtensions> = [
properties: {
id: 'helm',
perspective: 'dev',
group: 'resources',
section: 'resources',
componentProps: {
name: 'Helm',
href: '/helm-releases',
Expand All @@ -220,7 +236,7 @@ const plugin: Plugin<ConsumedExtensions> = [
properties: {
id: 'project',
perspective: 'dev',
group: 'resources',
section: 'resources',
componentProps: {
name: 'Project',
href: '/project-details',
Expand Down

0 comments on commit 94ce8db

Please sign in to comment.