@orchestrator-ui/orchestrator-ui-components 8.9.2 → 9.0.0
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/.turbo/turbo-build.log +7 -7
- package/.turbo/turbo-lint.log +1 -1
- package/.turbo/turbo-test.log +262 -19
- package/CHANGELOG.md +28 -0
- package/dist/index.d.ts +2082 -2505
- package/dist/index.js +2045 -2190
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/WfoError/WfoError.tsx +2 -2
- package/src/components/WfoInlineNoteEdit/WfoSubscriptionDetailNoteEdit.tsx +4 -8
- package/src/components/WfoInlineNoteEdit/WfoSubscriptionNoteEdit.tsx +6 -7
- package/src/components/WfoKeyValueTable/styles.ts +24 -0
- package/src/components/WfoPageTemplate/paths.ts +0 -1
- package/src/components/WfoPydanticForm/fields/WfoLabel.tsx +5 -1
- package/src/components/WfoPydanticForm/fields/styles.ts +12 -3
- package/src/components/WfoSettingsModal/WfoInformationModal.tsx +3 -2
- package/src/components/WfoSubscriptionsList/index.ts +1 -2
- package/src/components/WfoSubscriptionsList/subscriptionListItem.ts +14 -0
- package/src/components/WfoSubscriptionsList/subscriptionListTabs.ts +1 -20
- package/src/components/WfoSummary/WfoLatestActiveSubscriptionsSummaryCard.tsx +17 -13
- package/src/components/WfoSummary/WfoLatestOutOfSyncSubscriptionSummaryCard.tsx +28 -15
- package/src/components/WfoTable/WfoAdvancedTable/WfoAdvancedTable.tsx +5 -1
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoApplyFilterButton.tsx +37 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoDebounceCountdown.tsx +58 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoFieldSelector.spec.tsx +180 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoFieldSelector.tsx +66 -51
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoFilterBuilder.tsx +33 -98
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoRangeEditor.tsx +0 -1
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoRestoreLoop.spec.tsx +2 -2
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoStructuredSearchTable.tsx +5 -7
- package/src/components/WfoTable/WfoStructuredSearchTable/WfoValueEditor.tsx +9 -13
- package/src/components/WfoTable/WfoStructuredSearchTable/styles.ts +7 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/useSearchWithDebouncedCallback.spec.tsx +147 -0
- package/src/components/WfoTable/WfoStructuredSearchTable/utils.spec.ts +60 -1
- package/src/components/WfoTable/WfoStructuredSearchTable/utils.ts +133 -1
- package/src/configuration/version.ts +1 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDebouncedCallback.ts +48 -0
- package/src/hooks/usePathAutoComplete.spec.tsx +94 -9
- package/src/hooks/usePathAutoComplete.ts +10 -15
- package/src/hooks/useSearchPagination.ts +1 -1
- package/src/messages/en-GB.json +4 -2
- package/src/messages/nl-NL.json +4 -2
- package/src/pages/index.ts +0 -1
- package/src/pages/startPage/index.ts +1 -0
- package/src/pages/startPage/mappers.ts +15 -8
- package/src/pages/startPage/queryVariables.ts +0 -29
- package/src/pages/startPage/searchPayloads.ts +22 -0
- package/src/pages/subscriptions/WfoSubscriptionsListPage.tsx +511 -39
- package/src/rtk/endpoints/index.ts +0 -1
- package/src/rtk/endpoints/search.ts +3 -0
- package/src/rtk/endpoints/subscriptionListMutation.spec.ts +80 -0
- package/src/rtk/endpoints/subscriptionListMutation.ts +71 -52
- package/src/rtk/utils.spec.ts +30 -1
- package/src/rtk/utils.ts +2 -1
- package/src/types/search.ts +1 -3
- package/src/types/types.ts +0 -2
- package/src/utils/getDefaultTableConfig.ts +1 -6
- package/src/utils/getQueryParams.ts +1 -0
- package/src/components/WfoSubscriptionsList/WfoSubscriptionsList.tsx +0 -243
- package/src/components/WfoSubscriptionsList/subscriptionResultMappers.ts +0 -49
- package/src/pages/WfoSearchPocPage.tsx +0 -575
- package/src/rtk/endpoints/subscriptionListSummary.ts +0 -66
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@ export const WfoError = () => {
|
|
|
17
17
|
const { theme } = useOrchestratorTheme();
|
|
18
18
|
return (
|
|
19
19
|
<EuiFlexGroup direction="row" alignItems="center" gutterSize="s">
|
|
20
|
-
<WfoXCircleFill color={theme.colors.danger} />
|
|
20
|
+
<WfoXCircleFill color={theme.colors.danger} width={32} height={32} />
|
|
21
21
|
<h1>{t('errorMessage')}</h1>
|
|
22
22
|
</EuiFlexGroup>
|
|
23
23
|
);
|
|
@@ -30,7 +30,7 @@ export const WfoErrorWithMessage = ({ error }: WfoErrorWithMessageProps) => {
|
|
|
30
30
|
return (
|
|
31
31
|
<>
|
|
32
32
|
<EuiFlexGroup direction="row" alignItems="center" gutterSize="s">
|
|
33
|
-
<WfoXCircleFill color={theme.colors.danger} />
|
|
33
|
+
<WfoXCircleFill color={theme.colors.danger} width={32} height={32} />
|
|
34
34
|
<EuiText color={theme.colors.textDanger}>
|
|
35
35
|
{t('errorMessage')} ({message})
|
|
36
36
|
</EuiText>
|
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
|
|
4
4
|
import { useGetSubscriptionDetailQuery } from '@/rtk';
|
|
5
5
|
import { useStartProcessMutation } from '@/rtk/endpoints/forms';
|
|
6
|
-
import {
|
|
6
|
+
import { useUpdateSubscriptionNoteOptimisticMutation } from '@/rtk/endpoints/subscriptionListMutation';
|
|
7
7
|
import { SubscriptionDetail } from '@/types';
|
|
8
8
|
import { INVISIBLE_CHARACTER } from '@/utils';
|
|
9
9
|
|
|
@@ -18,13 +18,13 @@ export const WfoSubscriptionDetailNoteEdit: FC<WfoSubscriptionDetailNoteEditProp
|
|
|
18
18
|
subscriptionId,
|
|
19
19
|
onlyShowOnHover = false,
|
|
20
20
|
}) => {
|
|
21
|
-
const { data
|
|
21
|
+
const { data } = useGetSubscriptionDetailQuery({
|
|
22
22
|
subscriptionId,
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
const selectedItem = data?.subscription ?? { note: '' };
|
|
26
26
|
const [startProcess] = useStartProcessMutation();
|
|
27
|
-
const [
|
|
27
|
+
const [updateSubscriptionNoteOptimistic] = useUpdateSubscriptionNoteOptimisticMutation();
|
|
28
28
|
|
|
29
29
|
const triggerNoteModifyWorkflow = (note: string) => {
|
|
30
30
|
const noteModifyPayload = [{ subscription_id: subscriptionId }, { note: note }];
|
|
@@ -33,11 +33,7 @@ export const WfoSubscriptionDetailNoteEdit: FC<WfoSubscriptionDetailNoteEditProp
|
|
|
33
33
|
userInputs: noteModifyPayload,
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
queryName: endpointName ?? '',
|
|
38
|
-
subscriptionId: subscriptionId,
|
|
39
|
-
note: note,
|
|
40
|
-
});
|
|
36
|
+
updateSubscriptionNoteOptimistic({ subscriptionId, note });
|
|
41
37
|
};
|
|
42
38
|
|
|
43
39
|
return (
|
|
@@ -8,7 +8,7 @@ import { INVISIBLE_CHARACTER } from '@/utils';
|
|
|
8
8
|
|
|
9
9
|
interface WfoSubscriptionNoteEditProps {
|
|
10
10
|
onlyShowOnHover?: boolean;
|
|
11
|
-
queryVariables:
|
|
11
|
+
queryVariables: object;
|
|
12
12
|
endpointName: string | undefined;
|
|
13
13
|
subscriptionId: string;
|
|
14
14
|
note: string | null;
|
|
@@ -22,7 +22,7 @@ export const WfoSubscriptionNoteEdit: FC<WfoSubscriptionNoteEditProps> = ({
|
|
|
22
22
|
note,
|
|
23
23
|
}) => {
|
|
24
24
|
const [startProcess] = useStartProcessMutation();
|
|
25
|
-
const [
|
|
25
|
+
const [updateSubscriptionNoteOptimistic] = useUpdateSubscriptionNoteOptimisticMutation();
|
|
26
26
|
|
|
27
27
|
const triggerNoteModifyWorkflow = (note: string) => {
|
|
28
28
|
const noteModifyPayload = [{ subscription_id: subscriptionId }, { note: note === INVISIBLE_CHARACTER ? '' : note }];
|
|
@@ -31,11 +31,10 @@ export const WfoSubscriptionNoteEdit: FC<WfoSubscriptionNoteEditProps> = ({
|
|
|
31
31
|
userInputs: noteModifyPayload,
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
note: note,
|
|
34
|
+
updateSubscriptionNoteOptimistic({
|
|
35
|
+
subscriptionId,
|
|
36
|
+
note,
|
|
37
|
+
listQuery: { queryName: endpointName ?? '', queryVariables },
|
|
39
38
|
});
|
|
40
39
|
};
|
|
41
40
|
|
|
@@ -63,8 +63,32 @@ export const getStyles = ({ theme }: WfoThemeHelpers) => {
|
|
|
63
63
|
color: theme.colors.textParagraph,
|
|
64
64
|
display: 'flex',
|
|
65
65
|
alignItems: 'center',
|
|
66
|
+
flexWrap: 'wrap',
|
|
67
|
+
gap: theme.size.s,
|
|
66
68
|
overflowWrap: 'anywhere',
|
|
67
69
|
whiteSpace: 'pre-wrap',
|
|
70
|
+
|
|
71
|
+
'& > *': {
|
|
72
|
+
maxWidth: '100%',
|
|
73
|
+
flexGrow: 1,
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
'& > .euiBadge + .euiBadge': {
|
|
77
|
+
marginInlineStart: 0,
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
'&:has(.euiInlineEdit), & > :has(.euiInlineEdit)': {
|
|
81
|
+
flexGrow: 1,
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
'.euiInlineEditText .euiButtonEmpty': {
|
|
85
|
+
blockSize: 'auto',
|
|
86
|
+
whiteSpace: 'normal',
|
|
87
|
+
textAlign: 'start',
|
|
88
|
+
},
|
|
89
|
+
'.euiInlineEditText .eui-textTruncate': {
|
|
90
|
+
whiteSpace: 'pre-wrap !important',
|
|
91
|
+
},
|
|
68
92
|
});
|
|
69
93
|
|
|
70
94
|
const clipboardIconStyle = css({
|
|
@@ -3,7 +3,6 @@ export const PATH_START_NEW_WORKFLOW = '/workflows/new';
|
|
|
3
3
|
export const PATH_START_NEW_TASK = '/tasks/new';
|
|
4
4
|
export const PATH_WORKFLOWS = '/workflows';
|
|
5
5
|
export const PATH_SUBSCRIPTIONS = '/subscriptions';
|
|
6
|
-
export const PATH_SUBSCRIPTIONS_BETA = '/beta-subscriptions';
|
|
7
6
|
export const PATH_METADATA = '/metadata';
|
|
8
7
|
export const PATH_METADATA_PRODUCTS = '/metadata/products';
|
|
9
8
|
export const PATH_METADATA_PRODUCT_BLOCKS = '/metadata/productblocks';
|
|
@@ -2,6 +2,8 @@ import React from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { PydanticFormElement } from 'pydantic-forms';
|
|
4
4
|
|
|
5
|
+
import { euiFontSizeFromScale } from '@elastic/eui';
|
|
6
|
+
|
|
5
7
|
import { useOrchestratorTheme } from '@/hooks';
|
|
6
8
|
|
|
7
9
|
export const WfoLabel: PydanticFormElement = ({ pydanticFormField }) => {
|
|
@@ -11,7 +13,9 @@ export const WfoLabel: PydanticFormElement = ({ pydanticFormField }) => {
|
|
|
11
13
|
<div data-testid={pydanticFormField.id}>
|
|
12
14
|
<label
|
|
13
15
|
css={{
|
|
14
|
-
|
|
16
|
+
fontSize: euiFontSizeFromScale('m', theme),
|
|
17
|
+
fontWeight: theme.font.weight.semiBold,
|
|
18
|
+
color: theme.colors.link,
|
|
15
19
|
display: 'block',
|
|
16
20
|
}}
|
|
17
21
|
id={pydanticFormField.id}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { euiFontSizeFromScale, euiLineHeightFromBaseline } from '@elastic/eui';
|
|
1
2
|
import { css } from '@emotion/react';
|
|
2
3
|
|
|
3
4
|
import type { WfoThemeHelpers } from '@/hooks';
|
|
@@ -114,15 +115,23 @@ export const getCommonFormFieldStyles = ({ theme }: WfoThemeHelpers) => {
|
|
|
114
115
|
color: theme.colors.textParagraph,
|
|
115
116
|
},
|
|
116
117
|
'.euiFormLabel': {
|
|
117
|
-
|
|
118
|
+
fontSize: euiFontSizeFromScale('m', theme),
|
|
119
|
+
lineHeight: euiLineHeightFromBaseline('m', theme),
|
|
120
|
+
color: theme.colors.link,
|
|
118
121
|
cursor: 'text',
|
|
119
|
-
'&.euiFormLabel-
|
|
120
|
-
color: theme.colors.
|
|
122
|
+
'&.euiFormLabel-isInvalid': {
|
|
123
|
+
color: theme.colors.textDanger,
|
|
121
124
|
},
|
|
122
125
|
},
|
|
123
126
|
'.euiFormRow__labelWrapper': {
|
|
124
127
|
display: 'flex',
|
|
125
128
|
flexDirection: 'column',
|
|
129
|
+
'> .euiText': {
|
|
130
|
+
fontSize: euiFontSizeFromScale('s', theme),
|
|
131
|
+
lineHeight: euiLineHeightFromBaseline('s', theme),
|
|
132
|
+
fontWeight: theme.font.weight.regular,
|
|
133
|
+
color: theme.colors.textParagraph,
|
|
134
|
+
},
|
|
126
135
|
},
|
|
127
136
|
});
|
|
128
137
|
|
|
@@ -14,11 +14,12 @@ export type WfoInformationModalProps = {
|
|
|
14
14
|
title: string;
|
|
15
15
|
onClose: () => void;
|
|
16
16
|
children: ReactNode;
|
|
17
|
+
maxWidth?: number;
|
|
17
18
|
};
|
|
18
19
|
|
|
19
|
-
export const WfoInformationModal: FC<WfoInformationModalProps> = ({ title, onClose, children }) => {
|
|
20
|
+
export const WfoInformationModal: FC<WfoInformationModalProps> = ({ title, onClose, children, maxWidth }) => {
|
|
20
21
|
return (
|
|
21
|
-
<EuiModal onClose={onClose}>
|
|
22
|
+
<EuiModal onClose={onClose} maxWidth={maxWidth}>
|
|
22
23
|
<EuiModalHeader>
|
|
23
24
|
<EuiModalHeaderTitle size="xs">{title}</EuiModalHeaderTitle>
|
|
24
25
|
</EuiModalHeader>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Subscription } from '@/types';
|
|
2
|
+
|
|
3
|
+
export type SubscriptionListItem = Pick<
|
|
4
|
+
Subscription,
|
|
5
|
+
'subscriptionId' | 'description' | 'status' | 'insync' | 'note'
|
|
6
|
+
> & {
|
|
7
|
+
startDate: Date | null;
|
|
8
|
+
endDate: Date | null;
|
|
9
|
+
productName: string;
|
|
10
|
+
tag: string | null;
|
|
11
|
+
customerFullname: string;
|
|
12
|
+
customerShortcode: string;
|
|
13
|
+
metadata: object | null;
|
|
14
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { WfoFilterTab } from '../../components';
|
|
2
|
-
import { SubscriptionListItem } from './subscriptionResultMappers';
|
|
3
2
|
|
|
4
3
|
export enum WfoSubscriptionListTab {
|
|
5
4
|
ACTIVE = 'ACTIVE',
|
|
@@ -8,36 +7,18 @@ export enum WfoSubscriptionListTab {
|
|
|
8
7
|
ALL = 'ALL',
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
export const subscriptionListTabs: WfoFilterTab<WfoSubscriptionListTab
|
|
10
|
+
export const subscriptionListTabs: WfoFilterTab<WfoSubscriptionListTab>[] = [
|
|
12
11
|
{
|
|
13
12
|
id: WfoSubscriptionListTab.ACTIVE,
|
|
14
13
|
translationKey: 'active',
|
|
15
|
-
alwaysOnFilters: [
|
|
16
|
-
{
|
|
17
|
-
field: 'status',
|
|
18
|
-
value: 'active',
|
|
19
|
-
},
|
|
20
|
-
],
|
|
21
14
|
},
|
|
22
15
|
{
|
|
23
16
|
id: WfoSubscriptionListTab.TERMINATED,
|
|
24
17
|
translationKey: 'terminated',
|
|
25
|
-
alwaysOnFilters: [
|
|
26
|
-
{
|
|
27
|
-
field: 'status',
|
|
28
|
-
value: 'terminated',
|
|
29
|
-
},
|
|
30
|
-
],
|
|
31
18
|
},
|
|
32
19
|
{
|
|
33
20
|
id: WfoSubscriptionListTab.TRANSIENT,
|
|
34
21
|
translationKey: 'transient',
|
|
35
|
-
alwaysOnFilters: [
|
|
36
|
-
{
|
|
37
|
-
field: 'status',
|
|
38
|
-
value: 'initial-provisioning-migrating',
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
22
|
},
|
|
42
23
|
{
|
|
43
24
|
id: WfoSubscriptionListTab.ALL,
|
|
@@ -3,30 +3,34 @@ import React from 'react';
|
|
|
3
3
|
import { useTranslations } from 'next-intl';
|
|
4
4
|
|
|
5
5
|
import { PATH_SUBSCRIPTIONS, SummaryCardStatus, WfoSummaryCard } from '@/components';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { mapSubscriptionSearchResultToSummaryCardListItem } from '@/pages/startPage/mappers';
|
|
7
|
+
import { getSubscriptionSummarySearchPayload } from '@/pages/startPage/searchPayloads';
|
|
8
|
+
import { useSearchQuery } from '@/rtk';
|
|
9
|
+
import { Filter } from '@/types';
|
|
9
10
|
import { optionalArrayMapper } from '@/utils';
|
|
10
11
|
|
|
12
|
+
// Elasticsearch equivalent of the list page's default Active tab filter
|
|
13
|
+
// (`subscription.status == "active"`), so the count on the card matches the list.
|
|
14
|
+
const activeSubscriptionsFilter = {
|
|
15
|
+
bool: {
|
|
16
|
+
must: [{ term: { 'subscription.status': 'active' } }],
|
|
17
|
+
},
|
|
18
|
+
} as unknown as Filter;
|
|
19
|
+
|
|
20
|
+
const activeSubscriptionsSearchPayload = getSubscriptionSummarySearchPayload(activeSubscriptionsFilter);
|
|
21
|
+
|
|
11
22
|
export const WfoLatestActiveSubscriptionsSummaryCard = () => {
|
|
12
23
|
const t = useTranslations('startPage.activeSubscriptions');
|
|
13
24
|
|
|
14
|
-
const {
|
|
15
|
-
data: subscriptionsSummaryResult,
|
|
16
|
-
isFetching,
|
|
17
|
-
isLoading,
|
|
18
|
-
} = useGetSubscriptionSummaryListQuery(subscriptionsListSummaryQueryVariables);
|
|
25
|
+
const { data, isFetching, isLoading } = useSearchQuery(activeSubscriptionsSearchPayload);
|
|
19
26
|
|
|
20
27
|
return (
|
|
21
28
|
<WfoSummaryCard
|
|
22
29
|
headerTitle={t('headerTitle')}
|
|
23
|
-
headerValue={
|
|
30
|
+
headerValue={data?.cursor?.total_items ?? '-'}
|
|
24
31
|
headerStatus={SummaryCardStatus.Neutral}
|
|
25
32
|
listTitle={t('listTitle')}
|
|
26
|
-
listItems={optionalArrayMapper(
|
|
27
|
-
subscriptionsSummaryResult?.subscriptions,
|
|
28
|
-
mapSubscriptionSummaryToSummaryCardListItem,
|
|
29
|
-
)}
|
|
33
|
+
listItems={optionalArrayMapper(data?.data, mapSubscriptionSearchResultToSummaryCardListItem)}
|
|
30
34
|
button={{ name: t('buttonText'), url: PATH_SUBSCRIPTIONS }}
|
|
31
35
|
isLoading={isLoading}
|
|
32
36
|
isFetching={isFetching}
|
|
@@ -3,37 +3,50 @@ import React from 'react';
|
|
|
3
3
|
import { useTranslations } from 'next-intl';
|
|
4
4
|
|
|
5
5
|
import { PATH_SUBSCRIPTIONS, SummaryCardStatus, WfoSubscriptionListTab, WfoSummaryCard } from '@/components';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { mapSubscriptionSearchResultToSummaryCardListItem } from '@/pages/startPage/mappers';
|
|
7
|
+
import { getSubscriptionSummarySearchPayload } from '@/pages/startPage/searchPayloads';
|
|
8
|
+
import { useSearchQuery } from '@/rtk';
|
|
9
|
+
import { Filter } from '@/types';
|
|
9
10
|
import { optionalArrayMapper } from '@/utils';
|
|
10
11
|
import { WfoQueryParams, getUrlWithQueryParams } from '@/utils/getQueryParams';
|
|
11
12
|
|
|
13
|
+
const OUT_OF_SYNC_CEL =
|
|
14
|
+
'subscription.insync == false && (subscription.status == "provisioning" || subscription.status == "active")';
|
|
15
|
+
|
|
16
|
+
// Elasticsearch equivalent of OUT_OF_SYNC_CEL. The list page produces the same clauses from the
|
|
17
|
+
// CEL in the button link, so the count on the card matches the list.
|
|
18
|
+
const outOfSyncSubscriptionsFilter = {
|
|
19
|
+
bool: {
|
|
20
|
+
must: [
|
|
21
|
+
{ term: { 'subscription.insync': false } },
|
|
22
|
+
{
|
|
23
|
+
bool: {
|
|
24
|
+
should: [{ term: { 'subscription.status': 'active' } }, { term: { 'subscription.status': 'provisioning' } }],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
} as unknown as Filter;
|
|
30
|
+
|
|
31
|
+
const outOfSyncSubscriptionsSearchPayload = getSubscriptionSummarySearchPayload(outOfSyncSubscriptionsFilter);
|
|
32
|
+
|
|
12
33
|
export const WfoLatestOutOfSyncSubscriptionSummaryCard = () => {
|
|
13
34
|
const t = useTranslations('startPage.outOfSyncSubscriptions');
|
|
14
35
|
|
|
15
|
-
const {
|
|
16
|
-
data: outOfSyncSubscriptionsSummaryResult,
|
|
17
|
-
isFetching,
|
|
18
|
-
isLoading,
|
|
19
|
-
} = useGetSubscriptionSummaryListQuery(outOfSyncSubscriptionsListSummaryQueryVariables);
|
|
36
|
+
const { data, isFetching, isLoading } = useSearchQuery(outOfSyncSubscriptionsSearchPayload);
|
|
20
37
|
|
|
21
38
|
const queryParams = {
|
|
22
39
|
[WfoQueryParams.ACTIVE_TAB]: WfoSubscriptionListTab.ALL,
|
|
23
|
-
[WfoQueryParams.
|
|
24
|
-
[WfoQueryParams.QUERY_STRING]: 'status:(provisioning|active) insync:false',
|
|
40
|
+
[WfoQueryParams.FILTER_STRING]: OUT_OF_SYNC_CEL,
|
|
25
41
|
};
|
|
26
42
|
|
|
27
43
|
return (
|
|
28
44
|
<WfoSummaryCard
|
|
29
45
|
headerTitle={t('headerTitle')}
|
|
30
|
-
headerValue={
|
|
46
|
+
headerValue={data?.cursor?.total_items ?? '-'}
|
|
31
47
|
headerStatus={SummaryCardStatus.Error}
|
|
32
48
|
listTitle={t('listTitle')}
|
|
33
|
-
listItems={optionalArrayMapper(
|
|
34
|
-
outOfSyncSubscriptionsSummaryResult?.subscriptions,
|
|
35
|
-
mapSubscriptionSummaryToSummaryCardListItem,
|
|
36
|
-
)}
|
|
49
|
+
listItems={optionalArrayMapper(data?.data, mapSubscriptionSearchResultToSummaryCardListItem)}
|
|
37
50
|
button={{
|
|
38
51
|
name: t('buttonText'),
|
|
39
52
|
url: getUrlWithQueryParams(PATH_SUBSCRIPTIONS, queryParams),
|
|
@@ -190,7 +190,11 @@ export const WfoAdvancedTable = <T extends object>({
|
|
|
190
190
|
)}
|
|
191
191
|
|
|
192
192
|
{rowDetailData && (
|
|
193
|
-
<WfoInformationModal
|
|
193
|
+
<WfoInformationModal
|
|
194
|
+
title={detailModalTitle}
|
|
195
|
+
onClose={() => setSelectedDataForDetailModal(undefined)}
|
|
196
|
+
maxWidth={theme.breakpoint.m}
|
|
197
|
+
>
|
|
194
198
|
<WfoKeyValueTable keyValues={rowDetailData} showCopyToClipboardIcon />
|
|
195
199
|
</WfoInformationModal>
|
|
196
200
|
)}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useTranslations } from 'next-intl';
|
|
4
|
+
|
|
5
|
+
import { EuiButton } from '@elastic/eui';
|
|
6
|
+
|
|
7
|
+
import { WfoDebounceCountdown } from '@/components/WfoTable/WfoStructuredSearchTable/WfoDebounceCountdown';
|
|
8
|
+
import { getWfoStructuredSearchTableStyles } from '@/components/WfoTable/WfoStructuredSearchTable/styles';
|
|
9
|
+
import { DebouncedPendingRun, useWithOrchestratorTheme } from '@/hooks';
|
|
10
|
+
|
|
11
|
+
interface ApplyFilterButtonProps {
|
|
12
|
+
isDisabled: boolean;
|
|
13
|
+
pendingSearchRun?: DebouncedPendingRun;
|
|
14
|
+
onClick: () => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const WfoApplyFilterButton = ({ isDisabled, pendingSearchRun, onClick }: ApplyFilterButtonProps) => {
|
|
18
|
+
const t = useTranslations('common');
|
|
19
|
+
const { applyFilterContentStyles } = useWithOrchestratorTheme(getWfoStructuredSearchTableStyles);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<EuiButton
|
|
23
|
+
onClick={onClick}
|
|
24
|
+
id={'button-apply-filter'}
|
|
25
|
+
data-test-id={'button-apply-filter'}
|
|
26
|
+
fill
|
|
27
|
+
type="submit"
|
|
28
|
+
aria-label={t('applyFilter')}
|
|
29
|
+
disabled={isDisabled}
|
|
30
|
+
>
|
|
31
|
+
<span css={applyFilterContentStyles}>
|
|
32
|
+
{pendingSearchRun && <WfoDebounceCountdown key={pendingSearchRun.id} durationMs={pendingSearchRun.delay} />}
|
|
33
|
+
{t('applyFilter')}
|
|
34
|
+
</span>
|
|
35
|
+
</EuiButton>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { keyframes } from '@emotion/react';
|
|
4
|
+
|
|
5
|
+
const SIZE = 14;
|
|
6
|
+
const STROKE_WIDTH = 2;
|
|
7
|
+
const CENTER = SIZE / 2;
|
|
8
|
+
const RADIUS = (SIZE - STROKE_WIDTH) / 2;
|
|
9
|
+
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
|
|
10
|
+
|
|
11
|
+
const sweep = keyframes({
|
|
12
|
+
from: { strokeDashoffset: CIRCUMFERENCE },
|
|
13
|
+
to: { strokeDashoffset: 0 },
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
interface WfoDebounceCountdownProps {
|
|
17
|
+
durationMs: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Ring that fills over `durationMs`, showing how long is left before the pending search runs.
|
|
22
|
+
* Render it with a key that changes per scheduled run, so the sweep restarts from empty every
|
|
23
|
+
* time an edit pushes the debounce back.
|
|
24
|
+
*/
|
|
25
|
+
export const WfoDebounceCountdown = ({ durationMs }: WfoDebounceCountdownProps) => (
|
|
26
|
+
<svg width={SIZE} height={SIZE} viewBox={`0 0 ${SIZE} ${SIZE}`} aria-hidden="true" css={{ flex: 'none' }}>
|
|
27
|
+
<circle
|
|
28
|
+
cx={CENTER}
|
|
29
|
+
cy={CENTER}
|
|
30
|
+
r={RADIUS}
|
|
31
|
+
fill="none"
|
|
32
|
+
stroke="currentColor"
|
|
33
|
+
strokeWidth={STROKE_WIDTH}
|
|
34
|
+
opacity={0.3}
|
|
35
|
+
/>
|
|
36
|
+
<circle
|
|
37
|
+
cx={CENTER}
|
|
38
|
+
cy={CENTER}
|
|
39
|
+
r={RADIUS}
|
|
40
|
+
fill="none"
|
|
41
|
+
stroke="currentColor"
|
|
42
|
+
strokeWidth={STROKE_WIDTH}
|
|
43
|
+
strokeLinecap="round"
|
|
44
|
+
strokeDasharray={CIRCUMFERENCE}
|
|
45
|
+
// Start the sweep at 12 o'clock instead of 3 o'clock.
|
|
46
|
+
transform={`rotate(-90 ${CENTER} ${CENTER})`}
|
|
47
|
+
css={{
|
|
48
|
+
strokeDashoffset: CIRCUMFERENCE,
|
|
49
|
+
animation: `${sweep} ${durationMs}ms linear forwards`,
|
|
50
|
+
// A ring that jumps straight to full is still an honest "a search is queued" marker.
|
|
51
|
+
'@media (prefers-reduced-motion: reduce)': {
|
|
52
|
+
animation: 'none',
|
|
53
|
+
strokeDashoffset: 0,
|
|
54
|
+
},
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
</svg>
|
|
58
|
+
);
|