Skip to content

Commit 6082362

Browse files
committed
refactor
1 parent e3d4f02 commit 6082362

File tree

2 files changed

+148
-61
lines changed

2 files changed

+148
-61
lines changed

src/components/ControlPlane/GitRepositories.tsx

Lines changed: 99 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,85 +2,115 @@ import ConfiguredAnalyticstable from '../Shared/ConfiguredAnalyticsTable.tsx';
22
import { AnalyticalTableColumnDefinition, Panel, Title, Toolbar, ToolbarSpacer } from '@ui5/webcomponents-react';
33
import IllustratedError from '../Shared/IllustratedError.tsx';
44
import { useApiResource } from '../../lib/api/useApiResource';
5-
import { FluxRequest } from '../../lib/api/types/flux/listGitRepo';
6-
import { KustomizationsResponse } from '../../lib/api/types/flux/listKustomization';
5+
import { FluxRequest, GitReposResponse } from '../../lib/api/types/flux/listGitRepo';
76
import { useTranslation } from 'react-i18next';
87
import { formatDateAsTimeAgo } from '../../utils/i18n/timeAgo.ts';
98

109
import { YamlViewButton } from '../Yaml/YamlViewButton.tsx';
11-
import { useMemo } from 'react';
10+
import { Fragment, useCallback, useMemo, useRef } from 'react';
1211
import StatusFilter from '../Shared/StatusFilter/StatusFilter.tsx';
1312
import { ResourceStatusCell } from '../Shared/ResourceStatusCell.tsx';
1413
import { Resource } from '../../utils/removeManagedFieldsAndFilterData.ts';
14+
import { useSplitter } from '../Splitter/SplitterContext.tsx';
15+
import { YamlSidePanel } from '../Yaml/YamlSidePanel.tsx';
16+
import { useHandleResourcePatch } from '../../lib/api/types/crossplane/useHandleResourcePatch.ts';
17+
import { ErrorDialog, ErrorDialogHandle } from '../Shared/ErrorMessageBox.tsx';
18+
import { GitRepositoriesRowActionsMenu, GitRepoItem } from './GitRepositoriesActionMenu.tsx';
19+
20+
interface CellRow<T> {
21+
original: T;
22+
}
1523

