@camunda/ccma-saas-frontend 0.0.33 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/components/c4-ai-usage/c4-ai-usage.types.d.ts +1 -1
- package/lib/esm/components/c4-billing-page/elements/current-usage-metrics.js +4 -2
- package/lib/esm/components/c4-billing-page/elements/value-metric.js +3 -3
- package/lib/esm/components/c4-billing-page/elements/value-metric.spec.d.ts +1 -0
- package/lib/esm/components/c4-billing-page/elements/value-metric.spec.js +49 -0
- package/lib/esm/components/c4-cluster-details-secure-connectivity/c4-cluster-details-secure-connectivity.d.ts +1 -1
- package/lib/esm/components/c4-cluster-details-secure-connectivity/c4-cluster-details-secure-connectivity.js +87 -38
- package/lib/esm/components/c4-cluster-list/c4-cluster-list.d.ts +1 -1
- package/lib/esm/components/c4-cluster-list/c4-cluster-list.js +107 -1
- package/lib/esm/components/c4-cluster-list/c4-cluster-list.spec.d.ts +1 -0
- package/lib/esm/components/c4-cluster-list/c4-cluster-list.spec.js +132 -0
- package/lib/esm/components/c4-cluster-overview/cluster-details.d.ts +1 -5
- package/lib/esm/components/c4-cluster-overview/cluster-details.js +4 -11
- package/lib/esm/components/c4-cluster-settings/elements/multi-tenancy.d.ts +2 -1
- package/lib/esm/components/c4-cluster-settings/elements/multi-tenancy.js +2 -2
- package/lib/esm/components/c4-clusters-empty-state/c4-clusters-empty-state.types.d.ts +1 -1
- package/lib/esm/components/c4-create-cluster/c4-create-cluster.js +36 -9
- package/lib/esm/components/c4-create-cluster/c4-create-cluster.spec.d.ts +1 -0
- package/lib/esm/components/c4-create-cluster/c4-create-cluster.spec.js +187 -0
- package/lib/esm/components/c4-create-cluster/c4-create-cluster.types.d.ts +5 -0
- package/lib/esm/components/c4-delete-organization-modal/c4-delete-organization-modal.d.ts +3 -0
- package/lib/esm/components/c4-delete-organization-modal/c4-delete-organization-modal.js +41 -0
- package/lib/esm/components/c4-delete-organization-modal/c4-delete-organization-modal.types.d.ts +10 -0
- package/lib/esm/components/c4-delete-organization-modal/c4-delete-organization-modal.types.js +6 -0
- package/lib/esm/components/c4-job-dashboard-details-page/c4-job-dashboard-details-page.d.ts +1 -0
- package/lib/esm/components/c4-job-dashboard-details-page/c4-job-dashboard-details-page.js +22 -9
- package/lib/esm/components/c4-job-dashboard-details-page/c4-job-dashboard-details-page.types.d.ts +3 -1
- package/lib/esm/components/c4-job-dashboard-details-page/elements/c4-job-dashboard-error-table.js +6 -3
- package/lib/esm/components/c4-job-dashboard-details-page/elements/c4-job-dashboard-piechart.js +5 -4
- package/lib/esm/components/c4-job-dashboard-details-page/elements/c4-job-dashboard-time-chart.js +22 -1
- package/lib/esm/components/c4-job-dashboard-details-page/elements/c4-job-dashboard-worker-table.js +6 -2
- package/lib/esm/components/c4-job-dashboard-entry-point/c4-job-dashboard-entry-point.js +17 -5
- package/lib/esm/components/c4-job-dashboard-entry-point/c4-job-dashboard-entry-point.types.d.ts +3 -1
- package/lib/esm/components/c4-job-dashboard-overview-page/c4-job-dashboard-overview.js +19 -6
- package/lib/esm/components/c4-job-dashboard-overview-page/c4-job-dashboard-overview.types.d.ts +4 -1
- package/lib/esm/components/c4-job-dashboard-shared/c4-job-dashboard-error-handler.d.ts +2 -6
- package/lib/esm/components/c4-job-dashboard-shared/c4-job-dashboard-error-handler.js +3 -3
- package/lib/esm/components/c4-job-dashboard-shared/c4-job-dashboard-shared.types.d.ts +1 -1
- package/lib/esm/components/c4-job-dashboard-shared/c4-job-dashboard-table-heading-with-tooltip.d.ts +1 -0
- package/lib/esm/components/c4-job-dashboard-shared/c4-job-dashboard-table-heading-with-tooltip.js +19 -0
- package/lib/esm/components/c4-llm-usage-meter/c4-llm-usage-meter.js +1 -1
- package/lib/esm/components/c4-llm-usage-meter/c4-llm-usage-meter.types.d.ts +3 -3
- package/lib/esm/components/c4-multi-step-modal-ugly/c4-multi-step-modal-ugly.d.ts +1 -1
- package/lib/esm/components/c4-multi-step-modal-ugly/c4-multi-step-modal-ugly.js +7 -8
- package/lib/esm/components/c4-multi-step-modal-ugly/c4-multi-step-modal-ugly.types.d.ts +5 -3
- package/lib/esm/components/c4-page-template/c4-page-template.spec.js +1 -1
- package/lib/esm/components/c4-search/c4-search-results.js +1 -1
- package/lib/esm/components/c4-search/c4-search.js +1 -1
- package/lib/esm/components/c4-sm-cluster-details/c4-sm-cluster-details.js +1 -1
- package/lib/esm/components/c4-tabs/c4-tabs.spec.js +1 -1
- package/lib/esm/components/c4-theme-switcher/c4-theme-switcher.d.ts +2 -0
- package/lib/esm/components/c4-theme-switcher/c4-theme-switcher.js +49 -6
- package/lib/esm/components/c4-theme-switcher/c4-theme-switcher.types.d.ts +1 -1
- package/lib/esm/components/c4-usage-history/elements/usage-history-charts.d.ts +2 -2
- package/lib/esm/components/c4-usage-history/elements/usage-history-charts.js +1 -1
- package/lib/esm/externalUrls.const.d.ts +90 -0
- package/lib/esm/externalUrls.const.js +191 -0
- package/lib/esm/externalUrls.const.spec.d.ts +1 -0
- package/lib/esm/externalUrls.const.spec.js +108 -0
- package/lib/esm/i18n/en/modals/clusters.json +46 -0
- package/lib/esm/i18n/en/pages/clusterdetails.json +52 -3
- package/lib/esm/i18n/en/pages/createcluster.json +3 -1
- package/lib/esm/i18n/en/pages/job-dashboard.json +13 -8
- package/lib/esm/i18n/en/pages/orgmanagement.json +4 -0
- package/lib/esm/index.d.ts +3 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/runtime/c4-console-authz.d.ts +2 -1
- package/lib/esm/runtime/c4-console-authz.js +29 -58
- package/lib/esm/runtime/c4-console-authz.spec.js +86 -0
- package/lib/esm/runtime/c4-console-data-context.js +9 -5
- package/lib/esm/runtime/c4-console-data-context.types.d.ts +5 -1
- package/lib/esm/runtime/c4-console-data-store.d.ts +5 -1
- package/lib/esm/runtime/c4-console-data-store.js +67 -2
- package/lib/esm/runtime/c4-console-data-store.spec.js +142 -0
- package/lib/esm/themes/future-carbon-light.css +64 -0
- package/lib/esm/themes/future-carbon.css +64 -0
- package/lib/esm/widgets/cluster-client-details/c4-cluster-client-details-app.js +3 -2
- package/lib/esm/widgets/cluster-client-details/c4-cluster-client-details-app.types.d.ts +2 -2
- package/lib/esm/widgets/cluster-details/c4-cluster-details-app.js +247 -72
- package/lib/esm/widgets/cluster-details/c4-cluster-details-app.permissions.spec.d.ts +1 -0
- package/lib/esm/widgets/cluster-details/c4-cluster-details-app.permissions.spec.js +431 -0
- package/lib/esm/widgets/cluster-details/c4-cluster-details-app.types.d.ts +71 -14
- package/lib/esm/widgets/cluster-details/c4-cluster-details-page.spec.js +1 -1
- package/lib/esm/widgets/cluster-details/c4-cluster-details-page.types.d.ts +1 -1
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-alerts-tab.d.ts +8 -2
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-alerts-tab.js +43 -10
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-alerts-tab.spec.d.ts +1 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-alerts-tab.spec.js +72 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-byom-clients-tab.d.ts +1 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-byom-clients-tab.js +18 -7
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-byom-clients-tab.spec.d.ts +1 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-byom-clients-tab.spec.js +85 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-clients-tab.d.ts +4 -1
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-clients-tab.js +21 -17
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-clients-tab.mcp.spec.js +1 -1
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-clients-tab.spec.d.ts +1 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-clients-tab.spec.js +155 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-connector-secrets-tab.d.ts +6 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-connector-secrets-tab.js +5 -5
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-encryption-tab.d.ts +5 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-encryption-tab.js +4 -4
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-hot-backups-tab.d.ts +8 -4
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-hot-backups-tab.js +59 -22
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-hot-backups-tab.spec.d.ts +1 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-hot-backups-tab.spec.js +130 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-overview-tab.d.ts +14 -3
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-overview-tab.js +453 -58
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-overview-tab.spec.d.ts +1 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-overview-tab.spec.js +588 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-secure-connectivity-tab.d.ts +4 -0
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-secure-connectivity-tab.js +281 -175
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-secure-connectivity-tab.spec.d.ts +1 -1
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-secure-connectivity-tab.spec.js +191 -6
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-settings-tab.d.ts +8 -1
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-settings-tab.js +304 -186
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-settings-tab.spec.d.ts +1 -1
- package/lib/esm/widgets/cluster-details/tabs/c4-cluster-details-settings-tab.spec.js +184 -10
- package/lib/esm/widgets/clusters/c4-clusters-page.js +5 -3
- package/lib/esm/widgets/clusters/c4-clusters-page.spec.js +39 -4
- package/lib/esm/widgets/connector-management/c4-connector-management-executable-details-page.js +1 -1
- package/lib/esm/widgets/connector-management/c4-connector-management-executables-table-page.js +1 -1
- package/lib/esm/widgets/connector-management/c4-connector-management-page.js +1 -1
- package/lib/esm/widgets/create-cluster/c4-create-cluster-page.js +27 -10
- package/lib/esm/widgets/create-cluster/c4-create-cluster-page.spec.js +14 -2
- package/lib/esm/widgets/create-cluster/c4-create-cluster-page.types.d.ts +5 -3
- package/lib/esm/widgets/dashboard/c4-dashboard-app.js +8 -7
- package/lib/esm/widgets/dashboard/c4-dashboard-app.types.d.ts +10 -9
- package/lib/esm/widgets/group-details/c4-group-details-page.js +2 -3
- package/lib/esm/widgets/group-details/c4-group-details-page.spec.js +1 -1
- package/lib/esm/widgets/group-details/c4-group-details-page.types.d.ts +1 -1
- package/lib/esm/widgets/management/c4-management-app.d.ts +1 -1
- package/lib/esm/widgets/management/c4-management-app.js +345 -91
- package/lib/esm/widgets/management/c4-management-app.spec.d.ts +1 -0
- package/lib/esm/widgets/management/c4-management-app.spec.js +347 -0
- package/lib/esm/widgets/management/c4-management-app.types.d.ts +25 -14
- package/lib/esm/widgets/management/tabs/c4-management-billing-tab.d.ts +1 -0
- package/lib/esm/widgets/management/tabs/c4-management-billing-tab.js +9 -1
- package/lib/esm/widgets/management/tabs/c4-management-usage-tab.d.ts +2 -1
- package/lib/esm/widgets/management/tabs/c4-management-usage-tab.js +22 -19
- package/lib/esm/widgets/management/tabs/c4-management-users-tab.d.ts +13 -1
- package/lib/esm/widgets/management/tabs/c4-management-users-tab.js +172 -21
- package/lib/esm/widgets/management/tabs/c4-management-users-tab.spec.js +63 -1
- package/lib/esm/widgets/user-details/c4-user-details-page.js +2 -3
- package/lib/esm/widgets/user-details/c4-user-details-page.spec.js +6 -2
- package/lib/esm/widgets/user-details/c4-user-details-page.types.d.ts +1 -1
- package/package.json +15 -15
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
/*
|
|
3
3
|
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
|
|
4
4
|
* under one or more contributor license agreements. Licensed under a commercial license.
|
|
@@ -38,7 +38,9 @@ export const CurrentUsageMetrics = ({ title, decisionInstances, description, gen
|
|
|
38
38
|
break;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
const component = (_jsx(C4TileWithTitleAndAction, { title: title, description: description, children: ['sm', 'md'].includes(mediaSize) ? (
|
|
41
|
+
const component = (_jsx(C4TileWithTitleAndAction, { title: title, description: description, children: ['sm', 'md'].includes(mediaSize) ? (_jsx(Stack, { gap: 5, children: Array.from({ length: Math.ceil(metrics.length / 2) }, (_, rowIndex) => (_jsx(Grid, { style: { ...STYLES.grid }, children: metrics
|
|
42
|
+
.slice(rowIndex * 2, rowIndex * 2 + 2)
|
|
43
|
+
.map((metric, colIndex) => (_jsx(Column, { span: 8, style: { ...STYLES.grid }, children: metric }, `metric-${metricsOrder[rowIndex * 2 + colIndex]}`))) }, `row-${rowIndex}`))) })) : (_jsx(Grid, { style: { ...STYLES.grid }, children: metrics.map((metric, index) => (_jsx(Column, { span: 4, style: { ...STYLES.grid }, children: metric }, `metric-${metricsOrder[index]}`))) })) }));
|
|
42
44
|
return component;
|
|
43
45
|
};
|
|
44
46
|
export function mediaSizeByWidth(width) {
|
|
@@ -103,14 +103,14 @@ const MeterVisualization = ({ currentPrefix, current, currentPostfix, max, maxPo
|
|
|
103
103
|
display: 'grid',
|
|
104
104
|
gridTemplateColumns: '1fr auto',
|
|
105
105
|
width: '100%',
|
|
106
|
-
}, children: [_jsx("p", { style: { fontSize: '18px' }, children: data.current }), _jsx("p", { style: { color: 'var(--cds-text-helper)', alignSelf: 'end' }, children: data.max })] }), _jsx(MeterChart, { data: [
|
|
106
|
+
}, children: [_jsx("p", { style: { fontSize: '18px' }, children: data.current }), _jsx("p", { style: { color: 'var(--cds-text-helper)', alignSelf: 'end' }, children: data.max })] }), max > 0 && (_jsx(MeterChart, { data: [
|
|
107
107
|
{
|
|
108
108
|
group,
|
|
109
109
|
value: current,
|
|
110
110
|
},
|
|
111
|
-
], options: chartOptions })] }));
|
|
111
|
+
], options: chartOptions }))] }));
|
|
112
112
|
return component;
|
|
113
113
|
};
|
|
114
114
|
function formatNumber(number) {
|
|
115
|
-
return new Intl.NumberFormat('en-US'
|
|
115
|
+
return new Intl.NumberFormat('en-US').format(number);
|
|
116
116
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
|
|
4
|
+
* under one or more contributor license agreements. Licensed under a commercial license.
|
|
5
|
+
* You may not use this file except in compliance with the commercial license.
|
|
6
|
+
*/
|
|
7
|
+
import { render, screen } from '@testing-library/react';
|
|
8
|
+
import { vi } from 'vitest';
|
|
9
|
+
import { ValueMetric } from './value-metric.js';
|
|
10
|
+
vi.mock('@carbon/charts-react', () => ({
|
|
11
|
+
MeterChart: ({ data }) => (_jsx("div", { "data-testid": 'meter-chart', "data-value": data[0]?.value })),
|
|
12
|
+
}));
|
|
13
|
+
function buildChartProps(current, max = 500000) {
|
|
14
|
+
return {
|
|
15
|
+
title: 'Process instances',
|
|
16
|
+
loading: false,
|
|
17
|
+
metric: {
|
|
18
|
+
kind: 'chart',
|
|
19
|
+
value: {
|
|
20
|
+
current,
|
|
21
|
+
max,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
describe('ValueMetric', () => {
|
|
27
|
+
describe('MeterChart (progress bar)', () => {
|
|
28
|
+
it('renders the progress bar when included (max) > 0', () => {
|
|
29
|
+
render(_jsx(ValueMetric, { ...buildChartProps(0, 500000) }));
|
|
30
|
+
expect(screen.getByTestId('meter-chart')).toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
it('renders the progress bar when both current and max are > 0', () => {
|
|
33
|
+
render(_jsx(ValueMetric, { ...buildChartProps(400000, 500000) }));
|
|
34
|
+
expect(screen.getByTestId('meter-chart')).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
it('does NOT render the progress bar when included (max) is zero', () => {
|
|
37
|
+
render(_jsx(ValueMetric, { ...buildChartProps(0, 0) }));
|
|
38
|
+
expect(screen.queryByTestId('meter-chart')).not.toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
it('does NOT render the progress bar when max is zero even if current > 0', () => {
|
|
41
|
+
render(_jsx(ValueMetric, { ...buildChartProps(5, 0) }));
|
|
42
|
+
expect(screen.queryByTestId('meter-chart')).not.toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
it('still renders the current and max values when included (max) is zero', () => {
|
|
45
|
+
render(_jsx(ValueMetric, { ...buildChartProps(0, 0) }));
|
|
46
|
+
expect(screen.getAllByText('0')).toHaveLength(2);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type JSX } from 'react';
|
|
2
2
|
import type { C4ClusterDetailsSecureConnectivityProps } from './c4-cluster-details-secure-connectivity.types';
|
|
3
3
|
export declare const C4ClusterDetailsSecureConnectivity: ({ status, privateEndpoints, connectInAwsUrl, isLoading, isDeactivating, text, permissions, urls, onOpenActivate, onOpenPrivateEndpoint, onOpenDocs, onDeactivate, onOpenConnectInAws, onEditAllowedPrincipals, onEditAllowedRegions, }: C4ClusterDetailsSecureConnectivityProps) => JSX.Element;
|
|
@@ -7,6 +7,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
import { C3DataTable, C3EmptyState, } from '@camunda/camunda-composite-components';
|
|
8
8
|
import { Button, CodeSnippet, Layer, Link, Stack, StructuredListBody, StructuredListCell, StructuredListRow, StructuredListWrapper, Tile, } from '@carbon/react';
|
|
9
9
|
import { CheckmarkFilled, Edit, Launch, PendingFilled, } from '@carbon/react/icons/index.esm.js';
|
|
10
|
+
import { useEffect, useState } from 'react';
|
|
11
|
+
const singleSnippetMaxWidth = '48rem';
|
|
10
12
|
export const C4ClusterDetailsSecureConnectivity = ({ status, privateEndpoints, connectInAwsUrl, isLoading, isDeactivating, text, permissions, urls, onOpenActivate, onOpenPrivateEndpoint, onOpenDocs, onDeactivate, onOpenConnectInAws, onEditAllowedPrincipals, onEditAllowedRegions, }) => {
|
|
11
13
|
const endpointRows = (privateEndpoints ?? []).map((endpoint, index) => ({
|
|
12
14
|
id: endpoint.id,
|
|
@@ -102,15 +104,20 @@ export const C4ClusterDetailsSecureConnectivity = ({ status, privateEndpoints, c
|
|
|
102
104
|
if (!value) {
|
|
103
105
|
return _jsx("span", { children: "\u2014" });
|
|
104
106
|
}
|
|
105
|
-
return (_jsx(Layer, { style: { width: '100%', minWidth: 0 }, children: _jsx(CodeSnippet, { type: 'single', children: value }) }));
|
|
107
|
+
return (_jsx(Layer, { style: { width: '100%', maxWidth: singleSnippetMaxWidth, minWidth: 0 }, children: _jsx(CodeSnippet, { type: 'single', children: value }) }));
|
|
106
108
|
};
|
|
107
109
|
const renderListFieldWithEdit = (options) => {
|
|
108
110
|
const values = options.values ?? [];
|
|
109
111
|
return (_jsxs("div", { style: {
|
|
110
112
|
display: 'flex',
|
|
113
|
+
width: '100%',
|
|
114
|
+
minWidth: 0,
|
|
115
|
+
maxWidth: options.alignToSingleSnippet
|
|
116
|
+
? singleSnippetMaxWidth
|
|
117
|
+
: undefined,
|
|
111
118
|
gap: 'var(--cds-spacing-02)',
|
|
112
119
|
alignItems: values.length > 1 ? 'flex-start' : 'center',
|
|
113
|
-
}, children: [_jsx("div", { style: { flex: 1, minWidth: 0 }, children: values.length ? (_jsx(Stack, { gap: 1, children: values.map((value) => (_jsx(CodeSnippet, { type: 'inline', align: 'top', children: value }, value))) })) : (_jsx("span", { children: "\u2014" })) }), options.onEdit ? (_jsx(Button, { kind: 'ghost', size: '
|
|
120
|
+
}, children: [_jsx("div", { style: { flex: 1, minWidth: 0 }, children: values.length ? (_jsx(Stack, { gap: 1, children: values.map((value) => (_jsx(CodeSnippet, { type: 'inline', align: 'top', children: value }, value))) })) : (_jsx("span", { children: "\u2014" })) }), options.onEdit ? (_jsx(Button, { kind: 'ghost', size: 'md', hasIconOnly: true, renderIcon: Edit, iconDescription: options.editLabel, onClick: () => options.onEdit?.() })) : undefined] }));
|
|
114
121
|
};
|
|
115
122
|
const labelCellLeftStyle = {
|
|
116
123
|
width: '12rem',
|
|
@@ -121,11 +128,43 @@ export const C4ClusterDetailsSecureConnectivity = ({ status, privateEndpoints, c
|
|
|
121
128
|
color: 'var(--cds-text-secondary)',
|
|
122
129
|
paddingLeft: '40px',
|
|
123
130
|
};
|
|
131
|
+
const helperText01Style = {
|
|
132
|
+
fontSize: 'var(--cds-helper-text-01-font-size)',
|
|
133
|
+
fontWeight: 'var(--cds-helper-text-01-font-weight)',
|
|
134
|
+
lineHeight: 'var(--cds-helper-text-01-line-height)',
|
|
135
|
+
letterSpacing: 'var(--cds-helper-text-01-letter-spacing)',
|
|
136
|
+
color: 'var(--cds-text-secondary)',
|
|
137
|
+
};
|
|
138
|
+
// Responsive layout: switch to single-column when the viewport is narrower
|
|
139
|
+
// than 1520px (the point at which the 2-column layout starts breaking).
|
|
140
|
+
// Measuring window.innerWidth is simpler and more reliable than observing
|
|
141
|
+
// the container element: the content tile sits inside Carbon's 1584px max
|
|
142
|
+
// grid with a sidebar, so the container never reaches the element-width
|
|
143
|
+
// thresholds that would be needed to detect this breakpoint.
|
|
144
|
+
const [isNarrowLayout, setIsNarrowLayout] = useState(() => typeof window !== 'undefined' && window.innerWidth < 1520);
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
const handleResize = () => setIsNarrowLayout(window.innerWidth < 1520);
|
|
147
|
+
window.addEventListener('resize', handleResize);
|
|
148
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
149
|
+
}, []);
|
|
150
|
+
const deactivateLinkElement = onDeactivate ? (_jsx(Link, { href: '#', "aria-disabled": !permissions.canDeactivate || !!isDeactivating, tabIndex: !permissions.canDeactivate || isDeactivating ? -1 : undefined, onClick: (e) => {
|
|
151
|
+
e.preventDefault();
|
|
152
|
+
if (permissions.canDeactivate && !isDeactivating) {
|
|
153
|
+
onDeactivate();
|
|
154
|
+
}
|
|
155
|
+
}, style: !permissions.canDeactivate || isDeactivating
|
|
156
|
+
? {
|
|
157
|
+
color: 'var(--cds-text-disabled)',
|
|
158
|
+
pointerEvents: 'none',
|
|
159
|
+
}
|
|
160
|
+
: undefined, children: isDeactivating
|
|
161
|
+
? text.deactivatingButton
|
|
162
|
+
: (text.deactivateButton ?? 'Deactivate service') })) : undefined;
|
|
124
163
|
if (!isReady) {
|
|
125
164
|
return (_jsx(C3EmptyState, { icon: {
|
|
126
165
|
path: `../../../../assets/secureConnectivity.svg`,
|
|
127
166
|
altText: 'secureConnectivityIcon',
|
|
128
|
-
}, heading: text.emptyTitle, description: text.emptyDescription, button: status?.status !== undefined
|
|
167
|
+
}, heading: text.emptyTitle, description: text.emptyDescription, button: isLoading || status?.status !== undefined
|
|
129
168
|
? undefined
|
|
130
169
|
: {
|
|
131
170
|
onClick: () => onOpenActivate(),
|
|
@@ -142,47 +181,57 @@ export const C4ClusterDetailsSecureConnectivity = ({ status, privateEndpoints, c
|
|
|
142
181
|
display: 'flex',
|
|
143
182
|
alignItems: 'center',
|
|
144
183
|
gap: 'var(--cds-spacing-05)',
|
|
145
|
-
}, children: _jsx("h4", { style: { margin: 0 }, children: text.serviceDetailsTitle ?? 'Service details' }) }), _jsx(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
:
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
184
|
+
}, children: _jsx("h4", { style: { margin: 0 }, children: text.serviceDetailsTitle ?? 'Service details' }) }), _jsx("div", { children: isNarrowLayout ? (
|
|
185
|
+
// Single-column layout: each field on its own row
|
|
186
|
+
_jsx(StructuredListWrapper, { isCondensed: true, isFlush: true, style: { borderTop: 'none' }, children: _jsxs(StructuredListBody, { children: [_jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.enabledStatusLabel ?? 'Status' }), _jsx(StructuredListCell, { style: { borderTop: 'none' }, children: _jsxs("div", { style: {
|
|
187
|
+
display: 'flex',
|
|
188
|
+
justifyContent: 'space-between',
|
|
189
|
+
alignItems: 'center',
|
|
190
|
+
}, children: [statusElement, deactivateLinkElement] }) })] }), _jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.serviceNameLabel ?? 'Service name' }), _jsx(StructuredListCell, { style: { minWidth: 0 }, children: renderInlineCodeField(endpoint?.serviceName) })] }), _jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.serviceRegionLabel ?? 'Service region' }), _jsx(StructuredListCell, { style: { minWidth: 0 }, children: renderInlineCodeField(endpoint?.region) })] }), _jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.serviceTypeLabel ?? 'Service type' }), _jsx(StructuredListCell, { style: { minWidth: 0 }, children: renderInlineCodeField(endpoint?.type) })] }), _jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.privateDnsNameLabel ?? 'Private DNS name' }), _jsx(StructuredListCell, { style: { minWidth: 0 }, children: renderInlineCodeField(endpoint?.privateDnsName) })] }), _jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.allowedPrincipalsLabel }), _jsx(StructuredListCell, { style: { minWidth: 0 }, children: renderListFieldWithEdit({
|
|
191
|
+
values: status?.spec.allowedPrincipals,
|
|
192
|
+
onEdit: onEditAllowedPrincipals,
|
|
193
|
+
editLabel: 'Edit allowed principals',
|
|
194
|
+
alignToSingleSnippet: true,
|
|
195
|
+
}) })] }), _jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.allowedRegionsLabel }), _jsx(StructuredListCell, { style: { minWidth: 0 }, children: renderListFieldWithEdit({
|
|
196
|
+
values: status?.spec.allowedRegions,
|
|
197
|
+
onEdit: onEditAllowedRegions,
|
|
198
|
+
editLabel: 'Edit supported regions',
|
|
199
|
+
alignToSingleSnippet: true,
|
|
200
|
+
}) })] })] }) })) : (
|
|
201
|
+
// Two-column layout: pairs of fields side-by-side
|
|
202
|
+
_jsx(StructuredListWrapper, { isCondensed: true, isFlush: true, style: { borderTop: 'none', overflowX: 'auto' }, children: _jsxs(StructuredListBody, { children: [_jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.enabledStatusLabel ?? 'Status' }), _jsx(StructuredListCell, { style: { borderTop: 'none' }, children: statusElement }), _jsx(StructuredListCell, { noWrap: true, style: labelCellRightStyle, children: _jsx("span", { style: { opacity: 0 }, children: "\u2014" }) }), _jsx(StructuredListCell, { style: {
|
|
203
|
+
borderTop: 'none',
|
|
204
|
+
textAlign: 'right',
|
|
205
|
+
}, children: deactivateLinkElement })] }), _jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.serviceNameLabel ?? 'Service name' }), _jsx(StructuredListCell, { style: {
|
|
206
|
+
minWidth: 0,
|
|
207
|
+
paddingRight: '40px',
|
|
208
|
+
}, children: renderInlineCodeField(endpoint?.serviceName) }), _jsx(StructuredListCell, { noWrap: true, style: labelCellRightStyle, children: text.serviceRegionLabel ?? 'Service region' }), _jsx(StructuredListCell, { style: { minWidth: 0 }, children: renderInlineCodeField(endpoint?.region) })] }), _jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.serviceTypeLabel ?? 'Service type' }), _jsx(StructuredListCell, { style: {
|
|
209
|
+
minWidth: 0,
|
|
210
|
+
paddingRight: '40px',
|
|
211
|
+
}, children: renderInlineCodeField(endpoint?.type) }), _jsx(StructuredListCell, { noWrap: true, style: labelCellRightStyle, children: text.privateDnsNameLabel ?? 'Private DNS name' }), _jsx(StructuredListCell, { style: { minWidth: 0 }, children: renderInlineCodeField(endpoint?.privateDnsName) })] }), _jsxs(StructuredListRow, { children: [_jsx(StructuredListCell, { noWrap: true, style: labelCellLeftStyle, children: text.allowedPrincipalsLabel }), _jsx(StructuredListCell, { style: {
|
|
212
|
+
minWidth: 0,
|
|
213
|
+
paddingRight: '40px',
|
|
214
|
+
}, children: renderListFieldWithEdit({
|
|
215
|
+
values: status?.spec.allowedPrincipals,
|
|
216
|
+
onEdit: onEditAllowedPrincipals,
|
|
217
|
+
editLabel: 'Edit allowed principals',
|
|
218
|
+
}) }), _jsx(StructuredListCell, { noWrap: true, style: labelCellRightStyle, children: text.allowedRegionsLabel }), _jsx(StructuredListCell, { style: { minWidth: 0 }, children: renderListFieldWithEdit({
|
|
219
|
+
values: status?.spec.allowedRegions,
|
|
220
|
+
onEdit: onEditAllowedRegions,
|
|
221
|
+
editLabel: 'Edit supported regions',
|
|
222
|
+
}) })] })] }) })) }), _jsx("div", { children: _jsxs(Stack, { gap: 3, children: [_jsx("h4", { style: { margin: 0, marginTop: '12px' }, children: text.connectTitle ?? 'Connect to the service' }), connectInAwsUrl ? (_jsx(Button, { kind: 'tertiary', size: 'md', renderIcon: Launch, style: { whiteSpace: 'nowrap', maxWidth: '100%' }, onClick: () => {
|
|
178
223
|
if (onOpenConnectInAws) {
|
|
179
224
|
onOpenConnectInAws(connectInAwsUrl);
|
|
180
225
|
}
|
|
181
226
|
}, disabled: !onOpenConnectInAws, children: text.connectInAwsButtonLabel ??
|
|
182
|
-
'Create interface VPC endpoint connections in AWS' })) : undefined, text.connectHelperText ? (_jsx("div", { style:
|
|
227
|
+
'Create interface VPC endpoint connections in AWS' })) : undefined, text.connectHelperText ? (_jsx("div", { style: helperText01Style, children: text.connectHelperText })) : undefined] }) }), _jsxs("div", { children: [_jsx("div", { style: {
|
|
183
228
|
borderTop: '1px solid var(--cds-border-subtle-01)',
|
|
184
229
|
paddingTop: 'var(--cds-spacing-05)',
|
|
185
|
-
} }), _jsxs("h4", { style: {
|
|
230
|
+
} }), _jsxs("h4", { style: {
|
|
231
|
+
margin: 0,
|
|
232
|
+
marginTop: '12px',
|
|
233
|
+
marginBottom: 'var(--cds-spacing-03)',
|
|
234
|
+
}, children: [text.endpointConnectionsTitle ?? 'Endpoint connections', " (", endpointConnectionsCount, ")"] }), endpointRows.length === 0 && !isLoading ? (_jsx("div", { style: {
|
|
186
235
|
color: 'var(--cds-text-secondary)',
|
|
187
236
|
marginLeft: '24px',
|
|
188
237
|
marginBottom: '16px',
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type JSX } from 'react';
|
|
2
2
|
import type { C4ClusterListProps } from './c4-cluster-list.types';
|
|
3
3
|
export declare const C4ClusterList: ({ clusters, loading, urls, permissions, onNavigate, onDeleteCluster, onAssignTag, onWakeCluster, trialNotification, encryptionNotification, clusterCapMessage, emptyStateContent, translations, isClusterPaused, isRunningOnUnsupportedGeneration, }: C4ClusterListProps) => JSX.Element;
|
|
@@ -7,10 +7,16 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
7
7
|
import { C3ClusterTag, C3DataTable, } from '@camunda/camunda-composite-components';
|
|
8
8
|
import { Button, InlineNotification, Link } from '@carbon/react';
|
|
9
9
|
import { Add, WarningAltFilled } from '@carbon/react/icons/index.esm.js';
|
|
10
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, } from 'react';
|
|
10
11
|
import { ClusterStatusElement } from '../c4-cluster-overview/applications.js';
|
|
11
12
|
import { C4IconAndTextElement, getClusterLoadConfig, } from '../c4-cluster-overview/c4-cluster-overview.js';
|
|
12
13
|
import { C4LinkButton } from '../c4-link-button/c4-link-button.js';
|
|
13
14
|
import { C4PageTemplate } from '../c4-page-template/c4-page-template.js';
|
|
15
|
+
const DEFAULT_PAGE_SIZE = 10;
|
|
16
|
+
const PAGE_NUMBER_SELECTOR = '.cds--select__page-number select';
|
|
17
|
+
const PAGE_SIZE_SELECTOR = '.cds--select__item-count select';
|
|
18
|
+
const PAGE_FORWARD_BUTTON_SELECTOR = '.cds--pagination__button--forward';
|
|
19
|
+
const PAGE_BACKWARD_BUTTON_SELECTOR = '.cds--pagination__button--backward';
|
|
14
20
|
function isPlainLeftClick(event) {
|
|
15
21
|
return (event.button === 0 &&
|
|
16
22
|
!event.defaultPrevented &&
|
|
@@ -20,6 +26,106 @@ function isPlainLeftClick(event) {
|
|
|
20
26
|
!event.shiftKey);
|
|
21
27
|
}
|
|
22
28
|
export const C4ClusterList = ({ clusters, loading, urls, permissions, onNavigate, onDeleteCluster, onAssignTag, onWakeCluster, trialNotification, encryptionNotification, clusterCapMessage, emptyStateContent, translations, isClusterPaused, isRunningOnUnsupportedGeneration, }) => {
|
|
29
|
+
const tableContainerRef = useRef(null);
|
|
30
|
+
const stableClustersRef = useRef(clusters.map((cluster) => ({ ...cluster })));
|
|
31
|
+
const selectedPageRef = useRef(1);
|
|
32
|
+
const syncPageTimeoutRef = useRef(undefined);
|
|
33
|
+
const stableClusters = (() => {
|
|
34
|
+
const previousClusters = stableClustersRef.current;
|
|
35
|
+
const canReusePreviousClusters = previousClusters.length === clusters.length &&
|
|
36
|
+
previousClusters.every((cluster, index) => cluster.id === clusters[index]?.id);
|
|
37
|
+
if (canReusePreviousClusters) {
|
|
38
|
+
clusters.forEach((cluster, index) => {
|
|
39
|
+
Object.assign(previousClusters[index], cluster);
|
|
40
|
+
});
|
|
41
|
+
return previousClusters;
|
|
42
|
+
}
|
|
43
|
+
const nextClusters = clusters.map((cluster) => ({ ...cluster }));
|
|
44
|
+
stableClustersRef.current = nextClusters;
|
|
45
|
+
return nextClusters;
|
|
46
|
+
})();
|
|
47
|
+
const readPageSelect = useCallback(() => {
|
|
48
|
+
return (tableContainerRef.current?.querySelector(PAGE_NUMBER_SELECTOR) ?? null);
|
|
49
|
+
}, []);
|
|
50
|
+
const readPageSizeSelect = useCallback(() => {
|
|
51
|
+
return (tableContainerRef.current?.querySelector(PAGE_SIZE_SELECTOR) ?? null);
|
|
52
|
+
}, []);
|
|
53
|
+
const syncSelectedPageFromDom = useCallback(() => {
|
|
54
|
+
const pageSelect = readPageSelect();
|
|
55
|
+
if (!pageSelect) {
|
|
56
|
+
selectedPageRef.current = 1;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const page = Number(pageSelect.value);
|
|
60
|
+
if (Number.isFinite(page) && page > 0) {
|
|
61
|
+
selectedPageRef.current = page;
|
|
62
|
+
}
|
|
63
|
+
}, [readPageSelect]);
|
|
64
|
+
const scheduleSelectedPageSync = useCallback(() => {
|
|
65
|
+
if (typeof window === 'undefined') {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (syncPageTimeoutRef.current !== undefined) {
|
|
69
|
+
window.clearTimeout(syncPageTimeoutRef.current);
|
|
70
|
+
}
|
|
71
|
+
syncPageTimeoutRef.current = window.setTimeout(() => {
|
|
72
|
+
syncSelectedPageFromDom();
|
|
73
|
+
syncPageTimeoutRef.current = undefined;
|
|
74
|
+
}, 0);
|
|
75
|
+
}, [syncSelectedPageFromDom]);
|
|
76
|
+
useEffect(() => {
|
|
77
|
+
const tableContainer = tableContainerRef.current;
|
|
78
|
+
if (!tableContainer) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const pageSelect = tableContainer.querySelector(PAGE_NUMBER_SELECTOR);
|
|
82
|
+
const forwardButton = tableContainer.querySelector(PAGE_FORWARD_BUTTON_SELECTOR);
|
|
83
|
+
const backwardButton = tableContainer.querySelector(PAGE_BACKWARD_BUTTON_SELECTOR);
|
|
84
|
+
pageSelect?.addEventListener('change', syncSelectedPageFromDom);
|
|
85
|
+
forwardButton?.addEventListener('click', scheduleSelectedPageSync);
|
|
86
|
+
backwardButton?.addEventListener('click', scheduleSelectedPageSync);
|
|
87
|
+
return () => {
|
|
88
|
+
pageSelect?.removeEventListener('change', syncSelectedPageFromDom);
|
|
89
|
+
forwardButton?.removeEventListener('click', scheduleSelectedPageSync);
|
|
90
|
+
backwardButton?.removeEventListener('click', scheduleSelectedPageSync);
|
|
91
|
+
};
|
|
92
|
+
}, [scheduleSelectedPageSync, syncSelectedPageFromDom, stableClusters.length]);
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
return () => {
|
|
95
|
+
if (typeof window !== 'undefined' &&
|
|
96
|
+
syncPageTimeoutRef.current !== undefined) {
|
|
97
|
+
window.clearTimeout(syncPageTimeoutRef.current);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}, []);
|
|
101
|
+
useLayoutEffect(() => {
|
|
102
|
+
if (typeof window === 'undefined') {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const pageSelect = readPageSelect();
|
|
106
|
+
if (!pageSelect) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const currentPage = Number(pageSelect.value);
|
|
110
|
+
const currentPageSize = Number(readPageSizeSelect()?.value);
|
|
111
|
+
const pageSize = Number.isFinite(currentPageSize) && currentPageSize > 0
|
|
112
|
+
? currentPageSize
|
|
113
|
+
: DEFAULT_PAGE_SIZE;
|
|
114
|
+
const maxPage = Math.max(1, Math.ceil(stableClusters.length / pageSize));
|
|
115
|
+
const nextPage = Math.min(selectedPageRef.current, maxPage);
|
|
116
|
+
selectedPageRef.current = nextPage;
|
|
117
|
+
if (nextPage <= 1 || currentPage === nextPage) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
pageSelect.value = String(nextPage);
|
|
121
|
+
pageSelect.dispatchEvent(new Event('change', { bubbles: true }));
|
|
122
|
+
syncSelectedPageFromDom();
|
|
123
|
+
}, [
|
|
124
|
+
readPageSelect,
|
|
125
|
+
readPageSizeSelect,
|
|
126
|
+
stableClusters,
|
|
127
|
+
syncSelectedPageFromDom,
|
|
128
|
+
]);
|
|
23
129
|
const headerData = [
|
|
24
130
|
{
|
|
25
131
|
label: translations.headers.name,
|
|
@@ -208,7 +314,7 @@ export const C4ClusterList = ({ clusters, loading, urls, permissions, onNavigate
|
|
|
208
314
|
paddingBlockEnd: 'var(--cds-spacing-07)',
|
|
209
315
|
}, children: [_jsx("p", { style: { color: 'var(--cds-text-secondary)' }, children: translations.emptyState.noClusters }), permissions.canCreateCluster && (_jsx("div", { style: { marginTop: 'var(--cds-spacing-05)' }, children: _jsx(Button, { kind: 'primary', onClick: () => onNavigate(urls.createCluster), disabled: permissions.createClusterButtonDisabled, children: translations.createButton }) }))] })));
|
|
210
316
|
}
|
|
211
|
-
return (_jsx(C3DataTable, { headers: headerData, isLoading: loading, toolbar: toolbar, actions: actions, data:
|
|
317
|
+
return (_jsx("div", { ref: tableContainerRef, children: _jsx(C3DataTable, { headers: headerData, isLoading: loading, toolbar: toolbar, actions: actions, data: stableClusters, queryPrefix: 'cluster-list' }) }));
|
|
212
318
|
};
|
|
213
319
|
return (_jsxs(_Fragment, { children: [trialNotification, _jsxs(C4PageTemplate, { loading: loading, header: {
|
|
214
320
|
title: translations.title,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
|
|
4
|
+
* under one or more contributor license agreements. Licensed under a commercial license.
|
|
5
|
+
* You may not use this file except in compliance with the commercial license.
|
|
6
|
+
*/
|
|
7
|
+
import { render, waitFor } from '@testing-library/react';
|
|
8
|
+
import userEvent from '@testing-library/user-event';
|
|
9
|
+
import { C4ClusterList } from './c4-cluster-list.js';
|
|
10
|
+
function createCluster(id) {
|
|
11
|
+
return {
|
|
12
|
+
id: `cluster-${id}`,
|
|
13
|
+
name: `Cluster ${id}`,
|
|
14
|
+
generation: '8.8',
|
|
15
|
+
type: 'Production',
|
|
16
|
+
region: 'eu-central-1',
|
|
17
|
+
status: 'healthy',
|
|
18
|
+
tags: [],
|
|
19
|
+
originalIndex: id - 1,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function buildProps(clusters) {
|
|
23
|
+
return {
|
|
24
|
+
orgId: 'org-1',
|
|
25
|
+
clusters,
|
|
26
|
+
loading: false,
|
|
27
|
+
urls: {
|
|
28
|
+
clusterDetails: (clusterId) => `/org/org-1/clusters/${clusterId}`,
|
|
29
|
+
createCluster: '/org/org-1/clusters/create',
|
|
30
|
+
},
|
|
31
|
+
permissions: {
|
|
32
|
+
canCreateCluster: true,
|
|
33
|
+
canEditCluster: true,
|
|
34
|
+
canDeleteCluster: true,
|
|
35
|
+
canUpdateTag: true,
|
|
36
|
+
canSeeClusterLoad: false,
|
|
37
|
+
canWakeCluster: true,
|
|
38
|
+
createClusterButtonDisabled: false,
|
|
39
|
+
},
|
|
40
|
+
onNavigate: vi.fn(),
|
|
41
|
+
onDeleteCluster: vi.fn(),
|
|
42
|
+
onAssignTag: vi.fn(),
|
|
43
|
+
onWakeCluster: vi.fn(),
|
|
44
|
+
translations: {
|
|
45
|
+
title: 'Clusters',
|
|
46
|
+
createButton: 'Create cluster',
|
|
47
|
+
searchLabel: 'Search',
|
|
48
|
+
emptyState: {
|
|
49
|
+
noClusters: 'No clusters',
|
|
50
|
+
},
|
|
51
|
+
headers: {
|
|
52
|
+
name: 'Name',
|
|
53
|
+
generation: 'Generation',
|
|
54
|
+
type: 'Type',
|
|
55
|
+
region: 'Region',
|
|
56
|
+
status: 'Status',
|
|
57
|
+
tags: 'Tags',
|
|
58
|
+
},
|
|
59
|
+
overflowMenu: {
|
|
60
|
+
delete: 'Delete',
|
|
61
|
+
resume: 'Resume',
|
|
62
|
+
},
|
|
63
|
+
tags: {
|
|
64
|
+
addLabel: 'Add tag',
|
|
65
|
+
},
|
|
66
|
+
tooltips: {
|
|
67
|
+
clusterLoad: 'Cluster load',
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
isClusterPaused: () => false,
|
|
71
|
+
isRunningOnUnsupportedGeneration: () => false,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function getPageSelect() {
|
|
75
|
+
const pageSelect = document.querySelector('.cds--select__page-number select');
|
|
76
|
+
if (!pageSelect) {
|
|
77
|
+
throw new Error('Expected cluster list pagination page select');
|
|
78
|
+
}
|
|
79
|
+
return pageSelect;
|
|
80
|
+
}
|
|
81
|
+
describe('C4ClusterList pagination', () => {
|
|
82
|
+
it('preserves the selected page when clusters are added or removed', async () => {
|
|
83
|
+
const user = userEvent.setup();
|
|
84
|
+
const initialClusters = Array.from({ length: 20 }, (_, index) => {
|
|
85
|
+
return createCluster(index + 1);
|
|
86
|
+
});
|
|
87
|
+
const { rerender } = render(_jsx(C4ClusterList, { ...buildProps(initialClusters) }));
|
|
88
|
+
await waitFor(() => {
|
|
89
|
+
expect(getPageSelect().value).toBe('1');
|
|
90
|
+
});
|
|
91
|
+
await user.selectOptions(getPageSelect(), '2');
|
|
92
|
+
await waitFor(() => {
|
|
93
|
+
expect(getPageSelect().value).toBe('2');
|
|
94
|
+
});
|
|
95
|
+
rerender(_jsx(C4ClusterList, { ...buildProps([...initialClusters, createCluster(21)]) }));
|
|
96
|
+
await waitFor(() => {
|
|
97
|
+
expect(getPageSelect().value).toBe('2');
|
|
98
|
+
});
|
|
99
|
+
rerender(_jsx(C4ClusterList, { ...buildProps(initialClusters.slice(0, 19)) }));
|
|
100
|
+
await waitFor(() => {
|
|
101
|
+
expect(getPageSelect().value).toBe('2');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
it('preserves the selected page when cluster data updates without changing list length', async () => {
|
|
105
|
+
const user = userEvent.setup();
|
|
106
|
+
const initialClusters = Array.from({ length: 20 }, (_, index) => {
|
|
107
|
+
return createCluster(index + 1);
|
|
108
|
+
});
|
|
109
|
+
const { rerender } = render(_jsx(C4ClusterList, { ...buildProps(initialClusters) }));
|
|
110
|
+
await waitFor(() => {
|
|
111
|
+
expect(getPageSelect().value).toBe('1');
|
|
112
|
+
});
|
|
113
|
+
await user.selectOptions(getPageSelect(), '2');
|
|
114
|
+
await waitFor(() => {
|
|
115
|
+
expect(getPageSelect().value).toBe('2');
|
|
116
|
+
});
|
|
117
|
+
const updatedClusters = initialClusters.map((cluster, index) => {
|
|
118
|
+
if (index !== 0) {
|
|
119
|
+
return cluster;
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
...cluster,
|
|
123
|
+
status: 'updating',
|
|
124
|
+
generation: '8.8.1',
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
rerender(_jsx(C4ClusterList, { ...buildProps(updatedClusters) }));
|
|
128
|
+
await waitFor(() => {
|
|
129
|
+
expect(getPageSelect().value).toBe('2');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -90,7 +90,7 @@ export interface ClusterDetailsProps {
|
|
|
90
90
|
}
|
|
91
91
|
export declare const ClusterDetails: (props: ClusterDetailsProps) => JSX.Element;
|
|
92
92
|
export interface ClusterDetailsGenerationUpdateProps {
|
|
93
|
-
updateType: 'update-available' | 'update-available-wait-needed' | 'update-available-no-permissions' | 'no-update-latest' | '
|
|
93
|
+
updateType: 'update-available' | 'update-available-wait-needed' | 'update-available-no-permissions' | 'no-update-latest' | 'updating' | 'creating';
|
|
94
94
|
updateStates: {
|
|
95
95
|
updateAvailable: {
|
|
96
96
|
action: () => void;
|
|
@@ -107,10 +107,6 @@ export interface ClusterDetailsGenerationUpdateProps {
|
|
|
107
107
|
noUpdateLatest: {
|
|
108
108
|
label: string;
|
|
109
109
|
};
|
|
110
|
-
noUpdateRefresh: {
|
|
111
|
-
action: () => void;
|
|
112
|
-
label: string;
|
|
113
|
-
};
|
|
114
110
|
};
|
|
115
111
|
}
|
|
116
112
|
export declare const ClusterDetailsGenerationUpdate: (props: ClusterDetailsGenerationUpdateProps) => JSX.Element;
|
|
@@ -5,8 +5,8 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
5
5
|
* You may not use this file except in compliance with the commercial license.
|
|
6
6
|
*/
|
|
7
7
|
import { C3ClusterTag, } from '@camunda/camunda-composite-components';
|
|
8
|
-
import { Button, CodeSnippet,
|
|
9
|
-
import { Add, Information, Pause, Play,
|
|
8
|
+
import { Button, CodeSnippet, Layer, StructuredListBody, StructuredListCell, StructuredListRow, StructuredListWrapper, TextArea, } from '@carbon/react';
|
|
9
|
+
import { Add, Information, Pause, Play, UpdateNow } from '@carbon/react/icons/index.esm.js';
|
|
10
10
|
import { useEffect, useRef, useState } from 'react';
|
|
11
11
|
import { C4ActionableNotification } from '../c4-actionable-notification/c4-actionable-notification.js';
|
|
12
12
|
import { C4LinkButton } from '../c4-link-button/c4-link-button.js';
|
|
@@ -102,6 +102,7 @@ export const ClusterDetails = (props) => {
|
|
|
102
102
|
display: 'grid',
|
|
103
103
|
gridTemplateColumns: 'auto 1fr',
|
|
104
104
|
gap: '0.5rem',
|
|
105
|
+
alignItems: 'center',
|
|
105
106
|
}, children: [_jsx("p", { children: props.generation.value }), props.status?.value.toLowerCase() === 'healthy' && (_jsx(ClusterDetailsGenerationUpdate, { ...props.generation.update }))] }) })] }), props.type && (_jsxs(StructuredListRow, { style: rowStyle, children: [_jsx(StructuredListCell, { noWrap: true, children: props.type.label }), _jsx(StructuredListCell, { noWrap: true, children: _jsxs("div", { style: {
|
|
106
107
|
display: 'inline-grid',
|
|
107
108
|
gridAutoFlow: 'column',
|
|
@@ -119,7 +120,7 @@ export const ClusterDetailsGenerationUpdate = (props) => {
|
|
|
119
120
|
const latestMessage = 'No updates available - running on latest available version';
|
|
120
121
|
switch (props.updateType) {
|
|
121
122
|
case 'update-available':
|
|
122
|
-
component = (_jsx(Button, { onClick: () => props.updateStates.updateAvailable.action(), size: 'sm', renderIcon: UpdateNow,
|
|
123
|
+
component = (_jsx(Button, { onClick: () => props.updateStates.updateAvailable.action(), size: 'sm', renderIcon: UpdateNow, children: props.updateStates.updateAvailable.label }));
|
|
123
124
|
break;
|
|
124
125
|
case 'update-available-no-permissions':
|
|
125
126
|
component = (_jsxs("div", { style: {
|
|
@@ -153,14 +154,6 @@ export const ClusterDetailsGenerationUpdate = (props) => {
|
|
|
153
154
|
}, children: [_jsx(Information, {}), _jsx("p", { style: { wordBreak: 'break-word', overflowWrap: 'break-word' }, children: resolvedNoUpdateLatestLabel })] }));
|
|
154
155
|
break;
|
|
155
156
|
}
|
|
156
|
-
case 'no-update-refresh':
|
|
157
|
-
component = (_jsxs("div", { style: {
|
|
158
|
-
display: 'grid',
|
|
159
|
-
gridTemplateColumns: '16px auto 1fr',
|
|
160
|
-
gap: '0.5rem',
|
|
161
|
-
alignItems: 'start',
|
|
162
|
-
}, children: [_jsx(Information, {}), _jsx("p", { style: { wordBreak: 'break-word', overflowWrap: 'break-word' }, children: props.updateStates.noUpdateRefresh.label }), _jsx("div", { children: _jsx(IconButton, { label: 'Refresh', onClick: () => props.updateStates.noUpdateRefresh.action(), kind: 'ghost', style: { top: '-0.2rem' }, size: 'xs', children: _jsx(Renew, {}) }) })] }));
|
|
163
|
-
break;
|
|
164
157
|
case 'creating':
|
|
165
158
|
case 'updating':
|
|
166
159
|
component = _jsx(_Fragment, {});
|