From 31978462402ec4b52101d5a24c0384fd652b646a Mon Sep 17 00:00:00 2001 From: Alec Merdler Date: Fri, 27 Oct 2017 18:14:37 -0400 Subject: [PATCH] removed '/details' route for resource 'Overview' tab --- .../cloud-services/catalog.spec.tsx | 2 +- .../clusterserviceversion-resource.spec.tsx | 24 ++++++++--- .../clusterserviceversion.spec.tsx | 4 +- frontend/integration-tests/tests/crud.js | 2 +- frontend/public/components/RBAC/edit-rule.jsx | 4 +- frontend/public/components/RBAC/role.jsx | 41 ++++++++----------- frontend/public/components/app.jsx | 6 +-- .../components/cloud-services/catalog.tsx | 2 +- .../clusterserviceversion-resource.tsx | 7 ++-- .../cloud-services/clusterserviceversion.tsx | 8 ++-- frontend/public/components/container.jsx | 8 ++-- frontend/public/components/edit-yaml.jsx | 2 +- frontend/public/components/etcd-cluster.jsx | 2 +- frontend/public/components/events.jsx | 2 +- .../public/components/factory/details.tsx | 1 - .../modals/create-namespace-modal.jsx | 2 +- frontend/public/components/pod.jsx | 4 +- .../public/components/secscan/pod-vuln.jsx | 4 +- frontend/public/components/utils/index.tsx | 1 - .../public/components/utils/relative-link.jsx | 11 ----- .../public/components/utils/resource-link.jsx | 2 +- frontend/public/components/utils/vertnav.jsx | 20 ++++----- 22 files changed, 74 insertions(+), 85 deletions(-) delete mode 100644 frontend/public/components/utils/relative-link.jsx diff --git a/frontend/__tests__/components/cloud-services/catalog.spec.tsx b/frontend/__tests__/components/cloud-services/catalog.spec.tsx index e91d887cd1d..2f3fb5b9b61 100644 --- a/frontend/__tests__/components/cloud-services/catalog.spec.tsx +++ b/frontend/__tests__/components/cloud-services/catalog.spec.tsx @@ -138,7 +138,7 @@ describe(CatalogAppRow.displayName, () => { succeededNamespaces.forEach((ns, i) => { const csv = clusterServiceVersions[i]; - expect(ns.find(Link).props().to).toEqual(`/ns/${csv.metadata.namespace}/clusterserviceversion-v1s/${csv.metadata.name}/details`); + expect(ns.find(Link).props().to).toEqual(`/ns/${csv.metadata.namespace}/clusterserviceversion-v1s/${csv.metadata.name}`); }); }); diff --git a/frontend/__tests__/components/cloud-services/clusterserviceversion-resource.spec.tsx b/frontend/__tests__/components/cloud-services/clusterserviceversion-resource.spec.tsx index 63d3ec26c00..8a0c66513fe 100644 --- a/frontend/__tests__/components/cloud-services/clusterserviceversion-resource.spec.tsx +++ b/frontend/__tests__/components/cloud-services/clusterserviceversion-resource.spec.tsx @@ -381,10 +381,11 @@ describe(ClusterServiceVersionResourceStatus.displayName, () => { describe(ClusterServiceVersionResourcesDetailsPage.displayName, () => { let wrapper: ShallowWrapper; + let match: match; beforeEach(() => { - const match: match = { - params: {appName: 'etcd', plural: 'etcdclusters', name: 'my-etcd'}, + match = { + params: {appName: 'etcd', plural: 'etcdclusters', name: 'my-etcd', ns: 'example'}, isExact: false, url: '/ns/example/clusterserviceversion-v1s/etcd/etcdclusters/my-etcd', path: '/ns/:ns/clusterserviceversion-v1s/:appName/:plural/:name', @@ -398,7 +399,7 @@ describe(ClusterServiceVersionResourcesDetailsPage.displayName, () => { expect(detailsPage.exists()).toBe(true); expect(detailsPage.props().pages[0].name).toEqual('Overview'); - expect(detailsPage.props().pages[0].href).toEqual('details'); + expect(detailsPage.props().pages[0].href).toEqual(''); expect(detailsPage.props().pages[1].name).toEqual('YAML'); expect(detailsPage.props().pages[1].href).toEqual('yaml'); }); @@ -413,8 +414,21 @@ describe(ClusterServiceVersionResourcesDetailsPage.displayName, () => { const detailsPage = wrapper.find(DetailsPage); expect(detailsPage.props().breadcrumbs).toEqual([ - {name: 'etcd', path: '/ns/example/clusterserviceversion-v1s/etcd/details'}, - {name: `${testResourceInstance.kind} Details`, path: '/ns/example/clusterserviceversion-v1s/etcd/etcdclusters/my-etcd/details'}, + {name: 'etcd', path: '/ns/example/clusterserviceversion-v1s/etcd'}, + {name: `${testResourceInstance.kind} Details`, path: '/ns/example/clusterserviceversion-v1s/etcd/etcdclusters/my-etcd'}, + ]); + }); + + it('passes correct breadcrumbs even if `namespace`, `plural`, `appName`, and `name` URL parameters are the same', () => { + match.params = Object.keys(match.params).reduce((params, name) => Object.assign(params, {[name]: 'example'}), {}); + match.url = '/ns/example/clusterserviceversion-v1s/example/example/example'; + + wrapper.setProps({match}); + const detailsPage = wrapper.find(DetailsPage); + + expect(detailsPage.props().breadcrumbs).toEqual([ + {name: 'example', path: '/ns/example/clusterserviceversion-v1s/example'}, + {name: `${testResourceInstance.kind} Details`, path: '/ns/example/clusterserviceversion-v1s/example/example/example'}, ]); }); }); diff --git a/frontend/__tests__/components/cloud-services/clusterserviceversion.spec.tsx b/frontend/__tests__/components/cloud-services/clusterserviceversion.spec.tsx index fdd88420634..c365cd2e16a 100644 --- a/frontend/__tests__/components/cloud-services/clusterserviceversion.spec.tsx +++ b/frontend/__tests__/components/cloud-services/clusterserviceversion.spec.tsx @@ -64,7 +64,7 @@ describe(ClusterServiceVersionListItem.displayName, () => { expect(detailsButton.props().title).toEqual('View details'); expect(detailsButton.childAt(0).text()).toEqual('View details'); - expect(detailsButton.props().to).toEqual(`/ns/${testClusterServiceVersion.metadata.namespace}/clusterserviceversion-v1s/${testClusterServiceVersion.metadata.name}/details`); + expect(detailsButton.props().to).toEqual(`/ns/${testClusterServiceVersion.metadata.namespace}/clusterserviceversion-v1s/${testClusterServiceVersion.metadata.name}`); expect(detailsButton.hasClass('btn')).toBe(true); }); @@ -281,7 +281,7 @@ describe(ClusterServiceVersionsDetailsPage.displayName, () => { expect(detailsPage.exists()).toBe(true); expect(detailsPage.props().pages[0].name).toEqual('Overview'); - expect(detailsPage.props().pages[0].href).toEqual('details'); + expect(detailsPage.props().pages[0].href).toEqual(''); expect(detailsPage.props().pages[0].component).toEqual(ClusterServiceVersionDetails); expect(detailsPage.props().pages[1].name).toEqual('YAML'); expect(detailsPage.props().pages[1].href).toEqual('yaml'); diff --git a/frontend/integration-tests/tests/crud.js b/frontend/integration-tests/tests/crud.js index ae005730f8e..a219e04b694 100644 --- a/frontend/integration-tests/tests/crud.js +++ b/frontend/integration-tests/tests/crud.js @@ -88,7 +88,7 @@ const createExamples = (page, browser) => { } console.log('Resource created'); //with verify(), when an assertion fails, the test logs the failure and continues with other assertions. - browser.verify.urlContains('/example/details'); + browser.verify.urlContains('/example'); }); }; diff --git a/frontend/public/components/RBAC/edit-rule.jsx b/frontend/public/components/RBAC/edit-rule.jsx index 2ab92305629..450499aacfb 100644 --- a/frontend/public/components/RBAC/edit-rule.jsx +++ b/frontend/public/components/RBAC/edit-rule.jsx @@ -157,7 +157,7 @@ const EditRule = connect(state => state.k8s.get('RESOURCES') || {}, {getResource } this.handlePromise(k8sUpdate(this.kind, role)) .then(() => { - history.push(`${resourceObjPath(role, this.kind.kind)}/details`); + history.push(`${resourceObjPath(role, this.kind.kind)}`); }); } @@ -412,7 +412,7 @@ const EditRule = connect(state => state.k8s.get('RESOURCES') || {}, {getResource
- {role && Cancel} + {role && Cancel}
diff --git a/frontend/public/components/RBAC/role.jsx b/frontend/public/components/RBAC/role.jsx index b8cfd8fe662..ddc6f4a30b3 100644 --- a/frontend/public/components/RBAC/role.jsx +++ b/frontend/public/components/RBAC/role.jsx @@ -1,10 +1,9 @@ import * as React from 'react'; import * as fuzzy from 'fuzzysearch'; -import { Helmet } from 'react-helmet'; import { Link } from 'react-router-dom'; import { ColHead, DetailsPage, List, ListHeader, MultiListPage, ResourceRow, TextFilter } from '../factory'; -import { Cog, Firehose, Heading, MsgBox, NavBar, navFactory, NavTitle, ResourceCog, ResourceLink, Timestamp } from '../utils'; +import { Cog, Heading, MsgBox, navFactory, ResourceCog, ResourceLink, Timestamp } from '../utils'; import { BindingName, BindingsList, RulesList } from './index'; import { registerTemplate } from '../../yaml-templates'; import { flatten as bindingsFlatten } from './bindings'; @@ -109,8 +108,6 @@ class Details extends React.Component { } } -const pages = () => [navFactory.details(Details), navFactory.editYaml(), {href: 'bindings', name: 'Role Bindings'}]; - const BindingHeader = props => Name Subject Kind @@ -133,15 +130,9 @@ const BindingRow = ({obj: binding}) => ; -export const BindingsForRolePage = ({match: {params: {name, ns}}, kind}) =>
- - {`${name} ยท Bindings`} - - - - - - { + const {match: {params: {name, ns}}, kind} = props; + return
-
; + flatten={bindingsFlatten} />; +}; + +export const RolesDetailsPage = props => ; -export const RolesDetailsPage = props => ; export const ClusterRolesDetailsPage = RolesDetailsPage; const EmptyMsg = () => ; @@ -174,13 +169,6 @@ export const roleType = role => { return role.metadata.namespace ? 'namespace' : 'cluster'; }; -const resources = [ - {kind: 'Role', namespaced: true}, - {kind: 'ClusterRole', namespaced: false}, -]; - -const flatten = resources => _.flatMap(resources, 'data').filter(r => !!r); - export const RolesPage = ({namespace, showTitle}) => _.flatMap(resources, 'data').filter(r => !!r)} + resources={[ + {kind: 'Role', namespaced: true}, + {kind: 'ClusterRole', namespaced: false}, + ]} rowFilters={[{ type: 'role-kind', selected: ['cluster', 'namespace'], diff --git a/frontend/public/components/app.jsx b/frontend/public/components/app.jsx index 9b28fe35774..ea81ece3daa 100644 --- a/frontend/public/components/app.jsx +++ b/frontend/public/components/app.jsx @@ -22,7 +22,7 @@ import { NamespaceSelector } from './namespace'; import { Nav } from './nav'; import { ProfilePage } from './profile'; import { ResourceDetailsPage, ResourceListPage } from './resource-list'; -import { BindingsForRolePage, CopyRoleBinding, CreateRoleBinding, EditRoleBinding, EditRulePage } from './RBAC'; +import { CopyRoleBinding, CreateRoleBinding, EditRoleBinding, EditRulePage } from './RBAC'; import { StartGuidePage } from './start-guide'; import { SearchPage } from './search'; import { history, Loading, getNamespace } from './utils'; @@ -112,13 +112,11 @@ class App extends React.PureComponent { - } /> } /> - } /> } /> @@ -128,7 +126,7 @@ class App extends React.PureComponent { } /> } /> - + } /> diff --git a/frontend/public/components/cloud-services/catalog.tsx b/frontend/public/components/cloud-services/catalog.tsx index e802066b5c1..e7faceec528 100644 --- a/frontend/public/components/cloud-services/catalog.tsx +++ b/frontend/public/components/cloud-services/catalog.tsx @@ -70,7 +70,7 @@ export const BreakdownDetail: React.StatelessComponent = ( switch (csv.status.phase) { case ClusterServiceVersionPhase.CSVPhaseSucceeded: return
  • - {csv.metadata.namespace} + {csv.metadata.namespace}
  • ; case ClusterServiceVersionPhase.CSVPhaseFailed: return
  • {`${csv.metadata.namespace}: ${csv.status.reason}`}
  • ; diff --git a/frontend/public/components/cloud-services/clusterserviceversion-resource.tsx b/frontend/public/components/cloud-services/clusterserviceversion-resource.tsx index 2092b73a665..5d883f6cf73 100644 --- a/frontend/public/components/cloud-services/clusterserviceversion-resource.tsx +++ b/frontend/public/components/cloud-services/clusterserviceversion-resource.tsx @@ -76,7 +76,7 @@ export const ClusterServiceVersionResourceLink = connectToKinds()((props: Cluste return - {name} + {name} ; }); @@ -293,10 +293,9 @@ export const ClusterServiceVersionResourceDetails = connectToPlural( export const ClusterServiceVersionResourcesDetailsPage: React.StatelessComponent = (props) => i <= props.match.path.split('/').indexOf(':appName')).join('/')}`}, + {name: `${props.kind} Details`, path: `${props.match.url}`}, ]} pages={[ navFactory.details((props) => ), diff --git a/frontend/public/components/cloud-services/clusterserviceversion.tsx b/frontend/public/components/cloud-services/clusterserviceversion.tsx index a7a665d2fa4..9108eea7bfd 100644 --- a/frontend/public/components/cloud-services/clusterserviceversion.tsx +++ b/frontend/public/components/cloud-services/clusterserviceversion.tsx @@ -27,8 +27,8 @@ export const ClusterServiceVersionListItem: React.StatelessComponent ({...acc, [ns]: ns}), {})} - onChange={(ns) => history.push(`${route(appType.metadata.name, ns)}/details`)} /> - : View details } + onChange={(ns) => history.push(`${route(appType.metadata.name, ns)}`)} /> + : View details } { namespaces.length === 1 && View resources }
    ; @@ -47,7 +47,7 @@ export const ClusterServiceVersionRow: React.StatelessComponent
    - View details + View details View resources
    ; @@ -205,7 +205,7 @@ export const ClusterServiceVersionsDetailsPage: React.StatelessComponent ; - return ; + return ; }; export type ClusterServiceVersionsPageProps = { diff --git a/frontend/public/components/container.jsx b/frontend/public/components/container.jsx index 9b221c285ae..f19ae16071d 100644 --- a/frontend/public/components/container.jsx +++ b/frontend/public/components/container.jsx @@ -167,7 +167,7 @@ const Details = (props) => {

    Network

    Node
    -
    {pod.spec.nodeName}
    +
    {pod.spec.nodeName}
    Pod IP
    {pod.status.podIP || '-'}
    @@ -208,8 +208,8 @@ export const ContainersDetailsPage = (props) =>
    title={props.match.params.name} kind="Container" breadcrumbs={[ - {name: props.match.params.podName, path: `${props.match.url.split('/').slice(0, 5).join('/')}/details`}, - {name: 'Container Details', path: `${props.match.url}/details`}, + {name: props.match.params.podName, path: `${props.match.url.split('/').filter((_, i) => i <= props.match.path.split('/').indexOf(':podName')).join('/')}`}, + {name: 'Container Details', path: `${props.match.url}`}, ]} />
    isList: false, prop: 'obj', }]}> - +
    ; diff --git a/frontend/public/components/edit-yaml.jsx b/frontend/public/components/edit-yaml.jsx index fc5208ac80a..c7b3d08644e 100644 --- a/frontend/public/components/edit-yaml.jsx +++ b/frontend/public/components/edit-yaml.jsx @@ -188,7 +188,7 @@ export class EditYAML extends SafetyFirst { action(ko, obj, namespace, name) .then(o => { if (redirect) { - history.push(this.props.redirectURL || `${resourcePath(ko.kind, newName, newNamespace)}/details`); + history.push(this.props.redirectURL || `${resourcePath(ko.kind, newName, newNamespace)}`); // TODO: (ggreer). show message on new page. maybe delete old obj? return; } diff --git a/frontend/public/components/etcd-cluster.jsx b/frontend/public/components/etcd-cluster.jsx index 231fe58412c..6bd407ca53a 100644 --- a/frontend/public/components/etcd-cluster.jsx +++ b/frontend/public/components/etcd-cluster.jsx @@ -39,7 +39,7 @@ const menuActions = [UpdateCount, Edit, Delete]; const EtcdClusterLink = (props) => { const {uid, name, namespace} = props.metadata; - const path = `/ns/${namespace}/etcdclusters/${name}/details`; + const path = `/ns/${namespace}/etcdclusters/${name}`; return diff --git a/frontend/public/components/events.jsx b/frontend/public/components/events.jsx index 6c440d5516e..cb69b718090 100644 --- a/frontend/public/components/events.jsx +++ b/frontend/public/components/events.jsx @@ -53,7 +53,7 @@ class SysEvent extends React.PureComponent { Generated from {this.props.source.component} {this.props.source.component === 'kubelet' && - on {this.props.source.host} + on {this.props.source.host} }
    diff --git a/frontend/public/components/factory/details.tsx b/frontend/public/components/factory/details.tsx index 7c778fc5e8f..52053ea932b 100644 --- a/frontend/public/components/factory/details.tsx +++ b/frontend/public/components/factory/details.tsx @@ -25,7 +25,6 @@ export type DetailsPageProps = { label?: string; name?: string; namespace?: string; - isList: boolean; breadcrumbs?: {name: string, path: string}[]; }; diff --git a/frontend/public/components/modals/create-namespace-modal.jsx b/frontend/public/components/modals/create-namespace-modal.jsx index 3689914d8f0..b93300ad789 100644 --- a/frontend/public/components/modals/create-namespace-modal.jsx +++ b/frontend/public/components/modals/create-namespace-modal.jsx @@ -46,7 +46,7 @@ class CreateNamespaceModal extends PromiseComponent { this.handlePromise(promise).then(() => { this.props.close(); - history.push(`namespaces/${name}/details`); + history.push(`namespaces/${name}`); }); } diff --git a/frontend/public/components/pod.jsx b/frontend/public/components/pod.jsx index 01df20852e5..cfb66b68ac9 100644 --- a/frontend/public/components/pod.jsx +++ b/frontend/public/components/pod.jsx @@ -89,10 +89,10 @@ const PodHeader = props => const ContainerLink = ({pod, name}) => - {name} + {name} ; -const NodeLink = ({name}) => name ? {name} : -; +const NodeLink = ({name}) => name ? {name} : -; export const ContainerRow = ({pod, container}) => { const cstatus = getContainerStatus(pod, container.name); diff --git a/frontend/public/components/secscan/pod-vuln.jsx b/frontend/public/components/secscan/pod-vuln.jsx index 9b54b89fd49..d1ebc9a258d 100644 --- a/frontend/public/components/secscan/pod-vuln.jsx +++ b/frontend/public/components/secscan/pod-vuln.jsx @@ -96,7 +96,7 @@ const PodLink = ({pod, text}) => { const podname = _.get(pod, 'metadata.name'); return
    {text ? (`${text}: `) : ''} - + {podname}
    ; @@ -113,7 +113,7 @@ const ContainerLink = ({podvuln, name}) => { return - {name} + {name} ; }; diff --git a/frontend/public/components/utils/index.tsx b/frontend/public/components/utils/index.tsx index 356c3590386..9def14b4b0d 100644 --- a/frontend/public/components/utils/index.tsx +++ b/frontend/public/components/utils/index.tsx @@ -11,7 +11,6 @@ export * from './volume-icon'; export * from './timestamp'; export * from './vertnav'; export * from './details-page'; -export * from './relative-link'; export * from './inject'; export * from './firehose'; export * from './dropdown'; diff --git a/frontend/public/components/utils/relative-link.jsx b/frontend/public/components/utils/relative-link.jsx deleted file mode 100644 index dc583024607..00000000000 --- a/frontend/public/components/utils/relative-link.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import * as React from 'react'; -import { Link } from 'react-router-dom'; - -import { stripBasePath } from './index'; - -// A RelativeLink is a chalupa! -export const RelativeLink = ({to, children}) => { - // Take the current path, remove the base path and change the final slug - const path = stripBasePath(window.location.pathname).replace(/[^/]*$/, to); - return {children}; -}; diff --git a/frontend/public/components/utils/resource-link.jsx b/frontend/public/components/utils/resource-link.jsx index 0b45b4a4a08..043b80ea8c2 100644 --- a/frontend/public/components/utils/resource-link.jsx +++ b/frontend/public/components/utils/resource-link.jsx @@ -18,7 +18,7 @@ export const ResourceLink = ({kind, name, namespace, title, displayName}) => { return ( - {path ? {value} : {value}} + {path ? {value} : {value}} ); }; diff --git a/frontend/public/components/utils/vertnav.jsx b/frontend/public/components/utils/vertnav.jsx index ac43dacb21a..42a9229ce29 100644 --- a/frontend/public/components/utils/vertnav.jsx +++ b/frontend/public/components/utils/vertnav.jsx @@ -1,9 +1,9 @@ import * as React from 'react'; import * as classNames from'classnames'; import * as PropTypes from 'prop-types'; -import { Route, Switch } from 'react-router-dom'; +import { Route, Switch, Link } from 'react-router-dom'; -import { StatusBox, RelativeLink } from './index'; +import { StatusBox } from './index'; import { PodsPage } from '../pod'; import { AsyncComponent } from '../utils/async'; @@ -18,7 +18,7 @@ class PodsComponent extends React.PureComponent { export const navFactory = { details: (component = undefined) => ({ - href: 'details', + href: '', name: 'Overview', component, }), @@ -54,17 +54,17 @@ export const navFactory = { }), }; -const activeSlug = () => location.pathname.split('/').pop(); - -export const NavBar = ({pages}) => { +/** @type {React.StatelessComponent<{pages: {href: string, name: string, component: React.ComponentType}, basePath: string}>} */ +export const NavBar = ({pages, basePath}) => { const divider =
  • ; + basePath = basePath.replace(/\/$/, ''); return
      {_.flatten(_.map(pages, ({name, href}, i) => { - const klass = classNames('co-m-vert-nav__menu-item', {'co-m-vert-nav-item--active': href === activeSlug()}); - const tab =
    • {name}
    • ; + const klass = classNames('co-m-vert-nav__menu-item', {'co-m-vert-nav-item--active': location.pathname.replace(basePath, '/').endsWith(`/${href}`)}); + const tab =
    • {name}
    • ; // These tabs go before the divider - const before = ['details', 'edit', 'yaml']; + const before = ['', 'edit', 'yaml']; return (!before.includes(href) && i !== 0 && before.includes(pages[i - 1].href)) ? [divider, tab] : [tab]; }))}
    ; }; @@ -89,7 +89,7 @@ export class VertNav extends React.PureComponent { return
    - {!props.hideNav && } + {!props.hideNav && }