@camunda/ccma-saas-frontend 0.0.34 → 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-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-create-cluster/c4-create-cluster.js +34 -7
- 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 +3 -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 +5 -2
- package/lib/esm/components/c4-job-dashboard-details-page/c4-job-dashboard-details-page.types.d.ts +1 -1
- package/lib/esm/components/c4-job-dashboard-details-page/elements/c4-job-dashboard-piechart.js +2 -2
- package/lib/esm/components/c4-job-dashboard-details-page/elements/c4-job-dashboard-time-chart.js +6 -1
- package/lib/esm/components/c4-job-dashboard-overview-page/c4-job-dashboard-overview.js +4 -2
- package/lib/esm/components/c4-job-dashboard-overview-page/c4-job-dashboard-overview.types.d.ts +1 -1
- package/lib/esm/components/c4-theme-switcher/c4-theme-switcher.js +25 -2
- 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/pages/createcluster.json +3 -1
- package/lib/esm/index.d.ts +3 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/widgets/cluster-client-details/c4-cluster-client-details-app.js +2 -1
- 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 +47 -31
- package/lib/esm/widgets/cluster-details/c4-cluster-details-app.permissions.spec.js +34 -1
- package/lib/esm/widgets/cluster-details/c4-cluster-details-app.types.d.ts +68 -37
- 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/clusters/c4-clusters-page.js +5 -3
- package/lib/esm/widgets/clusters/c4-clusters-page.spec.js +37 -2
- package/lib/esm/widgets/clusters/c4-clusters-page.types.d.ts +1 -1
- package/lib/esm/widgets/create-cluster/c4-create-cluster-page.js +23 -15
- package/lib/esm/widgets/create-cluster/c4-create-cluster-page.types.d.ts +1 -1
- package/lib/esm/widgets/dashboard/c4-dashboard-app.js +8 -7
- package/lib/esm/widgets/dashboard/c4-dashboard-app.types.d.ts +9 -8
- package/lib/esm/widgets/group-details/c4-group-details-page.js +2 -3
- package/lib/esm/widgets/group-details/c4-group-details-page.types.d.ts +1 -1
- package/lib/esm/widgets/management/c4-management-app.js +90 -66
- package/lib/esm/widgets/management/c4-management-app.types.d.ts +16 -15
- package/lib/esm/widgets/management/tabs/c4-management-usage-tab.js +3 -4
- package/lib/esm/widgets/user-details/c4-user-details-page.js +2 -3
- package/lib/esm/widgets/user-details/c4-user-details-page.types.d.ts +1 -1
- package/package.json +2 -2
|
@@ -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
|
+
});
|
|
@@ -7,7 +7,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
7
7
|
import { C3ClusterTag, } from '@camunda/camunda-composite-components';
|
|
8
8
|
import { ClusterPlanTypeCategory, checkVersion, VersionCheckOperator, } from '@camunda/ccma-shared-types';
|
|
9
9
|
import { Button, Checkbox, Column, ContentSwitcher, FormLabel, Grid, InlineLoading, InlineNotification, Link, RadioButton, RadioButtonGroup, RadioTile, SkeletonText, Stack, Switch, Tag, TextArea, TextInput, Tile, } from '@carbon/react';
|
|
10
|
-
import { Code, DataBase } from '@carbon/react/icons/index.esm.js';
|
|
10
|
+
import { ChevronDown, ChevronUp, Code, DataBase } from '@carbon/react/icons/index.esm.js';
|
|
11
11
|
import { useRef, useState } from 'react';
|
|
12
12
|
import styled from 'styled-components';
|
|
13
13
|
import { C4ClusterTagSelector } from '../c4-cluster-tag-selector/c4-cluster-tag-selector.js';
|
|
@@ -87,6 +87,7 @@ export const C4CreateCluster = ({ loading, cta, formElements, autoUpdate, taskli
|
|
|
87
87
|
const defaultClusterPlanType = formElements.clusterPlanType.options.find((option) => option.default === true && option.disabled === false);
|
|
88
88
|
const [clusterPlanType, setClusterPlanType] = useState(defaultClusterPlanType ? defaultClusterPlanType?.uuid : '');
|
|
89
89
|
const [selectedTag, setSelectedTag] = useState('dev');
|
|
90
|
+
const [showOlderGenerations, setShowOlderGenerations] = useState(false);
|
|
90
91
|
const currentClusterPlanType = (clusterPlanType || defaultClusterPlanType?.uuid) ?? '';
|
|
91
92
|
const setClusterPlanTypeWithEffects = (clusterPlanTypeUuid) => {
|
|
92
93
|
updateNumberOfAllocatedHwPackages(1);
|
|
@@ -402,6 +403,37 @@ export const C4CreateCluster = ({ loading, cta, formElements, autoUpdate, taskli
|
|
|
402
403
|
setAuthorizationEnabled(selection === 'true');
|
|
403
404
|
}, children: [_jsx(RadioButton, { id: 'authorization-enabled', labelText: 'Enabled', value: 'true' }), _jsx(RadioButton, { id: 'authorization-disabled', labelText: 'Disabled', value: 'false' })] }, authorizationEnabled ? 'true' : 'false'), _jsxs("div", { children: [_jsx("p", { children: "When enabled, authorization-based access control is enforced." }), _jsxs("p", { children: ["When disabled, all users and clients will have full access to the cluster.", ' ', _jsx("a", { href: authorizationToggle.authorizationDocs, target: '_blank', rel: 'noopener', children: "Learn more" })] })] }), !authorizationEnabled && (_jsx(InlineNotification, { lowContrast: true, kind: ['stage', 'prod'].includes(selectedTag) ? 'warning' : 'info', hideCloseButton: true, title: 'Authorizations disabled', children: _jsx("p", { children: "All authenticated users & clients will have full access to the cluster." }) }))] }) }) })] }));
|
|
404
405
|
};
|
|
406
|
+
const renderGenerationRadioButtons = (generations) => {
|
|
407
|
+
return (_jsx(RadioButtonGroupWithGrid, { children: generations.map((generation) => (_jsx(Column, { sm: 4, md: 4, lg: 3, style: {
|
|
408
|
+
justifySelf: 'start',
|
|
409
|
+
marginBottom: '0.5rem',
|
|
410
|
+
}, children: _jsx(RadioButton, { id: generation.uuid, value: generation.uuid, labelText: generation.title, checked: selectedGeneration === generation.uuid, onChange: (value) => {
|
|
411
|
+
updateSelectedGeneration(value);
|
|
412
|
+
}, disabled: isSubmitting() || noAvailableSlots }, generation.uuid) }, generation.uuid))) }));
|
|
413
|
+
};
|
|
414
|
+
const renderGenerationSection = () => {
|
|
415
|
+
const allGenerations = getSelectedChannel()?.generations ?? [];
|
|
416
|
+
const existingClusterGenerations = allGenerations.filter((g) => g.classification === 'existingCluster');
|
|
417
|
+
const channelGenerations = allGenerations.filter((g) => g.classification !== 'existingCluster');
|
|
418
|
+
const hasOlderGenerations = existingClusterGenerations.length > 0;
|
|
419
|
+
return (_jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsxs(Stack, { gap: 2, children: [_jsx(FormLabel, { children: "Generation" }), renderGenerationRadioButtons(hasOlderGenerations ? channelGenerations : allGenerations), hasOlderGenerations && (_jsxs("div", { style: {
|
|
420
|
+
marginTop: 'var(--cds-spacing-03)',
|
|
421
|
+
}, children: [_jsx(Button, { kind: 'ghost', size: 'sm', type: 'button', onClick: () => {
|
|
422
|
+
setShowOlderGenerations((prev) => {
|
|
423
|
+
if (prev &&
|
|
424
|
+
existingClusterGenerations.some((g) => g.uuid === selectedGeneration)) {
|
|
425
|
+
return prev;
|
|
426
|
+
}
|
|
427
|
+
return !prev;
|
|
428
|
+
});
|
|
429
|
+
}, renderIcon: showOlderGenerations ? ChevronUp : ChevronDown, "aria-expanded": showOlderGenerations, "aria-controls": 'older-generations-panel', children: formElements.generation.olderGenerationsLabel ??
|
|
430
|
+
'View older generations' }), showOlderGenerations && (_jsxs("div", { id: 'older-generations-panel', style: {
|
|
431
|
+
marginTop: 'var(--cds-spacing-03)',
|
|
432
|
+
}, children: [renderGenerationRadioButtons(existingClusterGenerations), _jsx("p", { style: {
|
|
433
|
+
color: 'var(--cds-text-helper)',
|
|
434
|
+
}, children: formElements.generation.olderGenerationsHelperText ??
|
|
435
|
+
'These are older generations that are used in your organization.' })] }))] }))] }) }) }));
|
|
436
|
+
};
|
|
405
437
|
const renderContent = () => {
|
|
406
438
|
if (loading) {
|
|
407
439
|
return (_jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx(SkeletonText, {}) }) }));
|
|
@@ -481,12 +513,7 @@ export const C4CreateCluster = ({ loading, cta, formElements, autoUpdate, taskli
|
|
|
481
513
|
: enableMap.prod }) }) }), _jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx("p", { children: formElements.stageLabel.textBelow }) }) })] }), _jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx(C4Divider, {}) }) }), _jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsxs(Stack, { gap: 2, children: [_jsx(FormElementTitle, { title: formElements.generation.title }), _jsx("div", { style: { overflowX: 'auto', marginBottom: '0.5rem' }, children: _jsx(ContentSwitcher, { size: 'md', style: {
|
|
482
514
|
height: '100%',
|
|
483
515
|
width: `${7 * formElements.generation.channels.length}rem`,
|
|
484
|
-
}, onChange: (data) => updateSelectedChannel(String(data.name ?? '')), selectedIndex: defaultChannelIndex, children: formElements.generation.channels.map((channel) => (_jsx(Switch, { name: channel.uuid, disabled: noAvailableSlots, children: channel.title }, channel.uuid))) }) }), getSelectedChannel() && (_jsxs(Stack, { gap: 4, children: [_jsx(Grid, { children: _jsx(Column, { span: 7, children: _jsx("p", { children: getSelectedChannel()?.description }) }) }), _jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsxs(Stack, { gap: 2, children: [_jsx(
|
|
485
|
-
justifySelf: 'start',
|
|
486
|
-
marginBottom: '0.5rem',
|
|
487
|
-
}, children: _jsx(RadioButton, { id: generation.uuid, value: generation.uuid, labelText: generation.title, checked: selectedGeneration === generation.uuid, onChange: (value) => {
|
|
488
|
-
updateSelectedGeneration(value);
|
|
489
|
-
}, disabled: isSubmitting() || noAvailableSlots }, generation.uuid) }, generation.uuid))) })] }) }) })] }))] }) }) }), authorizationToggle?.enabled && renderAuthorizationRadio(), tasklistModeToggle?.enabled && renderTasklistV2Content(), autoUpdate?.enabled && (_jsxs(_Fragment, { children: [_jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx(C4Divider, {}) }) }), _jsxs(Stack, { gap: 2, children: [_jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx(FormElementTitle, { title: formElements.autoUpdate?.title ?? '' }) }) }), autoUpdateEnabled && (_jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx(Checkbox, { id: 'autoupdate', labelText: formElements.autoUpdate?.label ?? '', checked: autoUpdateChecked, onChange: (event) => {
|
|
516
|
+
}, onChange: (data) => updateSelectedChannel(String(data.name ?? '')), selectedIndex: defaultChannelIndex, children: formElements.generation.channels.map((channel) => (_jsx(Switch, { name: channel.uuid, disabled: noAvailableSlots, children: channel.title }, channel.uuid))) }) }), getSelectedChannel() && (_jsxs(Stack, { gap: 4, children: [_jsx(Grid, { children: _jsx(Column, { span: 7, children: _jsx("p", { children: getSelectedChannel()?.description }) }) }), renderGenerationSection()] }))] }) }) }), authorizationToggle?.enabled && renderAuthorizationRadio(), tasklistModeToggle?.enabled && renderTasklistV2Content(), autoUpdate?.enabled && (_jsxs(_Fragment, { children: [_jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx(C4Divider, {}) }) }), _jsxs(Stack, { gap: 2, children: [_jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx(FormElementTitle, { title: formElements.autoUpdate?.title ?? '' }) }) }), autoUpdateEnabled && (_jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx(Checkbox, { id: 'autoupdate', labelText: formElements.autoUpdate?.label ?? '', checked: autoUpdateChecked, onChange: (event) => {
|
|
490
517
|
setAutoUpdateChecked(event.target.checked);
|
|
491
518
|
}, disabled: isSubmitting() || !autoUpdateEnabled || noAvailableSlots }, 'autoupdate') }) })), _jsx(Grid, { children: _jsx(Column, { span: 12, children: _jsx("p", { children: autoUpdateEnabled
|
|
492
519
|
? formElements.autoUpdate?.description
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,187 @@
|
|
|
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 userEvent from '@testing-library/user-event';
|
|
9
|
+
import { C4CreateCluster } from './c4-create-cluster.js';
|
|
10
|
+
function buildChannelsWithClassification() {
|
|
11
|
+
return [
|
|
12
|
+
{
|
|
13
|
+
title: 'Stable',
|
|
14
|
+
description: 'Stable channel',
|
|
15
|
+
uuid: 'stable',
|
|
16
|
+
default: true,
|
|
17
|
+
generations: [
|
|
18
|
+
{
|
|
19
|
+
title: 'Camunda 8.8+gen18',
|
|
20
|
+
uuid: 'gen-8.8-18',
|
|
21
|
+
default: true,
|
|
22
|
+
classification: 'channel',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
title: 'Camunda 8.7+gen24',
|
|
26
|
+
uuid: 'gen-8.7-24',
|
|
27
|
+
default: false,
|
|
28
|
+
classification: 'channel',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: 'Camunda 8.4+gen15',
|
|
32
|
+
uuid: 'gen-8.4-15',
|
|
33
|
+
default: false,
|
|
34
|
+
classification: 'existingCluster',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
title: 'Camunda 8.3+gen10',
|
|
38
|
+
uuid: 'gen-8.3-10',
|
|
39
|
+
default: false,
|
|
40
|
+
classification: 'existingCluster',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
function buildChannelsWithoutClassification() {
|
|
47
|
+
return [
|
|
48
|
+
{
|
|
49
|
+
title: 'Stable',
|
|
50
|
+
description: 'Stable channel',
|
|
51
|
+
uuid: 'stable',
|
|
52
|
+
default: true,
|
|
53
|
+
generations: [
|
|
54
|
+
{
|
|
55
|
+
title: 'Camunda 8.8+gen18',
|
|
56
|
+
uuid: 'gen-8.8-18',
|
|
57
|
+
default: true,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
title: 'Camunda 8.7+gen24',
|
|
61
|
+
uuid: 'gen-8.7-24',
|
|
62
|
+
default: false,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
function buildProps(channels) {
|
|
69
|
+
return {
|
|
70
|
+
loading: false,
|
|
71
|
+
banner: {
|
|
72
|
+
noSlotsLeft: {
|
|
73
|
+
title: 'No slots',
|
|
74
|
+
description: 'No slots available',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
cta: {
|
|
78
|
+
label: 'Create cluster',
|
|
79
|
+
states: {
|
|
80
|
+
submitting: 'Creating...',
|
|
81
|
+
success: 'Created',
|
|
82
|
+
error: 'Error',
|
|
83
|
+
},
|
|
84
|
+
create: vi.fn().mockResolvedValue({ success: true, clusterId: 'c-1' }),
|
|
85
|
+
postCreate: vi.fn(),
|
|
86
|
+
},
|
|
87
|
+
formElements: {
|
|
88
|
+
name: {
|
|
89
|
+
title: 'Cluster name',
|
|
90
|
+
placeholder: 'Name',
|
|
91
|
+
validation: () => ({ isValid: true, message: '' }),
|
|
92
|
+
},
|
|
93
|
+
clusterPlanType: {
|
|
94
|
+
title: 'Cluster type',
|
|
95
|
+
options: [
|
|
96
|
+
{
|
|
97
|
+
title: 'Production',
|
|
98
|
+
type: 'prod',
|
|
99
|
+
uuid: 'prod',
|
|
100
|
+
description: 'Production cluster',
|
|
101
|
+
default: true,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
region: {
|
|
106
|
+
title: 'Region',
|
|
107
|
+
backupRegionTitle: 'Backup',
|
|
108
|
+
description: 'Select region',
|
|
109
|
+
backupDescription: 'Select backup',
|
|
110
|
+
dualRegionBackups: false,
|
|
111
|
+
options: [
|
|
112
|
+
{
|
|
113
|
+
title: 'EU West',
|
|
114
|
+
uuid: 'eu-west',
|
|
115
|
+
provider: 'aws',
|
|
116
|
+
default: true,
|
|
117
|
+
backups: [],
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
generation: {
|
|
122
|
+
title: 'Channel',
|
|
123
|
+
channels,
|
|
124
|
+
olderGenerationsLabel: 'View older generations',
|
|
125
|
+
olderGenerationsHelperText: 'These are older generations that are used in your organization.',
|
|
126
|
+
},
|
|
127
|
+
stageLabel: {
|
|
128
|
+
title: 'Tag',
|
|
129
|
+
textBelow: 'Assign a tag',
|
|
130
|
+
boxes: {
|
|
131
|
+
dev: { text: 'dev' },
|
|
132
|
+
test: { text: 'test' },
|
|
133
|
+
stage: { text: 'stage' },
|
|
134
|
+
prod: { text: 'prod' },
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
describe('C4CreateCluster older generations toggle', () => {
|
|
141
|
+
it('hides existingCluster generations by default', () => {
|
|
142
|
+
render(_jsx(C4CreateCluster, { ...buildProps(buildChannelsWithClassification()) }));
|
|
143
|
+
expect(screen.getByLabelText('Camunda 8.8+gen18')).toBeInTheDocument();
|
|
144
|
+
expect(screen.getByLabelText('Camunda 8.7+gen24')).toBeInTheDocument();
|
|
145
|
+
expect(screen.queryByLabelText('Camunda 8.4+gen15')).not.toBeInTheDocument();
|
|
146
|
+
expect(screen.queryByLabelText('Camunda 8.3+gen10')).not.toBeInTheDocument();
|
|
147
|
+
expect(screen.getByRole('button', { name: /view older generations/i })).toBeInTheDocument();
|
|
148
|
+
});
|
|
149
|
+
it('shows existingCluster generations when toggle is clicked', async () => {
|
|
150
|
+
render(_jsx(C4CreateCluster, { ...buildProps(buildChannelsWithClassification()) }));
|
|
151
|
+
const toggle = screen.getByRole('button', {
|
|
152
|
+
name: /view older generations/i,
|
|
153
|
+
});
|
|
154
|
+
await userEvent.click(toggle);
|
|
155
|
+
expect(screen.getByLabelText('Camunda 8.4+gen15')).toBeInTheDocument();
|
|
156
|
+
expect(screen.getByLabelText('Camunda 8.3+gen10')).toBeInTheDocument();
|
|
157
|
+
expect(screen.getByText('These are older generations that are used in your organization.')).toBeInTheDocument();
|
|
158
|
+
});
|
|
159
|
+
it('prevents collapsing when an older generation is selected', async () => {
|
|
160
|
+
render(_jsx(C4CreateCluster, { ...buildProps(buildChannelsWithClassification()) }));
|
|
161
|
+
const toggle = screen.getByRole('button', {
|
|
162
|
+
name: /view older generations/i,
|
|
163
|
+
});
|
|
164
|
+
await userEvent.click(toggle);
|
|
165
|
+
const olderRadio = screen.getByLabelText('Camunda 8.4+gen15');
|
|
166
|
+
await userEvent.click(olderRadio);
|
|
167
|
+
await userEvent.click(toggle);
|
|
168
|
+
expect(screen.getByLabelText('Camunda 8.4+gen15')).toBeInTheDocument();
|
|
169
|
+
expect(screen.getByLabelText('Camunda 8.3+gen10')).toBeInTheDocument();
|
|
170
|
+
});
|
|
171
|
+
it('allows collapsing when a channel generation is selected', async () => {
|
|
172
|
+
render(_jsx(C4CreateCluster, { ...buildProps(buildChannelsWithClassification()) }));
|
|
173
|
+
const toggle = screen.getByRole('button', {
|
|
174
|
+
name: /view older generations/i,
|
|
175
|
+
});
|
|
176
|
+
await userEvent.click(toggle);
|
|
177
|
+
expect(screen.getByLabelText('Camunda 8.4+gen15')).toBeInTheDocument();
|
|
178
|
+
await userEvent.click(toggle);
|
|
179
|
+
expect(screen.queryByLabelText('Camunda 8.4+gen15')).not.toBeInTheDocument();
|
|
180
|
+
});
|
|
181
|
+
it('does not render the toggle when no existingCluster generations exist', () => {
|
|
182
|
+
render(_jsx(C4CreateCluster, { ...buildProps(buildChannelsWithoutClassification()) }));
|
|
183
|
+
expect(screen.queryByRole('button', { name: /view older generations/i })).not.toBeInTheDocument();
|
|
184
|
+
expect(screen.getByLabelText('Camunda 8.8+gen18')).toBeInTheDocument();
|
|
185
|
+
expect(screen.getByLabelText('Camunda 8.7+gen24')).toBeInTheDocument();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
@@ -61,6 +61,7 @@ export interface C4CreateClusterChannelWithGenerations {
|
|
|
61
61
|
default: boolean;
|
|
62
62
|
uuid: string;
|
|
63
63
|
version?: string;
|
|
64
|
+
classification?: 'channel' | 'existingCluster';
|
|
64
65
|
}>;
|
|
65
66
|
}
|
|
66
67
|
export interface C4CreateClusterProps {
|
|
@@ -143,6 +144,8 @@ export interface C4CreateClusterProps {
|
|
|
143
144
|
generation: {
|
|
144
145
|
title: string;
|
|
145
146
|
channels: C4CreateClusterChannelWithGenerations[];
|
|
147
|
+
olderGenerationsLabel?: string;
|
|
148
|
+
olderGenerationsHelperText?: string;
|
|
146
149
|
};
|
|
147
150
|
autoUpdate?: {
|
|
148
151
|
title: string;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type JSX } from 'react';
|
|
2
|
+
import type { C4DeleteOrganizationModalProps } from './c4-delete-organization-modal.types';
|
|
3
|
+
export declare const C4DeleteOrganizationModal: ({ t, open, loading, error, organizationName, onRequestClose, onRequestSubmit, preventCloseOnClickOutside, }: C4DeleteOrganizationModalProps) => JSX.Element;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } 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 { InlineNotification, Modal, Stack, TextInput } from '@carbon/react';
|
|
8
|
+
import { useEffect, useState } from 'react';
|
|
9
|
+
function safeTranslate(t, key, fallback, options) {
|
|
10
|
+
try {
|
|
11
|
+
const translated = t?.(key, options);
|
|
12
|
+
if (!translated || translated === key) {
|
|
13
|
+
return fallback;
|
|
14
|
+
}
|
|
15
|
+
if (key.includes(':')) {
|
|
16
|
+
const withoutNamespace = key.split(':').slice(1).join(':');
|
|
17
|
+
if (translated === withoutNamespace) {
|
|
18
|
+
return fallback;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return translated;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return fallback;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export const C4DeleteOrganizationModal = ({ t, open, loading, error, organizationName, onRequestClose, onRequestSubmit, preventCloseOnClickOutside, }) => {
|
|
28
|
+
const [confirmText, setConfirmText] = useState('');
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!open) {
|
|
31
|
+
setConfirmText('');
|
|
32
|
+
}
|
|
33
|
+
}, [open]);
|
|
34
|
+
const modalHeading = safeTranslate(t, 'orgmanagement:tabs.settings.orgmanagement.deleteOrganization', 'Delete organization');
|
|
35
|
+
const primaryButtonText = safeTranslate(t, 'orgmanagement:tabs.overview.actions.deleteOrg', 'Delete');
|
|
36
|
+
const secondaryButtonText = safeTranslate(t, 'common:cancel', 'Cancel');
|
|
37
|
+
const message = safeTranslate(t, 'orgmanagement:tabs.settings.orgmanagement.deleteConfirmation', `Are you sure you want to delete "${organizationName}"? The organization and its clusters, Web Modeler files, and other assets will be deleted. This action cannot be undone.`, { organizationName });
|
|
38
|
+
const confirmLabel = safeTranslate(t, 'orgmanagement:tabs.settings.orgmanagement.deleteConfirmLabel', 'Type the word DELETE to confirm');
|
|
39
|
+
const errorMessage = safeTranslate(t, 'orgmanagement:tabs.settings.orgmanagement.deleteError', 'Failed to delete organization. Please try again.');
|
|
40
|
+
return (_jsx(Modal, { modalHeading: modalHeading, open: open, onRequestClose: onRequestClose, onRequestSubmit: onRequestSubmit, primaryButtonText: primaryButtonText, primaryButtonDisabled: loading || confirmText.trim() !== 'DELETE', secondaryButtonText: secondaryButtonText, size: 'sm', danger: true, id: 'delete-organization-modal', preventCloseOnClickOutside: preventCloseOnClickOutside ?? true, children: _jsxs(Stack, { gap: 6, children: [error && (_jsx(InlineNotification, { kind: 'error', title: errorMessage, hideCloseButton: true })), _jsx("p", { children: message }), _jsx(TextInput, { id: 'c4-delete-organization-confirmation', labelText: confirmLabel, value: confirmText, onChange: (e) => setConfirmText(e.target.value), disabled: loading })] }) }));
|
|
41
|
+
};
|
package/lib/esm/components/c4-delete-organization-modal/c4-delete-organization-modal.types.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface C4DeleteOrganizationModalProps {
|
|
2
|
+
t?: (key: string, options?: Record<string, unknown>) => string;
|
|
3
|
+
open: boolean;
|
|
4
|
+
loading: boolean;
|
|
5
|
+
error?: boolean;
|
|
6
|
+
organizationName: string;
|
|
7
|
+
onRequestClose: () => void;
|
|
8
|
+
onRequestSubmit: () => void | Promise<void>;
|
|
9
|
+
preventCloseOnClickOutside?: boolean;
|
|
10
|
+
}
|
|
@@ -5,4 +5,5 @@ export interface ColorScale {
|
|
|
5
5
|
Failed: string;
|
|
6
6
|
}
|
|
7
7
|
export declare const CHART_HEIGHT = "20vh";
|
|
8
|
+
export declare const PIE_CHART_MAX_WIDTH_PX = 400;
|
|
8
9
|
export declare const C4JobDashboardDetailsPage: ({ jobType, config, isLoadingConfig, lastUpdatedAt, errorData, timeSeries, workerData, jobData, onTimeRangeChange, breadcrumb, translations, docsUrls, trackErrorClick, }: C4JobDashboardDetailsPageProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,6 +6,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
6
6
|
*/
|
|
7
7
|
import { InlineNotification, Stack, Tile } from '@carbon/react';
|
|
8
8
|
import styled from 'styled-components';
|
|
9
|
+
import { getC4JobDashboardDocsUrls } from '../../externalUrls.const.js';
|
|
9
10
|
import { C4Breadcrumb } from '../c4-breadcrumb/c4-breadcrumb.js';
|
|
10
11
|
import { C4JobDashboardErrorHandler } from '../c4-job-dashboard-shared/c4-job-dashboard-error-handler.js';
|
|
11
12
|
import C4JobDashboardTimeRangeDropdown from '../c4-job-dashboard-shared/c4-job-dashboard-time-range-dropdown.js';
|
|
@@ -41,7 +42,9 @@ const PieChartWrapper = styled(TileWithShadow) `
|
|
|
41
42
|
}
|
|
42
43
|
`;
|
|
43
44
|
export const CHART_HEIGHT = '20vh';
|
|
45
|
+
export const PIE_CHART_MAX_WIDTH_PX = 400;
|
|
44
46
|
export const C4JobDashboardDetailsPage = ({ jobType, config, isLoadingConfig, lastUpdatedAt, errorData, timeSeries, workerData, jobData, onTimeRangeChange, breadcrumb, translations, docsUrls, trackErrorClick, }) => {
|
|
47
|
+
const resolvedDocsUrls = getC4JobDashboardDocsUrls(docsUrls);
|
|
45
48
|
const colorScale = {
|
|
46
49
|
Created: '#002D9C',
|
|
47
50
|
Completed: '#009D9A',
|
|
@@ -50,7 +53,7 @@ export const C4JobDashboardDetailsPage = ({ jobType, config, isLoadingConfig, la
|
|
|
50
53
|
const featureIsDisabled = !isLoadingConfig && config && !config.enabled;
|
|
51
54
|
if (featureIsDisabled) {
|
|
52
55
|
const error = { status: 403, details: 'Feature is disabled', message: '' };
|
|
53
|
-
return (_jsx(C4JobDashboardErrorHandler, { itemsLength: 0, showIcons: true, translations: translations.errorHandler, error: error, docsUrls:
|
|
56
|
+
return (_jsx(C4JobDashboardErrorHandler, { itemsLength: 0, showIcons: true, translations: translations.errorHandler, error: error, docsUrls: resolvedDocsUrls }));
|
|
54
57
|
}
|
|
55
|
-
return (_jsxs(Stack, { gap: 4, children: [_jsx(C4Breadcrumb, { title: translations.title, elements: breadcrumb.elements }), _jsxs("p", { children: [translations.jobTypeLabel, " ", _jsx("strong", { children: jobType })] }), _jsx(C4TimestampInformation, { description: translations.lastUpdated, lastUpdatedAt: lastUpdatedAt }), _jsx(C4JobDashboardTimeRangeDropdown, { onChange: onTimeRangeChange, exportInterval: config?.exportInterval, disabled: isLoadingConfig, translations: translations.dropdown }), jobData.isIncomplete && (_jsx(InlineNotification, { style: { maxWidth: '100%' }, lowContrast: true, kind: 'warning', title: translations.dataLimitWarning.title, subtitle: translations.dataLimitWarning.description })), _jsx(ChartContainer, { children: _jsxs(ChartGrid, { children: [_jsx(TimeChartWrapper, { children: _jsx(C4JobDashboardTimeChart, { timeSeries: timeSeries.items, colorScale: colorScale, isLoading: timeSeries.isLoading, translations: translations, error: timeSeries.error, docsUrls:
|
|
58
|
+
return (_jsxs(Stack, { gap: 4, children: [_jsx(C4Breadcrumb, { title: translations.title, elements: breadcrumb.elements }), _jsxs("p", { children: [translations.jobTypeLabel, " ", _jsx("strong", { children: jobType })] }), _jsx(C4TimestampInformation, { description: translations.lastUpdated, lastUpdatedAt: lastUpdatedAt }), _jsx(C4JobDashboardTimeRangeDropdown, { onChange: onTimeRangeChange, exportInterval: config?.exportInterval, disabled: isLoadingConfig, translations: translations.dropdown }), jobData.isIncomplete && (_jsx(InlineNotification, { style: { maxWidth: '100%' }, lowContrast: true, kind: 'warning', title: translations.dataLimitWarning.title, subtitle: translations.dataLimitWarning.description })), _jsx(ChartContainer, { children: _jsxs(ChartGrid, { children: [_jsx(TimeChartWrapper, { children: _jsx(C4JobDashboardTimeChart, { timeSeries: timeSeries.items, colorScale: colorScale, isLoading: timeSeries.isLoading, translations: translations, error: timeSeries.error, docsUrls: resolvedDocsUrls }) }), _jsx(PieChartWrapper, { children: _jsx(C4JobDashboardPieChart, { jobData: jobData.data, colorScale: colorScale, isLoading: jobData.isLoading, translations: translations, error: jobData.error, docsUrls: resolvedDocsUrls }) })] }) }), _jsx(TileWithShadow, { children: _jsx(C4JobDashboardWorkerTable, { workerData: workerData.items, isLoading: workerData.isLoading, translations: translations, error: workerData.error, docsUrls: resolvedDocsUrls }) }), _jsx(TileWithShadow, { children: _jsx(C4JobDashboardErrorTable, { errors: errorData.items, operateBaseUrl: errorData.operateBaseUrl, isLoading: errorData.isLoading, translations: translations, error: errorData.error, docsUrls: resolvedDocsUrls, trackErrorClick: trackErrorClick }) })] }));
|
|
56
59
|
};
|
package/lib/esm/components/c4-job-dashboard-details-page/elements/c4-job-dashboard-piechart.js
CHANGED
|
@@ -6,7 +6,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
6
6
|
*/
|
|
7
7
|
import { DonutChart } from '@carbon/charts-react';
|
|
8
8
|
import { C4JobDashboardErrorHandler } from '../../c4-job-dashboard-shared/c4-job-dashboard-error-handler.js';
|
|
9
|
-
import { CHART_HEIGHT } from '../c4-job-dashboard-details-page.js';
|
|
9
|
+
import { CHART_HEIGHT, PIE_CHART_MAX_WIDTH_PX, } from '../c4-job-dashboard-details-page.js';
|
|
10
10
|
import C4JobDashboardChartHeading from './c4-job-dashboard-chart-heading.js';
|
|
11
11
|
function C4JobDashboardPieChart({ jobData, error, colorScale, isLoading, translations, docsUrls, }) {
|
|
12
12
|
const completedCount = jobData?.completed?.count ?? 0;
|
|
@@ -70,6 +70,6 @@ function C4JobDashboardPieChart({ jobData, error, colorScale, isLoading, transla
|
|
|
70
70
|
const noData = (jobData?.created.count === jobData?.failed.count &&
|
|
71
71
|
jobData?.completed.count === 0) ||
|
|
72
72
|
!jobData;
|
|
73
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { style: { marginBottom: 25 }, children: _jsx(C4JobDashboardChartHeading, { title: translations.charts.createdVsCompleted.title, tooltipLabel: translations.charts.createdVsCompleted.tooltip }) }), (!jobData || noData || error) && !isLoading ? (_jsx(C4JobDashboardErrorHandler, { itemsLength: noData ? 0 : 1, showIcons: false, translations: translations.errorHandler, error: error, docsUrls: docsUrls })) : (_jsx("div", { children: _jsx(DonutChart, { data: pieData, options: pieOptions }) }))] }));
|
|
73
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { style: { marginBottom: 25 }, children: _jsx(C4JobDashboardChartHeading, { title: translations.charts.createdVsCompleted.title, tooltipLabel: translations.charts.createdVsCompleted.tooltip }) }), (!jobData || noData || error) && !isLoading ? (_jsx(C4JobDashboardErrorHandler, { itemsLength: noData ? 0 : 1, showIcons: false, translations: translations.errorHandler, error: error, docsUrls: docsUrls })) : (_jsx("div", { style: { maxWidth: PIE_CHART_MAX_WIDTH_PX, margin: '0 auto' }, children: _jsx(DonutChart, { data: pieData, options: pieOptions }) }))] }));
|
|
74
74
|
}
|
|
75
75
|
export default C4JobDashboardPieChart;
|
package/lib/esm/components/c4-job-dashboard-details-page/elements/c4-job-dashboard-time-chart.js
CHANGED
|
@@ -44,6 +44,11 @@ function C4JobDashboardTimeChart({ timeSeries, isLoading, colorScale, translatio
|
|
|
44
44
|
const lastTimeDataPoint = Math.max(...timeSeries.map((t) => new Date(t.time).getTime()));
|
|
45
45
|
const coversMultipleDays = new Date(firstTimeDataPoint).toDateString() !==
|
|
46
46
|
new Date(lastTimeDataPoint).toDateString();
|
|
47
|
+
const formattedColorScale = {
|
|
48
|
+
[translations.charts.legend.completed]: colorScale.Completed,
|
|
49
|
+
[translations.charts.legend.failed]: colorScale.Failed,
|
|
50
|
+
[translations.charts.legend.created]: colorScale.Created,
|
|
51
|
+
};
|
|
47
52
|
const areaOptions = {
|
|
48
53
|
resizable: true,
|
|
49
54
|
toolbar: {
|
|
@@ -89,7 +94,7 @@ function C4JobDashboardTimeChart({ timeSeries, isLoading, colorScale, translatio
|
|
|
89
94
|
},
|
|
90
95
|
},
|
|
91
96
|
color: {
|
|
92
|
-
scale:
|
|
97
|
+
scale: formattedColorScale,
|
|
93
98
|
},
|
|
94
99
|
};
|
|
95
100
|
return (_jsxs(Stack, { gap: 6, children: [_jsx(C4JobDashboardChartHeading, { title: translations.charts.jobWorkload.title, tooltipLabel: translations.charts.jobWorkload.tooltip }), _jsxs("strong", { children: [translations.charts.jobWorkload.subtitle, " "] }), (!timeSeries || timeSeries.length === 0 || error) && !isLoading ? (_jsx(C4JobDashboardErrorHandler, { itemsLength: timeSeries.length, showIcons: false, translations: translations.errorHandler, error: error, docsUrls: docsUrls })) : (_jsx("div", { style: { height: CHART_HEIGHT }, children: _jsx(StackedAreaChart, { data: chartData, options: areaOptions }) }))] }));
|
|
@@ -8,6 +8,7 @@ import { C3DataTable, } from '@camunda/camunda-composite-components';
|
|
|
8
8
|
import { InlineNotification, Stack } from '@carbon/react';
|
|
9
9
|
import { Launch } from '@carbon/react/icons/index.esm.js';
|
|
10
10
|
import { useEffect, useState } from 'react';
|
|
11
|
+
import { getC4JobDashboardDocsUrls } from '../../externalUrls.const.js';
|
|
11
12
|
import { C4Breadcrumb } from '../c4-breadcrumb/c4-breadcrumb.js';
|
|
12
13
|
import { C4BackgroundFetchingIndicator } from '../c4-job-dashboard-shared/c4-background-fetching-indicator.js';
|
|
13
14
|
import { C4JobDashboardErrorHandler } from '../c4-job-dashboard-shared/c4-job-dashboard-error-handler.js';
|
|
@@ -16,6 +17,7 @@ import C4JobDashboardTimeRangeDropdown from '../c4-job-dashboard-shared/c4-job-d
|
|
|
16
17
|
import C4TimestampInformation from '../c4-job-dashboard-shared/c4-timestamp-information.js';
|
|
17
18
|
import { C4LinkButton } from '../c4-link-button/c4-link-button.js';
|
|
18
19
|
export const C4JobDashboardOverviewPage = ({ error, items, isIncomplete, config, onTimeRangeChange, breadcrumb, isLoadingConfig, isLoadingTable, translations, lastUpdatedAt, docsUrls, }) => {
|
|
20
|
+
const resolvedDocsUrls = getC4JobDashboardDocsUrls(docsUrls);
|
|
19
21
|
const [rows, setRows] = useState([]);
|
|
20
22
|
useEffect(() => {
|
|
21
23
|
const originalRows = items.map((row, index) => ({
|
|
@@ -51,9 +53,9 @@ export const C4JobDashboardOverviewPage = ({ error, items, isIncomplete, config,
|
|
|
51
53
|
details: 'Feature is disabled',
|
|
52
54
|
message: '',
|
|
53
55
|
};
|
|
54
|
-
return (_jsx(C4JobDashboardErrorHandler, { itemsLength: 0, showIcons: true, translations: translations.errorHandler, error: error, docsUrls:
|
|
56
|
+
return (_jsx(C4JobDashboardErrorHandler, { itemsLength: 0, showIcons: true, translations: translations.errorHandler, error: error, docsUrls: resolvedDocsUrls }));
|
|
55
57
|
}
|
|
56
|
-
return (_jsxs(Stack, { gap: 3, children: [_jsx(C4Breadcrumb, { loading: false, elements: breadcrumb.elements, title: translations.title }), _jsxs("p", { children: [translations.description, ' ', _jsx(C4LinkButton, { onClick: () => window.open('https://docs.camunda.io/docs/components/concepts/job-workers/'), label: translations.learnMoreLabel, icon: _jsx(Launch, {}) })] }), _jsx(C4TimestampInformation, { description: translations.lastUpdated, lastUpdatedAt: lastUpdatedAt }), _jsx(C4JobDashboardTimeRangeDropdown, { onChange: onTimeRangeChange, exportInterval: config?.exportInterval, disabled: isLoadingConfig, translations: translations.dropdown }), shouldShowErrorHandler ? (_jsx(C4JobDashboardErrorHandler, { error: error, itemsLength: items.length, showIcons: true, translations: translations.errorHandler, docsUrls:
|
|
58
|
+
return (_jsxs(Stack, { gap: 3, children: [_jsx(C4Breadcrumb, { loading: false, elements: breadcrumb.elements, title: translations.title }), _jsxs("p", { children: [translations.description, ' ', _jsx(C4LinkButton, { onClick: () => window.open('https://docs.camunda.io/docs/components/concepts/job-workers/'), label: translations.learnMoreLabel, icon: _jsx(Launch, {}) })] }), _jsx(C4TimestampInformation, { description: translations.lastUpdated, lastUpdatedAt: lastUpdatedAt }), _jsx(C4JobDashboardTimeRangeDropdown, { onChange: onTimeRangeChange, exportInterval: config?.exportInterval, disabled: isLoadingConfig, translations: translations.dropdown }), shouldShowErrorHandler ? (_jsx(C4JobDashboardErrorHandler, { error: error, itemsLength: items.length, showIcons: true, translations: translations.errorHandler, docsUrls: resolvedDocsUrls })) : (_jsxs(_Fragment, { children: [isIncomplete && (_jsx(InlineNotification, { style: { maxWidth: '100%' }, lowContrast: true, kind: 'warning', title: translations.dataLimitWarning.title, subtitle: translations.dataLimitWarning.description })), _jsx(C3DataTable, { id: 'usage-history-table', data: rows, toolbar: toolbar, headers: [
|
|
57
59
|
{
|
|
58
60
|
key: 'jobType',
|
|
59
61
|
label: translations.tableHeaders.jobType,
|
|
@@ -21,6 +21,12 @@ import cyberzeeIcon from './cyberzee-removebg-preview-100.png';
|
|
|
21
21
|
const STORAGE_KEY = 'camunda-theme-mode';
|
|
22
22
|
const ACTIVATION_KEY = 'camunda-theme-switcher-enabled';
|
|
23
23
|
const ACTIVATION_EVENT = 'camunda-theme-switcher-activated';
|
|
24
|
+
/**
|
|
25
|
+
* Custom events dispatched by the AprilFoolsNotification component.
|
|
26
|
+
* Used to reposition the theme switcher when the notification is visible.
|
|
27
|
+
*/
|
|
28
|
+
const APRIL_FOOLS_SHOWN_EVENT = 'camunda-april-fools-shown';
|
|
29
|
+
const APRIL_FOOLS_HIDDEN_EVENT = 'camunda-april-fools-hidden';
|
|
24
30
|
/**
|
|
25
31
|
* Cyberzee icon component for theme toggle
|
|
26
32
|
*/
|
|
@@ -54,6 +60,7 @@ const getThemeButtonContent = (theme) => {
|
|
|
54
60
|
export const C4ThemeSwitcher = ({ position = 'bottom-right', visible = true, onThemeChange, }) => {
|
|
55
61
|
const [currentTheme, setCurrentTheme] = useState('normal');
|
|
56
62
|
const [isActivated, setIsActivated] = useState(() => localStorage.getItem(ACTIVATION_KEY) === 'true');
|
|
63
|
+
const [isAprilFoolsVisible, setIsAprilFoolsVisible] = useState(false);
|
|
57
64
|
const { resolvedTheme } = useC3Profile();
|
|
58
65
|
// Register developer-console activation function
|
|
59
66
|
useEffect(() => {
|
|
@@ -70,6 +77,17 @@ export const C4ThemeSwitcher = ({ position = 'bottom-right', visible = true, onT
|
|
|
70
77
|
window.removeEventListener(ACTIVATION_EVENT, handleActivation);
|
|
71
78
|
};
|
|
72
79
|
}, []);
|
|
80
|
+
// Listen for April Fools notification visibility to shift position left
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
const handleShown = () => setIsAprilFoolsVisible(true);
|
|
83
|
+
const handleHidden = () => setIsAprilFoolsVisible(false);
|
|
84
|
+
window.addEventListener(APRIL_FOOLS_SHOWN_EVENT, handleShown);
|
|
85
|
+
window.addEventListener(APRIL_FOOLS_HIDDEN_EVENT, handleHidden);
|
|
86
|
+
return () => {
|
|
87
|
+
window.removeEventListener(APRIL_FOOLS_SHOWN_EVENT, handleShown);
|
|
88
|
+
window.removeEventListener(APRIL_FOOLS_HIDDEN_EVENT, handleHidden);
|
|
89
|
+
};
|
|
90
|
+
}, []);
|
|
73
91
|
// Apply theme class to body
|
|
74
92
|
const applyThemeClass = useCallback((theme, carbonTheme) => {
|
|
75
93
|
// Remove all theme classes
|
|
@@ -174,9 +192,14 @@ export const C4ThemeSwitcher = ({ position = 'bottom-right', visible = true, onT
|
|
|
174
192
|
if (!visible || (!isActivated && currentTheme === 'normal')) {
|
|
175
193
|
return _jsx(_Fragment, { children: " " });
|
|
176
194
|
}
|
|
177
|
-
// Position styles
|
|
195
|
+
// Position styles. When the April Fools notification is visible in the
|
|
196
|
+
// bottom-right corner (right: 1rem, maxWidth: 28rem), shift the button
|
|
197
|
+
// further left so the two never overlap.
|
|
178
198
|
const positionStyles = {
|
|
179
|
-
'bottom-right': {
|
|
199
|
+
'bottom-right': {
|
|
200
|
+
bottom: '20px',
|
|
201
|
+
right: isAprilFoolsVisible ? 'calc(28rem + 2rem)' : '80px',
|
|
202
|
+
},
|
|
180
203
|
'bottom-left': { bottom: '20px', left: '20px' },
|
|
181
204
|
'top-right': { top: '20px', right: '20px' },
|
|
182
205
|
'top-left': { top: '20px', left: '20px' },
|