Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Helm Release List Page and Nav Item for it
- Loading branch information
1 parent
0150aba
commit 35f2d74
Showing
8 changed files
with
393 additions
and
1 deletion.
There are no files selected for viewing
53 changes: 53 additions & 0 deletions
53
frontend/packages/dev-console/src/components/helm/HelmReleaseHeader.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,53 @@ | ||
import { sortable } from '@patternfly/react-table'; | ||
|
||
export const tableColumnClasses = { | ||
name: 'col-lg-2 col-md-3 col-sm-4 col-xs-4', | ||
revision: 'col-lg-2 col-md-3 col-sm-3 col-xs-3', | ||
timestamp: 'col-lg-2 col-md-4 col-sm-5 col-xs-5', | ||
status: 'col-lg-2 col-md-2 hidden-sm hidden-xs', | ||
chartName: 'col-lg-2 hidden-md hidden-sm hidden-xs', | ||
chartVersion: 'col-lg-2 hidden-md hidden-sm hidden-xs', | ||
}; | ||
|
||
const HelmReleaseHeader = () => { | ||
return [ | ||
{ | ||
title: 'Name', | ||
sortField: 'name', | ||
transforms: [sortable], | ||
props: { className: tableColumnClasses.name }, | ||
}, | ||
{ | ||
title: 'Revision', | ||
sortField: 'version', | ||
transforms: [sortable], | ||
props: { className: tableColumnClasses.revision }, | ||
}, | ||
{ | ||
title: 'Timestamp', | ||
sortField: 'info.last_deployed', | ||
transforms: [sortable], | ||
props: { className: tableColumnClasses.timestamp }, | ||
}, | ||
{ | ||
title: 'Status', | ||
sortField: 'info.status', | ||
transforms: [sortable], | ||
props: { className: tableColumnClasses.status }, | ||
}, | ||
{ | ||
title: 'Chart Name', | ||
sortField: 'chart.metadata.name', | ||
transforms: [sortable], | ||
props: { className: tableColumnClasses.chartName }, | ||
}, | ||
{ | ||
title: 'Chart Version', | ||
sortField: 'chart.metadata.version', | ||
transforms: [sortable], | ||
props: { className: tableColumnClasses.chartVersion }, | ||
}, | ||
]; | ||
}; | ||
|
||
export default HelmReleaseHeader; |
116 changes: 116 additions & 0 deletions
116
frontend/packages/dev-console/src/components/helm/HelmReleaseList.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,116 @@ | ||
import * as React from 'react'; | ||
import * as _ from 'lodash'; | ||
import { coFetchJSON } from '@console/internal/co-fetch'; | ||
import { Table, TextFilter } from '@console/internal/components/factory'; | ||
import { SortByDirection } from '@patternfly/react-table'; | ||
import { CheckBoxes } from '@console/internal/components/row-filter'; | ||
import { FirehoseResult, getQueryArgument } from '@console/internal/components/utils'; | ||
import { HelmRelease, HelmFilterType } from './helm-types'; | ||
import { helmRowFilters, getFilteredItems, useDeepCompareMemoize } from './helm-utils'; | ||
import HelmReleaseHeader from './HelmReleaseHeader'; | ||
import HelmReleaseRow from './HelmReleaseRow'; | ||
|
||
interface HelmReleaseListProps { | ||
namespace: string; | ||
secrets?: FirehoseResult; | ||
} | ||
|
||
const HelmReleaseList: React.FC<HelmReleaseListProps> = ({ namespace, secrets }) => { | ||
const [releases, setReleases] = React.useState([]); | ||
const [filteredReleases, setFilteredReleases] = React.useState([]); | ||
const [fetched, setFetched] = React.useState(false); | ||
|
||
const memoizedSecrets = useDeepCompareMemoize(secrets.data); | ||
|
||
React.useEffect(() => { | ||
let ignore = false; | ||
|
||
const activeFilters = | ||
getQueryArgument('rowFilter-helm-release-status') && | ||
getQueryArgument('rowFilter-helm-release-status').split(','); | ||
|
||
const fetchHelmReleases = async () => { | ||
const res: HelmRelease[] = await coFetchJSON('/api/console/helm/list'); | ||
const namespacedReleases = (res && res.filter((rel) => rel.namespace === namespace)) || []; | ||
|
||
if (ignore) return; | ||
|
||
setReleases(namespacedReleases); | ||
setFetched(true); | ||
|
||
if (activeFilters) { | ||
const filteredItems = getFilteredItems( | ||
namespacedReleases, | ||
HelmFilterType.Row, | ||
activeFilters, | ||
); | ||
setFilteredReleases(filteredItems); | ||
} else { | ||
setFilteredReleases(namespacedReleases); | ||
} | ||
}; | ||
|
||
fetchHelmReleases(); | ||
|
||
return () => { | ||
ignore = true; | ||
}; | ||
}, [namespace, memoizedSecrets]); | ||
|
||
const applyRowFilter = React.useCallback( | ||
(filter) => { | ||
const filteredItems = getFilteredItems(releases, HelmFilterType.Row, filter); | ||
setFilteredReleases(filteredItems); | ||
}, | ||
[releases], | ||
); | ||
|
||
const applyTextFilter = React.useCallback( | ||
(filter) => { | ||
const filteredItems = getFilteredItems(releases, HelmFilterType.Text, filter); | ||
setFilteredReleases(filteredItems); | ||
}, | ||
[releases], | ||
); | ||
|
||
const RowsOfRowFilters = _.map(helmRowFilters, ({ items, reducer, selected, type }, i) => { | ||
return ( | ||
<CheckBoxes | ||
key={i} | ||
applyFilter={applyRowFilter} | ||
items={items} | ||
itemCount={_.size(releases)} | ||
numbers={_.countBy(releases, reducer)} | ||
selected={selected} | ||
type={type} | ||
reduxIDs={[]} | ||
/> | ||
); | ||
}); | ||
|
||
return ( | ||
<> | ||
<div className="co-m-pane__filter-bar"> | ||
<div className="co-m-pane__filter-bar-group co-m-pane__filter-bar-group--filter"> | ||
<TextFilter label="by name" onChange={(e) => applyTextFilter(e.target.value)} /> | ||
</div> | ||
</div> | ||
|
||
<div className="co-m-pane__body"> | ||
{!_.isEmpty(releases) && RowsOfRowFilters} | ||
<Table | ||
data={filteredReleases} | ||
defaultSortField="name" | ||
defaultSortOrder={SortByDirection.asc} | ||
aria-label="Helm Releases" | ||
Header={HelmReleaseHeader} | ||
Row={HelmReleaseRow} | ||
loaded={fetched} | ||
virtualize | ||
/> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export default React.memo(HelmReleaseList); |
46 changes: 46 additions & 0 deletions
46
frontend/packages/dev-console/src/components/helm/HelmReleasePage.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,46 @@ | ||
import * as React from 'react'; | ||
import { RouteComponentProps } from 'react-router'; | ||
import Helmet from 'react-helmet'; | ||
import { PageHeading, Firehose } from '@console/internal/components/utils'; | ||
import { SecretModel } from '@console/internal/models'; | ||
import ProjectListPage from '../projects/ProjectListPage'; | ||
import NamespacedPage, { NamespacedPageVariants } from '../NamespacedPage'; | ||
import HelmReleaseList from './HelmReleaseList'; | ||
|
||
type HelmReleasePageProps = RouteComponentProps<{ ns: string }>; | ||
|
||
export const HelmReleasePage: React.FC<HelmReleasePageProps> = (props) => { | ||
const { | ||
match: { | ||
params: { ns: namespace }, | ||
}, | ||
} = props; | ||
|
||
const resources = [ | ||
{ | ||
isList: true, | ||
namespace, | ||
kind: SecretModel.kind, | ||
prop: 'secrets', | ||
optional: true, | ||
selector: { owner: 'helm' }, | ||
}, | ||
]; | ||
return namespace ? ( | ||
<NamespacedPage variant={NamespacedPageVariants.light} hideApplications> | ||
<Helmet> | ||
<title>Helm Releases</title> | ||
</Helmet> | ||
<PageHeading title="Helm Releases" /> | ||
<Firehose resources={resources}> | ||
<HelmReleaseList namespace={namespace} /> | ||
</Firehose> | ||
</NamespacedPage> | ||
) : ( | ||
<ProjectListPage title="Helm Releases"> | ||
Select a project to view the list of Helm Releases | ||
</ProjectListPage> | ||
); | ||
}; | ||
|
||
export default HelmReleasePage; |
44 changes: 44 additions & 0 deletions
44
frontend/packages/dev-console/src/components/helm/HelmReleaseRow.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,44 @@ | ||
import * as React from 'react'; | ||
import { Status } from '@console/shared'; | ||
import { TableRow, TableData } from '@console/internal/components/factory'; | ||
import { Timestamp } from '@console/internal/components/utils'; | ||
import { Link } from 'react-router-dom'; | ||
import { HelmRelease } from './helm-types'; | ||
import { tableColumnClasses } from './HelmReleaseHeader'; | ||
|
||
interface HelmReleaseRowProps { | ||
obj: HelmRelease; | ||
index: number; | ||
key?: string; | ||
style: object; | ||
} | ||
|
||
const HelmReleaseRow: React.FC<HelmReleaseRowProps> = ({ obj, index, key, style }) => { | ||
return ( | ||
<TableRow id={obj.name} index={index} trKey={key} style={style}> | ||
<TableData className={tableColumnClasses.name}> | ||
<Link | ||
to={`/helm-releases/ns/${obj.namespace}/release/${obj.name}`} | ||
title={obj.name} | ||
className="co-resource-item__resource-name" | ||
data-test-id={obj.name} | ||
> | ||
{obj.name} | ||
</Link> | ||
</TableData> | ||
<TableData className={tableColumnClasses.revision}>{obj.version}</TableData> | ||
<TableData className={tableColumnClasses.timestamp}> | ||
<Timestamp timestamp={obj.info.last_deployed} /> | ||
</TableData> | ||
<TableData className={tableColumnClasses.status}> | ||
<Status status={obj.info.status} /> | ||
</TableData> | ||
<TableData className={tableColumnClasses.chartName}>{obj.chart.metadata.name}</TableData> | ||
<TableData className={tableColumnClasses.chartVersion}> | ||
{obj.chart.metadata.version} | ||
</TableData> | ||
</TableRow> | ||
); | ||
}; | ||
|
||
export default HelmReleaseRow; |
34 changes: 34 additions & 0 deletions
34
frontend/packages/dev-console/src/components/helm/helm-types.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,34 @@ | ||
export interface HelmRelease { | ||
name: string; | ||
namespace: string; | ||
chart: { | ||
files: object[]; | ||
metadata: { | ||
name: string; | ||
version: string; | ||
}; | ||
templates: object[]; | ||
values: object; | ||
}; | ||
info: { | ||
description: string; | ||
deleted: string; | ||
first_deployed: string; | ||
last_deployed: string; | ||
status: string; | ||
}; | ||
hooks: object[]; | ||
manifest: string; | ||
version: string; | ||
} | ||
|
||
export enum HelmReleaseStatus { | ||
Deployed = 'deployed', | ||
Failed = 'failed', | ||
Other = 'other', | ||
} | ||
|
||
export enum HelmFilterType { | ||
Row = 'row', | ||
Text = 'text', | ||
} |
74 changes: 74 additions & 0 deletions
74
frontend/packages/dev-console/src/components/helm/helm-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,74 @@ | ||
import * as React from 'react'; | ||
import * as _ from 'lodash'; | ||
import * as fuzzy from 'fuzzysearch'; | ||
import { HelmRelease, HelmReleaseStatus, HelmFilterType } from './helm-types'; | ||
|
||
export const HelmReleaseStatusLabels = { | ||
[HelmReleaseStatus.Deployed]: 'Deployed', | ||
[HelmReleaseStatus.Failed]: 'Failed', | ||
[HelmReleaseStatus.Other]: 'Other', | ||
}; | ||
|
||
export const otherStatuses = [ | ||
'unknown', | ||
'uninstalled', | ||
'superseded', | ||
'uninstalling', | ||
'pending-install', | ||
'pending-upgrade', | ||
'pending-rollback', | ||
]; | ||
|
||
export const releaseStatusReducer = (release: HelmRelease) => { | ||
if (otherStatuses.includes(release.info.status)) { | ||
return HelmReleaseStatus.Other; | ||
} | ||
return release.info.status; | ||
}; | ||
|
||
export const selectedStatuses = [ | ||
HelmReleaseStatus.Deployed, | ||
HelmReleaseStatus.Failed, | ||
HelmReleaseStatus.Other, | ||
]; | ||
|
||
export const helmRowFilters = [ | ||
{ | ||
type: 'helm-release-status', | ||
selected: selectedStatuses, | ||
reducer: releaseStatusReducer, | ||
items: selectedStatuses.map((status) => ({ | ||
id: status, | ||
title: HelmReleaseStatusLabels[status], | ||
})), | ||
}, | ||
]; | ||
|
||
export const getFilteredItems = ( | ||
items: HelmRelease[], | ||
filterType: HelmFilterType, | ||
filter: string | string[], | ||
) => { | ||
switch (filterType) { | ||
case HelmFilterType.Row: | ||
return items.filter((release: HelmRelease) => { | ||
return otherStatuses.includes(release.info.status) | ||
? filter.includes(HelmReleaseStatus.Other) | ||
: filter.includes(release.info.status); | ||
}); | ||
case HelmFilterType.Text: | ||
return items.filter((release: HelmRelease) => fuzzy(filter, release.name)); | ||
default: | ||
return items; | ||
} | ||
}; | ||
|
||
export const useDeepCompareMemoize = (value) => { | ||
const ref = React.useRef(); | ||
|
||
if (!_.isEqual(value, ref.current)) { | ||
ref.current = value; | ||
} | ||
|
||
return ref.current; | ||
}; |
Oops, something went wrong.