1624
export function GitRepositories() {
1725
const { data, error, isLoading } = useApiResource(FluxRequest); //404 if component not enabled
1826
const { t } = useTranslation();
19-
20-
interface CellData<T> {
21-
cell: {
22-
value: T | null; // null for grouping rows
23-
row: {
24-
original?: FluxRow; // missing for grouping rows
25-
};
26-
};
27-
}
27+
const { openInAside } = useSplitter();
28+
const errorDialogRef = useRef<ErrorDialogHandle>(null);
29+
const handlePatch = useHandleResourcePatch(errorDialogRef);
2830

2931
type FluxRow = {
3032
name: string;
3133
created: string;
3234
isReady: boolean;
3335
statusUpdateTime?: string;
34-
item: unknown;
36+
item: GitRepoItem;
3537
readyMessage: string;
38+
revision?: string;
3639
};
3740

38-
const columns: AnalyticalTableColumnDefinition[] = useMemo(
39-
() => [
40-
{
41-
Header: t('FluxList.tableNameHeader'),
42-
accessor: 'name',
43-
minWidth: 250,
44-
},
45-
{
46-
Header: t('FluxList.tableCreatedHeader'),
47-
accessor: 'created',
48-
},
49-
{
50-
Header: t('FluxList.tableVersionHeader'),
51-
accessor: 'revision',
52-
},
53-
{
54-
Header: t('FluxList.tableStatusHeader'),
55-
accessor: 'status',
56-
width: 125,
57-
hAlign: 'Center',
58-
Filter: ({ column }) => <StatusFilter column={column} />,
59-
Cell: (cellData: CellData<FluxRow>) =>
60-
cellData.cell.row.original?.isReady != null ? (
61-
<ResourceStatusCell
62-
positiveText={t('common.ready')}
63-
negativeText={t('errors.error')}
64-
isOk={cellData.cell.row.original?.isReady}
65-
transitionTime={
66-
cellData.cell.row.original?.statusUpdateTime ? cellData.cell.row.original?.statusUpdateTime : ''
67-
}
68-
message={cellData.cell.row.original?.readyMessage}
69-
/>
70-
) : null,
71-
},
72-
{
73-
Header: t('yaml.YAML'),
74-
hAlign: 'Center',
75-
width: 75,
76-
accessor: 'yaml',
77-
disableFilters: true,
78-
Cell: (cellData: CellData<KustomizationsResponse['items']>) => (
79-
<YamlViewButton variant="resource" resource={cellData.cell.row.original?.item as Resource} />
80-
),
81-
},
82-
],
83-
[t],
41+
const openEditPanel = useCallback(
42+
(item: GitRepoItem) => {
43+
const identityKey = `${item.kind}:${item.metadata.namespace ?? ''}:${item.metadata.name}`;
44+
openInAside(
45+
<Fragment key={identityKey}>
46+
<YamlSidePanel
47+
isEdit={true}
48+
resource={item as unknown as Resource}
49+
filename={`${item.kind}_${item.metadata.name}`}
50+
onApply={async (parsed) => await handlePatch(item, parsed)}
51+
/>
52+
</Fragment>,
53+
);
54+
},
55+
[openInAside, handlePatch],
56+
);
57+
58+
const columns = useMemo<AnalyticalTableColumnDefinition[]>(
59+
() =>
60+
[
61+
{
62+
Header: t('FluxList.tableNameHeader'),
63+
accessor: 'name',
64+
minWidth: 250,
65+
},
66+
{
67+
Header: t('FluxList.tableCreatedHeader'),
68+
accessor: 'created',
69+
},
70+
{
71+
Header: t('FluxList.tableVersionHeader'),
72+
accessor: 'revision',
73+
},
74+
{
75+
Header: t('FluxList.tableStatusHeader'),
76+
accessor: 'status',
77+
width: 125,
78+
hAlign: 'Center',
79+
Filter: ({ column }) => <StatusFilter column={column} />,
80+
Cell: ({ row }: { row: CellRow<FluxRow> }) =>
81+
row.original?.isReady != null ? (
82+
<ResourceStatusCell
83+
positiveText={t('common.ready')}
84+
negativeText={t('errors.error')}
85+
isOk={row.original?.isReady}
86+
transitionTime={row.original?.statusUpdateTime ? row.original?.statusUpdateTime : ''}
87+
message={row.original?.readyMessage}
88+
/>
89+
) : null,
90+
},
91+
{
92+
Header: t('yaml.YAML'),
93+
hAlign: 'Center',
94+
width: 75,
95+
accessor: 'yaml',
96+
disableFilters: true,
97+
Cell: ({ row }: { row: CellRow<FluxRow> }) => (
98+
<YamlViewButton variant="resource" resource={row.original.item as unknown as Resource} />
99+
),
100+
},
101+
{
102+
Header: t('ManagedResources.actionColumnHeader'),
103+
hAlign: 'Center',
104+
width: 60,
105+
disableFilters: true,
106+
accessor: 'actions',
107+
Cell: ({ row }: { row: CellRow<FluxRow> }) =>
108+
row.original?.item ? (
109+
<GitRepositoriesRowActionsMenu item={row.original?.item} onEdit={openEditPanel} />
110+
) : undefined,
111+
},
112+
] as AnalyticalTableColumnDefinition[],
113+
[t, openEditPanel],
84114
);
85115

86116
if (error) {
@@ -102,7 +132,12 @@ export function GitRepositories() {
102132
statusUpdateTime: readyObject?.lastTransitionTime,
103133
revision: shortenCommitHash(item.status.artifact?.revision ?? '-'),
104134
created: formatDateAsTimeAgo(item.metadata.creationTimestamp),
105-
item: item,
135+
item: {
136+
...item,
137+
kind: 'GitRepository',
138+
apiVersion: 'source.toolkit.fluxcd.io/v1',
139+
metadata: { ...item.metadata },
140+
} as GitRepoItem,
106141
readyMessage: readyObject?.message ?? readyObject?.reason ?? '',
107142
};
108143
}) ?? [];
@@ -118,7 +153,10 @@ export function GitRepositories() {
118153
</Toolbar>
119154
}
120155
>
121-
<ConfiguredAnalyticstable columns={columns} isLoading={isLoading} data={rows} />
156+
<>
157+
<ConfiguredAnalyticstable columns={columns} isLoading={isLoading} data={rows} />
158+
<ErrorDialog ref={errorDialogRef} />
159+
</>
122160
</Panel>
123161
);
124162
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { FC, useRef, useState } from 'react';
2+
import { Button, Menu, MenuItem, MenuDomRef } from '@ui5/webcomponents-react';
3+
import { useTranslation } from 'react-i18next';
4+
import type { ButtonClickEventDetail } from '@ui5/webcomponents/dist/Button.js';
5+
import type { Ui5CustomEvent, ButtonDomRef } from '@ui5/webcomponents-react';
6+
import type { GitReposResponse } from '../../lib/api/types/flux/listGitRepo';
7+
8+
export type GitRepoItem = GitReposResponse['items'][0] & {
9+
apiVersion?: string;
10+
metadata: GitReposResponse['items'][0]['metadata'] & { namespace?: string };
11+
};
12+
13+
interface GitRepositoriesRowActionsMenuProps {
14+
item: GitRepoItem;
15+
onEdit: (item: GitRepoItem) => void;
16+
}
17+
18+
export const GitRepositoriesRowActionsMenu: FC<GitRepositoriesRowActionsMenuProps> = ({ item, onEdit }) => {
19+
const { t } = useTranslation();
20+
const popoverRef = useRef<MenuDomRef>(null);
21+
const [open, setOpen] = useState(false);
22+
23+
const handleOpenerClick = (e: Ui5CustomEvent<ButtonDomRef, ButtonClickEventDetail>) => {
24+
if (popoverRef.current && e.currentTarget) {
25+
popoverRef.current.opener = e.currentTarget as unknown as HTMLElement;
26+
setOpen((prev) => !prev);
27+
}
28+
};
29+
30+
return (
31+
<>
32+
<Button icon="overflow" design="Transparent" onClick={handleOpenerClick} />
33+
<Menu
34+
ref={popoverRef}
35+
open={open}
36+
onItemClick={(event) => {
37+
const element = event.detail.item as HTMLElement;
38+
const action = element.dataset.action;
39+
if (action === 'edit') {
40+
onEdit(item);
41+
}
42+
setOpen(false);
43+
}}
44+
>
45+
<MenuItem text={t('ManagedResources.editAction', 'Edit')} icon="edit" data-action="edit" />
46+
</Menu>
47+
</>
48+
);
49+
};

0 commit comments

Comments
 (0)