Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3918 from karthikjeeyar/add-resource-menu
feat(topology-resourcemenu): add resource menu actions
- Loading branch information
Showing
12 changed files
with
311 additions
and
13 deletions.
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
frontend/packages/dev-console/src/actions/add-resources.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import * as React from 'react'; | ||
import { | ||
GitAltIcon, | ||
OsImageIcon, | ||
CatalogIcon, | ||
CubeIcon, | ||
DatabaseIcon, | ||
} from '@patternfly/react-icons'; | ||
import { ImportOptions } from '../components/import/import-types'; | ||
import { KebabAction, createKebabAction } from '../utils/add-resources-menu-utils'; | ||
|
||
export const fromGit = createKebabAction('From Git', <GitAltIcon />, ImportOptions.GIT); | ||
|
||
export const containerImage = createKebabAction( | ||
'Container Image', | ||
<OsImageIcon />, | ||
ImportOptions.CONTAINER, | ||
); | ||
|
||
export const fromCatalog = createKebabAction( | ||
'From Catalog', | ||
<CatalogIcon />, | ||
ImportOptions.CATALOG, | ||
false, | ||
); | ||
export const fromDockerfile = createKebabAction( | ||
'From Dockerfile', | ||
<CubeIcon />, | ||
ImportOptions.DOCKERFILE, | ||
); | ||
|
||
export const fromDatabaseCatalog = createKebabAction( | ||
'Database', | ||
<DatabaseIcon />, | ||
ImportOptions.DATABASE, | ||
false, | ||
); | ||
|
||
export const addResourceMenu: KebabAction[] = [ | ||
fromGit, | ||
containerImage, | ||
fromCatalog, | ||
fromDockerfile, | ||
fromDatabaseCatalog, | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 25 additions & 0 deletions
25
frontend/packages/dev-console/src/components/topology/actions/graphActions.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import * as _ from 'lodash'; | ||
import { KebabOption } from '@console/internal/components/utils/kebab'; | ||
import { GraphElement, Node } from '@console/topology'; | ||
import { TYPE_WORKLOAD } from '../const'; | ||
import { addResourceMenu } from '../../../actions/add-resources'; | ||
import { TopologyDataObject } from '../topology-types'; | ||
|
||
const addResourcesMenu = (workload: TopologyDataObject) => { | ||
let menuItems = []; | ||
if (_.isEmpty(workload)) { | ||
return menuItems; | ||
} | ||
const primaryResource = _.get(workload, ['resources', 'obj'], null); | ||
if (primaryResource) { | ||
menuItems = addResourceMenu.map((menuItem) => menuItem(primaryResource, false)); | ||
} | ||
return menuItems; | ||
}; | ||
|
||
export const graphActions = (elements: GraphElement[]): KebabOption[] => { | ||
const primaryResource: Node = _.find(elements, { | ||
type: TYPE_WORKLOAD, | ||
}) as Node; | ||
return [...addResourcesMenu(primaryResource.getData())]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
frontend/packages/dev-console/src/components/topology/components/GraphComponent.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
frontend/packages/dev-console/src/utils/__tests__/add-resources-menu-utils.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { URL } from 'url'; | ||
import * as React from 'react'; | ||
import { GitAltIcon } from '@patternfly/react-icons'; | ||
import { KebabOption, asAccessReview } from '@console/internal/components/utils'; | ||
import { DeploymentModel } from '@console/internal/models'; | ||
import { | ||
getMenuPath, | ||
getAddPageUrl, | ||
createKebabAction, | ||
KebabAction, | ||
} from '../add-resources-menu-utils'; | ||
import { | ||
transformTopologyData, | ||
getTopologyResourceObject, | ||
} from '../../components/topology/topology-utils'; | ||
import { ImportOptions } from '../../components/import/import-types'; | ||
import { MockResources } from '../../components/topology/__tests__/topology-test-data'; | ||
import { TopologyDataResources } from '../../components/topology/topology-types'; | ||
|
||
const getTopologyData = (mockData: TopologyDataResources, transformByProp: string[]) => { | ||
const result = transformTopologyData(mockData, transformByProp); | ||
const keys = Object.keys(result.topology); | ||
const resource = getTopologyResourceObject(result.topology[keys[0]]); | ||
return { resource }; | ||
}; | ||
|
||
describe('addResourceMenuUtils: ', () => { | ||
it('should give proper menu item path based on the application', () => { | ||
expect(getMenuPath(true)).toEqual('Add to Application'); | ||
expect(getMenuPath(false)).toEqual('Add to Project'); | ||
}); | ||
|
||
it('should return the page url with proper queryparams for git import flow', () => { | ||
const { resource } = getTopologyData(MockResources, ['deployments']); | ||
const url = new URL(getAddPageUrl(resource, ImportOptions.GIT, true), 'https://mock.test.com'); | ||
|
||
expect(url.pathname).toBe('/import/ns/testproject1'); | ||
expect(url.searchParams.get('importType')).toBe('git'); | ||
expect(url.searchParams.get('application')).toBe('application-1'); | ||
expect(url.searchParams.get('isKnativeDisabled')).toBe('true'); | ||
expect(Array.from(url.searchParams.entries())).toHaveLength(3); | ||
}); | ||
|
||
it('should return the page url without application params in the url', () => { | ||
const { resource } = getTopologyData(MockResources, ['deployments']); | ||
const url = new URL(getAddPageUrl(resource, ImportOptions.GIT, false), 'https://mock.test.com'); | ||
expect(url.searchParams.has('application')).toBe(false); | ||
}); | ||
|
||
it('should return the page url with proper queryparams for container image flow', () => { | ||
const { resource } = getTopologyData(MockResources, ['deployments']); | ||
const url = new URL( | ||
getAddPageUrl(resource, ImportOptions.CONTAINER, true), | ||
'https://mock.test.com', | ||
); | ||
expect(url.pathname).toBe('/deploy-image/ns/testproject1'); | ||
expect(url.searchParams.get('application')).toBe('application-1'); | ||
expect(url.searchParams.get('isKnativeDisabled')).toBe('true'); | ||
expect(Array.from(url.searchParams.entries())).toHaveLength(2); | ||
}); | ||
|
||
it('should return the page url with proper queryparams for catalog flow', () => { | ||
const { resource } = getTopologyData(MockResources, ['deployments']); | ||
const url = new URL( | ||
getAddPageUrl(resource, ImportOptions.CATALOG, true), | ||
'https://mock.test.com', | ||
); | ||
expect(url.pathname).toBe('/catalog/ns/testproject1'); | ||
expect(url.searchParams.get('application')).toBe('application-1'); | ||
expect(url.searchParams.get('isKnativeDisabled')).toBe('true'); | ||
expect(Array.from(url.searchParams.entries())).toHaveLength(2); | ||
}); | ||
|
||
it('should return the page url with proper queryparams for dockerfile flow', () => { | ||
const { resource } = getTopologyData(MockResources, ['deployments']); | ||
const url = new URL( | ||
getAddPageUrl(resource, ImportOptions.DOCKERFILE, true), | ||
'https://mock.test.com', | ||
); | ||
expect(url.pathname).toBe('/import/ns/testproject1'); | ||
expect(url.searchParams.get('importType')).toBe('docker'); | ||
expect(url.searchParams.get('application')).toBe('application-1'); | ||
expect(url.searchParams.get('isKnativeDisabled')).toBe('true'); | ||
expect(Array.from(url.searchParams.entries())).toHaveLength(3); | ||
}); | ||
|
||
it('should return the page url with proper queryparams for database flow', () => { | ||
const { resource } = getTopologyData(MockResources, ['deployments']); | ||
const url = new URL( | ||
getAddPageUrl(resource, ImportOptions.DATABASE, true), | ||
'https://mock.test.com', | ||
); | ||
expect(url.pathname).toBe('/catalog/ns/testproject1'); | ||
expect(url.searchParams.get('category')).toBe('databases'); | ||
expect(url.searchParams.get('application')).toBe('application-1'); | ||
expect(url.searchParams.get('isKnativeDisabled')).toBe('true'); | ||
expect(Array.from(url.searchParams.entries())).toHaveLength(3); | ||
}); | ||
|
||
it('it should return a valid kebabAction on invoking createKebabAction', () => { | ||
const { resource } = getTopologyData(MockResources, ['deployments']); | ||
const icon = <GitAltIcon />; | ||
const hasApplication = true; | ||
const label = 'From Git'; | ||
|
||
const kebabAction: KebabAction = createKebabAction(label, icon, ImportOptions.GIT); | ||
const kebabOption: KebabOption = kebabAction(resource, hasApplication); | ||
|
||
expect(kebabOption.label).toEqual(label); | ||
expect(kebabOption.icon).toEqual(icon); | ||
expect(kebabOption.path).toEqual('Add to Application'); | ||
expect(kebabOption.href).toEqual(getAddPageUrl(resource, ImportOptions.GIT, hasApplication)); | ||
expect(kebabOption.accessReview).toEqual(asAccessReview(DeploymentModel, resource, 'create')); | ||
}); | ||
}); |
72 changes: 72 additions & 0 deletions
72
frontend/packages/dev-console/src/utils/add-resources-menu-utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import * as _ from 'lodash'; | ||
import { K8sResourceKind, modelFor, referenceFor } from '@console/internal/module/k8s'; | ||
import { KebabOption, asAccessReview } from '@console/internal/components/utils'; | ||
import { ImportOptions } from '../components/import/import-types'; | ||
|
||
const PART_OF = 'app.kubernetes.io/part-of'; | ||
|
||
export const getAddPageUrl = ( | ||
obj: K8sResourceKind, | ||
type: string, | ||
hasApplication: boolean, | ||
): string => { | ||
let pageUrl = ''; | ||
const params = new URLSearchParams(); | ||
const appGroup = _.get(obj, ['metadata', 'labels', PART_OF], ''); | ||
const { | ||
metadata: { namespace: ns }, | ||
} = obj; | ||
switch (type) { | ||
case ImportOptions.GIT: | ||
pageUrl = `/import/ns/${ns}`; | ||
params.append('importType', 'git'); | ||
break; | ||
case ImportOptions.CONTAINER: | ||
pageUrl = `/deploy-image/ns/${ns}`; | ||
break; | ||
case ImportOptions.CATALOG: | ||
pageUrl = `/catalog/ns/${ns}`; | ||
break; | ||
case ImportOptions.DOCKERFILE: | ||
pageUrl = `/import/ns/${ns}`; | ||
params.append('importType', 'docker'); | ||
break; | ||
case ImportOptions.DATABASE: | ||
pageUrl = `/catalog/ns/${ns}`; | ||
params.append('category', 'databases'); | ||
break; | ||
default: | ||
throw new Error('Invalid Import option provided'); | ||
} | ||
params.append('isKnativeDisabled', 'true'); | ||
if (hasApplication && appGroup) { | ||
params.append('application', encodeURIComponent(appGroup)); | ||
} | ||
return `${pageUrl}?${params.toString()}`; | ||
}; | ||
|
||
export const getMenuPath = (hasApplication: boolean): string => | ||
hasApplication ? 'Add to Application' : 'Add to Project'; | ||
|
||
type KebabFactory = ( | ||
label: string, | ||
icon: React.ReactNode, | ||
importType: ImportOptions, | ||
checkAccess?: boolean, | ||
) => KebabAction; | ||
|
||
export type KebabAction = (obj?: K8sResourceKind, hasApplication?: boolean) => KebabOption; | ||
|
||
export const createKebabAction: KebabFactory = (label, icon, importType, checkAccess = true) => ( | ||
obj: K8sResourceKind, | ||
hasApplication: boolean, | ||
) => { | ||
const resourceModel = modelFor(referenceFor(obj)); | ||
return { | ||
label, | ||
icon, | ||
path: getMenuPath(hasApplication), | ||
href: getAddPageUrl(obj, importType, hasApplication), | ||
accessReview: checkAccess && asAccessReview(resourceModel, obj, 'create'), | ||
}; | ||
}; |
Oops, something went wrong.