Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@
},
"yaml": {
"copiedToClipboard": "YAML copied to clipboard!",
"YAML": "YAML"
"YAML": "File"
},
"createMCP": {
"dialogTitle": "Create Managed Control Plane",
Expand Down
5 changes: 5 additions & 0 deletions src/components/ControlPlane/FluxList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { timeAgo } from '../../utils/i18n/timeAgo.ts';
import { ResourceStatusCell } from '../Shared/ResourceStatusCell.tsx';
import { YamlViewButton } from '../Yaml/YamlViewButton.tsx';
import { useMemo } from 'react';
import StatusFilter from '../Shared/StatusFilter.tsx';

export default function FluxList() {
const {
Expand Down Expand Up @@ -68,6 +69,7 @@ export default function FluxList() {
accessor: 'status',
width: 85,
hAlign: 'Center',
Filter: ({ column }) => <StatusFilter column={column} />,
Cell: (cellData: CellData<FluxRow['isReady']>) =>
cellData.cell.row.original?.isReady != null ? (
<ResourceStatusCell
Expand All @@ -85,6 +87,7 @@ export default function FluxList() {
hAlign: 'Center',
width: 85,
accessor: 'yaml',
disableFilters: true,
Cell: (cellData: CellData<KustomizationsResponse['items']>) => (
<YamlViewButton resourceObject={cellData.cell.row.original?.item} />
),
Expand All @@ -109,6 +112,7 @@ export default function FluxList() {
accessor: 'status',
width: 85,
hAlign: 'Center',
Filter: ({ column }) => <StatusFilter column={column} />,
Cell: (cellData: CellData<FluxRow['isReady']>) =>
cellData.cell.row.original?.isReady != null ? (
<ResourceStatusCell
Expand All @@ -127,6 +131,7 @@ export default function FluxList() {
hAlign: 'Center',
width: 85,
accessor: 'yaml',
disableFilters: true,
Cell: (cellData: CellData<FluxRow>) => (
<YamlViewButton resourceObject={cellData.cell.row.original?.item} />
),
Expand Down
6 changes: 5 additions & 1 deletion src/components/ControlPlane/ManagedResources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { resourcesInterval } from '../../lib/shared/constants';
import { ResourceStatusCell } from '../Shared/ResourceStatusCell';
import { YamlViewButton } from '../Yaml/YamlViewButton.tsx';
import { useMemo } from 'react';
import StatusFilter from '../Shared/StatusFilter.tsx';

interface CellData<T> {
cell: {
Expand Down Expand Up @@ -66,6 +67,7 @@ export function ManagedResources() {
accessor: 'synced',
hAlign: 'Center',
width: 85,
Filter: ({ column }) => <StatusFilter column={column} />,
Cell: (cellData: CellData<ResourceRow['synced']>) =>
cellData.cell.row.original?.synced != null ? (
<ResourceStatusCell
Expand All @@ -79,6 +81,7 @@ export function ManagedResources() {
accessor: 'ready',
hAlign: 'Center',
width: 85,
Filter: ({ column }) => <StatusFilter column={column} />,
Cell: (cellData: CellData<ResourceRow['ready']>) =>
cellData.cell.row.original?.ready != null ? (
<ResourceStatusCell
Expand All @@ -92,8 +95,9 @@ export function ManagedResources() {
hAlign: 'Center',
width: 85,
accessor: 'yaml',
disableFilters: true,
Cell: (cellData: CellData<ResourceRow>) =>
!!cellData.cell.row.original?.item ? (
cellData.cell.row.original?.item ? (
<YamlViewButton resourceObject={cellData.cell.row.original?.item} />
) : undefined,
},
Expand Down
35 changes: 20 additions & 15 deletions src/components/ControlPlane/Providers.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import {
AnalyticalTable,
AnalyticalTableColumnDefinition,
AnalyticalTableScaleWidthMode,
Title,
} from '@ui5/webcomponents-react';

import useResource from '../../lib/api/useApiResource';
import IllustratedError from '../Shared/IllustratedError';
import '@ui5/webcomponents-icons/dist/sys-enter-2';
import '@ui5/webcomponents-icons/dist/sys-cancel-2';
import { ProvidersListRequest } from '../../lib/api/types/crossplane/listProviders';
import { resourcesInterval } from '../../lib/shared/constants';
import { timeAgo } from '../../utils/i18n/timeAgo';
import { ResourceStatusCell } from '../Shared/ResourceStatusCell';

import { YamlViewButton } from '../Yaml/YamlViewButton.tsx';
import { useMemo } from 'react';

import '@ui5/webcomponents-icons/dist/sys-enter-2';
import '@ui5/webcomponents-icons/dist/sys-cancel-2';
import StatusFilter from '../Shared/StatusFilter.tsx';

interface CellData<T> {
cell: {
value: T | null; // null for grouping rows
value: T | null;
row: {
original?: ProvidersRow; // missing for grouping rows
original?: ProvidersRow;
};
};
}

type ProvidersRow = {
name: string;
version: string;
healthy: boolean;
healthy: string;
healthyTransitionTime: string;
installed: boolean;
installed: string;
installedTransitionTime: string;
created: string;
item: unknown;
Expand Down Expand Up @@ -67,10 +69,12 @@ export function Providers() {
accessor: 'installed',
hAlign: 'Center',
width: 85,
Filter: ({ column }) => <StatusFilter column={column} />,
filter: 'equals',
Cell: (cellData: CellData<ProvidersRow['installed']>) =>
cellData.cell.row.original?.installed != null ? (
<ResourceStatusCell
value={cellData.cell.row.original?.installed}
value={cellData.cell.row.original?.installed === 'true'}
transitionTime={
cellData.cell.row.original?.installedTransitionTime
}
Expand All @@ -82,26 +86,28 @@ export function Providers() {
accessor: 'healthy',
hAlign: 'Center',
width: 85,
Filter: ({ column }) => <StatusFilter column={column} />,
filter: 'equals',
Cell: (cellData: CellData<ProvidersRow['healthy']>) =>
cellData.cell.row.original?.installed != null ? (
<ResourceStatusCell
value={cellData.cell.row.original?.healthy}
value={cellData.cell.row.original?.healthy === 'true'}
transitionTime={cellData.cell.row.original?.healthyTransitionTime}
/>
) : null,
},

{
Header: t('yaml.YAML'),
hAlign: 'Center',
width: 85,
accessor: 'yaml',
disableFilters: true,
Cell: (cellData: CellData<ProvidersRow>) => (
<YamlViewButton resourceObject={cellData.cell.row.original?.item} />
),
},
],
[],
[t],
);

const rows: ProvidersRow[] =
Expand All @@ -115,9 +121,9 @@ export function Providers() {
return {
name: item.metadata.name,
created: timeAgo.format(new Date(item.metadata.creationTimestamp)),
installed: installed?.status === 'True',
installed: installed?.status === 'True' ? 'true' : 'false',
installedTransitionTime: installed?.lastTransitionTime ?? '',
healthy: healthy?.status === 'True',
healthy: healthy?.status === 'True' ? 'true' : 'false',
healthyTransitionTime: healthy?.lastTransitionTime ?? '',
version: item.spec.package.match(/\d+(\.\d+)+/g)?.toString() ?? '',
item: item,
Expand All @@ -138,7 +144,6 @@ export function Providers() {
scaleWidthMode={AnalyticalTableScaleWidthMode.Smart}
loading={isLoading}
filterable
// Prevent the table from resetting when the data changes
retainColumnWidth
reactTableOptions={{
autoResetHiddenColumns: false,
Expand Down
1 change: 1 addition & 0 deletions src/components/ControlPlane/ProvidersConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export function ProvidersConfig() {
hAlign: 'Center',
width: 85,
accessor: 'yaml',
disableFilters: true,
Cell: (cellData: CellData<Rows>) =>
cellData.cell.row.original?.resource ? (
<YamlViewButton
Expand Down
1 change: 1 addition & 0 deletions src/components/Projects/ProjectsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export default function ProjectsList() {
Header: t('yaml.YAML'),
accessor: 'yaml',
width: 85,
disableFilters: true,
hAlign: 'Center',
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Cell: (instance: any) => (
Expand Down
103 changes: 103 additions & 0 deletions src/components/Shared/StatusFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Select, Option, Icon } from '@ui5/webcomponents-react';

export interface StatusFilterProps {
column: {
filterValue?: string;
setFilter?: (value?: string) => void;
};
}

interface SelectChangeEventDetail {
selectedOption: HTMLElement & {
dataset?: {
value?: string;
};
};
}

type SelectChangeEvent = CustomEvent<SelectChangeEventDetail>;

interface OptionProps {
value: string;
iconName: string;
color: string;
labelKey: string;
isSelected: boolean;
}

const StatusFilter: React.FC<StatusFilterProps> = ({ column }) => {
const { t } = useTranslation();

const handleChange = (e: SelectChangeEvent) => {
const selectedOption = e.detail.selectedOption;
if (!selectedOption || !column.setFilter) return;

const val = selectedOption.dataset?.value;
column.setFilter(val === 'all' ? undefined : val);
};

const renderOption = ({
Copy link
Contributor

@andreaskienle andreaskienle Jun 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a component defined inside another component, isn’t it? That’s usually not recommended in React. Consider moving it outside the component. That said, if we really need access to the parent’s props or state and the component is pretty small, it’s usually fine. Just a heads-up

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed changes

value,
iconName,
color,
labelKey,
isSelected,
}: OptionProps) => (
<Option
data-value={value}
selected={isSelected}
style={{
padding: '6px 10px',
}}
>
<div
style={{
display: 'flex',
alignItems: 'center',
gap: 8,
}}
>
<Icon
name={iconName}
style={{
color,
width: 16,
height: 16,
flexShrink: 0,
}}
/>
<span style={{ fontSize: 14 }}>{t(labelKey)}</span>
</div>
</Option>
);

return (
<Select onChange={handleChange}>
{renderOption({
value: 'all',
iconName: 'filter',
color: 'gray',
labelKey: 'All',
isSelected: column.filterValue === undefined,
})}
{renderOption({
value: 'true',
iconName: 'sys-enter-2',
color: 'green',
labelKey: 'Enabled',
isSelected: column.filterValue === 'true',
})}
{renderOption({
value: 'false',
iconName: 'sys-cancel-2',
color: 'red',
labelKey: 'Disabled',
isSelected: column.filterValue === 'false',
})}
</Select>
);
};

export default StatusFilter;
Loading