@axinom/mosaic-ui 0.34.0-rc.9 → 0.34.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/dist/components/Explorer/SelectionExplorer/SelectionExplorer.d.ts +3 -0
- package/dist/components/Explorer/SelectionExplorer/SelectionExplorer.d.ts.map +1 -1
- package/dist/components/FormElements/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/FormElements/Checkbox/CheckboxField.d.ts +1 -1
- package/dist/components/FormElements/Checkbox/CheckboxField.d.ts.map +1 -1
- package/dist/components/FormElements/CustomTags/CustomTagsField.d.ts.map +1 -1
- package/dist/components/FormElements/DateTimeField/DateTimeTextField.d.ts +1 -1
- package/dist/components/FormElements/DateTimeField/DateTimeTextField.d.ts.map +1 -1
- package/dist/components/FormElements/DynamicDataListControl/DynamicDataListField.d.ts.map +1 -1
- package/dist/components/FormElements/FileUploadControl/FileUploadField.d.ts.map +1 -1
- package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.d.ts +1 -1
- package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.d.ts.map +1 -1
- package/dist/components/FormElements/SingleLineText/SingleLineText.d.ts.map +1 -1
- package/dist/components/List/ListRow/ListRow.d.ts.map +1 -1
- package/dist/index.es.js +3 -3
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/initialize.d.ts +3 -3
- package/dist/initialize.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.spec.tsx +2 -2
- package/src/components/Explorer/SelectionExplorer/SelectionExplorer.spec.tsx +49 -0
- package/src/components/Explorer/SelectionExplorer/SelectionExplorer.stories.tsx +111 -45
- package/src/components/Explorer/SelectionExplorer/SelectionExplorer.tsx +24 -3
- package/src/components/FormElements/BooleanView/BooleanViewField.scss +4 -6
- package/src/components/FormElements/BooleanView/BooleanViewField.spec.tsx +6 -6
- package/src/components/FormElements/BooleanView/BooleanViewField.tsx +1 -1
- package/src/components/FormElements/Checkbox/Checkbox.tsx +1 -1
- package/src/components/FormElements/Checkbox/CheckboxField.tsx +4 -5
- package/src/components/FormElements/CustomTags/CustomTags.scss +15 -4
- package/src/components/FormElements/CustomTags/CustomTags.spec.tsx +3 -3
- package/src/components/FormElements/CustomTags/CustomTags.tsx +3 -3
- package/src/components/FormElements/CustomTags/CustomTagsField.tsx +1 -2
- package/src/components/FormElements/DateTimeField/DateTimeTextField.tsx +3 -3
- package/src/components/FormElements/DynamicDataListControl/DynamicDataListField.tsx +1 -2
- package/src/components/FormElements/FileUploadControl/FileUploadField.tsx +1 -2
- package/src/components/FormElements/FormElementContainer/FormElementContainer.scss +0 -1
- package/src/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.tsx +1 -1
- package/src/components/FormElements/Radio/RadioField.tsx +2 -2
- package/src/components/FormElements/SingleLineText/SingleLineText.spec.tsx +5 -4
- package/src/components/FormElements/SingleLineText/SingleLineText.tsx +6 -1
- package/src/components/FormElements/Tags/Tags.scss +1 -1
- package/src/components/FormElements/ToggleButton/ToggleButton.scss +18 -7
- package/src/components/FormStation/FormStation.spec.tsx +12 -6
- package/src/components/FormStation/FormStation.tsx +6 -6
- package/src/components/InlineMenu/InlineMenu.scss +20 -5
- package/src/components/LandingPageTiles/TileLarge/TileLarge.scss +11 -6
- package/src/components/List/ListRow/ListRow.scss +4 -1
- package/src/components/List/ListRow/ListRow.spec.tsx +11 -6
- package/src/components/List/ListRow/ListRow.tsx +43 -36
- package/src/initialize.ts +4 -4
- package/src/styles/variables.scss +11 -0
package/dist/initialize.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AddIndicator, CustomEventEmitter, RemoveIndicator, ShowNotification } from './types/ui-config';
|
|
2
|
-
export declare enum
|
|
2
|
+
export declare enum SaveIndicatorType {
|
|
3
3
|
Saving = "saving",
|
|
4
4
|
Inactive = "inactive",
|
|
5
5
|
Dirty = "dirty"
|
|
@@ -8,7 +8,7 @@ export declare let showNotification: ShowNotification | (() => void);
|
|
|
8
8
|
export declare let addIndicator: AddIndicator | (() => void);
|
|
9
9
|
export declare let removeIndicator: RemoveIndicator | (() => void);
|
|
10
10
|
export declare let on: CustomEventEmitter['on'] | (() => void);
|
|
11
|
-
export declare let setSaveIndicator: (type:
|
|
11
|
+
export declare let setSaveIndicator: (type: SaveIndicatorType) => void;
|
|
12
12
|
/**
|
|
13
13
|
* Passes the PiralApi methods to the UI library.
|
|
14
14
|
* @param app {UiConfig} object containing PiralApi methods for use in UI library.
|
|
@@ -19,6 +19,6 @@ export interface UiConfig {
|
|
|
19
19
|
addIndicator: AddIndicator;
|
|
20
20
|
removeIndicator: RemoveIndicator;
|
|
21
21
|
on: CustomEventEmitter['on'];
|
|
22
|
-
setSaveIndicator: (type:
|
|
22
|
+
setSaveIndicator: (type: SaveIndicatorType) => void;
|
|
23
23
|
}
|
|
24
24
|
//# sourceMappingURL=initialize.d.ts.map
|
package/dist/initialize.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initialize.d.ts","sourceRoot":"","sources":["../src/initialize.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAE3B,oBAAY,
|
|
1
|
+
{"version":3,"file":"initialize.d.ts","sourceRoot":"","sources":["../src/initialize.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAE3B,oBAAY,iBAAiB;IAC3B,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,KAAK,UAAU;CAChB;AAED,eAAO,IAAI,gBAAgB,EAAE,gBAAgB,GAAG,CAAC,MAAM,IAAI,CAC7B,CAAC;AAE/B,eAAO,IAAI,YAAY,EAAE,YAAY,GAAG,CAAC,MAAM,IAAI,CAA4B,CAAC;AAEhF,eAAO,IAAI,eAAe,EAAE,eAAe,GAAG,CAAC,MAAM,IAAI,CAC5B,CAAC;AAE9B,eAAO,IAAI,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,CAAkB,CAAC;AAExE,eAAO,IAAI,gBAAgB,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAC5B,CAAC;AAE/B;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAQhD;AAED,MAAM,WAAW,QAAQ;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,EAAE,eAAe,CAAC;IACjC,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7B,gBAAgB,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACrD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-ui",
|
|
3
|
-
"version": "0.34.0
|
|
3
|
+
"version": "0.34.0",
|
|
4
4
|
"description": "UI components for building Axinom Mosaic applications",
|
|
5
5
|
"author": "Axinom",
|
|
6
6
|
"license": "PROPRIETARY",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"build-storybook": "storybook build"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@axinom/mosaic-core": "^0.4.7
|
|
35
|
+
"@axinom/mosaic-core": "^0.4.7",
|
|
36
36
|
"@faker-js/faker": "^7.4.0",
|
|
37
37
|
"@popperjs/core": "^2.9.2",
|
|
38
38
|
"clsx": "^1.1.0",
|
|
@@ -102,5 +102,5 @@
|
|
|
102
102
|
"publishConfig": {
|
|
103
103
|
"access": "public"
|
|
104
104
|
},
|
|
105
|
-
"gitHead": "
|
|
105
|
+
"gitHead": "7c6702d386aee28156332c050cf7c97f3df2b1db"
|
|
106
106
|
}
|
|
@@ -49,7 +49,7 @@ describe('createInputRenderer', () => {
|
|
|
49
49
|
|
|
50
50
|
const input = wrapper.find('input');
|
|
51
51
|
|
|
52
|
-
expect(input.
|
|
52
|
+
expect(input.getDOMNode<HTMLInputElement>().value).toBe(mockValue);
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
it(`emits 'onValueChange' with the new value when 'input' value has changed`, () => {
|
|
@@ -59,7 +59,7 @@ describe('createInputRenderer', () => {
|
|
|
59
59
|
|
|
60
60
|
const input = wrapper.find('input');
|
|
61
61
|
|
|
62
|
-
expect(input.
|
|
62
|
+
expect(input.getDOMNode<HTMLInputElement>().value).toBe('');
|
|
63
63
|
|
|
64
64
|
act(() => {
|
|
65
65
|
input.simulate('change', { target: { value: mockValueUpdated } });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mount, shallow } from 'enzyme';
|
|
2
|
+
import { noop } from 'lodash';
|
|
2
3
|
import React from 'react';
|
|
3
4
|
import { act } from 'react-dom/test-utils';
|
|
4
5
|
import { actWithReturn } from '../../../helpers/testing';
|
|
@@ -165,4 +166,52 @@ describe('SelectionExplorer', () => {
|
|
|
165
166
|
mode: 'SINGLE_ITEMS',
|
|
166
167
|
});
|
|
167
168
|
});
|
|
169
|
+
|
|
170
|
+
it('shows inline menu with link to details page when `generateItemLink` is set', () => {
|
|
171
|
+
const [provider] = getDataProvider();
|
|
172
|
+
const path = '/test';
|
|
173
|
+
|
|
174
|
+
const wrapper = shallow(
|
|
175
|
+
<SelectionExplorer
|
|
176
|
+
columns={mockListColumns}
|
|
177
|
+
dataProvider={provider}
|
|
178
|
+
stationKey="mock-key"
|
|
179
|
+
onSelection={noop}
|
|
180
|
+
generateItemLink={() => path}
|
|
181
|
+
/>,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
const actions =
|
|
185
|
+
wrapper.find(Explorer).prop('inlineMenuActions')?.({}) || [];
|
|
186
|
+
expect(actions[0].path).toBe(path);
|
|
187
|
+
expect(actions[0].openInNewTab).toBe(true);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('adds details page inline menu action when `inlineMenuActions` and `generateItemLink` is defined', () => {
|
|
191
|
+
const [provider] = getDataProvider();
|
|
192
|
+
const path = '/test';
|
|
193
|
+
const inlineAction = {
|
|
194
|
+
label: 'Test Action',
|
|
195
|
+
onActionSelected: noop,
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const wrapper = shallow(
|
|
199
|
+
<SelectionExplorer
|
|
200
|
+
columns={mockListColumns}
|
|
201
|
+
dataProvider={provider}
|
|
202
|
+
stationKey="mock-key"
|
|
203
|
+
onSelection={noop}
|
|
204
|
+
inlineMenuActions={() => [inlineAction]}
|
|
205
|
+
generateItemLink={() => path}
|
|
206
|
+
/>,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const actions =
|
|
210
|
+
wrapper.find(Explorer).prop('inlineMenuActions')?.({}) || [];
|
|
211
|
+
|
|
212
|
+
expect(actions[0]).toBe(inlineAction);
|
|
213
|
+
|
|
214
|
+
expect(actions[1].path).toBe(path);
|
|
215
|
+
expect(actions[1].openInNewTab).toBe(true);
|
|
216
|
+
});
|
|
168
217
|
});
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker';
|
|
2
2
|
import { action } from '@storybook/addon-actions';
|
|
3
3
|
import { Meta, StoryObj } from '@storybook/react';
|
|
4
|
+
import { noop } from 'lodash';
|
|
4
5
|
import React, { useMemo } from 'react';
|
|
6
|
+
import { MemoryRouter } from 'react-router';
|
|
5
7
|
import {
|
|
6
8
|
createGroups,
|
|
7
9
|
generateItemArray,
|
|
8
10
|
randomDate,
|
|
9
11
|
} from '../../../helpers/storybook';
|
|
10
12
|
import { FilterType, FilterTypes } from '../../Filters/Filters.model';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
+
import { IconName } from '../../Icons';
|
|
14
|
+
import {
|
|
15
|
+
ExplorerDataProvider,
|
|
16
|
+
ExplorerDataProviderConfiguration,
|
|
17
|
+
} from '../Explorer.model';
|
|
13
18
|
import {
|
|
14
19
|
createInMemoryDataProvider,
|
|
15
20
|
findAnywhereInStringCaseInsensitive,
|
|
@@ -77,7 +82,7 @@ export default meta;
|
|
|
77
82
|
const generateData = (
|
|
78
83
|
amount: number,
|
|
79
84
|
{ startIndex = 1, usePrefix = true } = {},
|
|
80
|
-
):
|
|
85
|
+
): SelectExplorerStoryData[] =>
|
|
81
86
|
generateItemArray(amount, (i) => {
|
|
82
87
|
const index = i + startIndex;
|
|
83
88
|
return {
|
|
@@ -92,6 +97,49 @@ const generateData = (
|
|
|
92
97
|
};
|
|
93
98
|
});
|
|
94
99
|
|
|
100
|
+
const generateDataProvider =
|
|
101
|
+
(): ExplorerDataProvider<SelectExplorerStoryData> => {
|
|
102
|
+
const pageSize = 20;
|
|
103
|
+
|
|
104
|
+
const actualProvider = createInMemoryDataProvider<SelectExplorerStoryData>(
|
|
105
|
+
generateData(100, {
|
|
106
|
+
usePrefix: false,
|
|
107
|
+
}),
|
|
108
|
+
{
|
|
109
|
+
filterFunctions: {
|
|
110
|
+
title: findAnywhereInStringCaseInsensitive,
|
|
111
|
+
desc: findAnywhereInStringCaseInsensitive,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
return {
|
|
116
|
+
loadData: async (
|
|
117
|
+
config: ExplorerDataProviderConfiguration<SelectExplorerStoryData>,
|
|
118
|
+
) => {
|
|
119
|
+
// Report the call
|
|
120
|
+
action('loadData')(config);
|
|
121
|
+
|
|
122
|
+
const currentPage = (config.pagingInformation as number) ?? 0;
|
|
123
|
+
|
|
124
|
+
// Use the in memory provider to do the heavy lifting
|
|
125
|
+
const { totalCount, filteredCount, data } =
|
|
126
|
+
await actualProvider.loadData(config);
|
|
127
|
+
|
|
128
|
+
// Apply paging to the results
|
|
129
|
+
return {
|
|
130
|
+
totalCount: totalCount,
|
|
131
|
+
filteredCount: filteredCount,
|
|
132
|
+
data: data.slice(
|
|
133
|
+
pageSize * currentPage,
|
|
134
|
+
pageSize * (currentPage + 1),
|
|
135
|
+
),
|
|
136
|
+
pagingInformation: currentPage + 1,
|
|
137
|
+
hasMoreData: currentPage < 9,
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
|
|
95
143
|
const freeTextFilter: FilterType<SelectExplorerStoryData> = {
|
|
96
144
|
label: 'Title',
|
|
97
145
|
property: 'title',
|
|
@@ -114,8 +162,7 @@ const optionFilter: FilterType<SelectExplorerStoryData> = {
|
|
|
114
162
|
],
|
|
115
163
|
};
|
|
116
164
|
|
|
117
|
-
export const
|
|
118
|
-
name: 'Selection Explorer',
|
|
165
|
+
export const Default: StoryObj<SelectionExplorerStoryType> = {
|
|
119
166
|
args: {
|
|
120
167
|
title: 'Selection Explorer',
|
|
121
168
|
columns: [
|
|
@@ -141,46 +188,7 @@ export const SelectExplorer: StoryObj<SelectionExplorerStoryType> = {
|
|
|
141
188
|
render: (args) =>
|
|
142
189
|
React.createElement(() => {
|
|
143
190
|
const dataProvider: ExplorerDataProvider<SelectExplorerStoryData> =
|
|
144
|
-
useMemo(
|
|
145
|
-
const pageSize = 20;
|
|
146
|
-
|
|
147
|
-
const actualProvider =
|
|
148
|
-
createInMemoryDataProvider<SelectExplorerStoryData>(
|
|
149
|
-
generateData(100, {
|
|
150
|
-
usePrefix: false,
|
|
151
|
-
}),
|
|
152
|
-
{
|
|
153
|
-
filterFunctions: {
|
|
154
|
-
title: findAnywhereInStringCaseInsensitive,
|
|
155
|
-
desc: findAnywhereInStringCaseInsensitive,
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
);
|
|
159
|
-
return {
|
|
160
|
-
loadData: async (config) => {
|
|
161
|
-
// Report the call
|
|
162
|
-
action('loadData')(config);
|
|
163
|
-
|
|
164
|
-
const currentPage = (config.pagingInformation as number) ?? 0;
|
|
165
|
-
|
|
166
|
-
// Use the in memory provider to do the heavy lifting
|
|
167
|
-
const { totalCount, filteredCount, data } =
|
|
168
|
-
await actualProvider.loadData(config);
|
|
169
|
-
|
|
170
|
-
// Apply paging to the results
|
|
171
|
-
return {
|
|
172
|
-
totalCount: totalCount,
|
|
173
|
-
filteredCount: filteredCount,
|
|
174
|
-
data: data.slice(
|
|
175
|
-
pageSize * currentPage,
|
|
176
|
-
pageSize * (currentPage + 1),
|
|
177
|
-
),
|
|
178
|
-
pagingInformation: currentPage + 1,
|
|
179
|
-
hasMoreData: currentPage < 9,
|
|
180
|
-
};
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
}, []);
|
|
191
|
+
useMemo(generateDataProvider, []);
|
|
184
192
|
|
|
185
193
|
return (
|
|
186
194
|
<SelectionExplorer<SelectExplorerStoryData>
|
|
@@ -190,3 +198,61 @@ export const SelectExplorer: StoryObj<SelectionExplorerStoryType> = {
|
|
|
190
198
|
);
|
|
191
199
|
}),
|
|
192
200
|
};
|
|
201
|
+
|
|
202
|
+
export const WithOpenDetailsInlineAction: StoryObj<SelectionExplorerStoryType> =
|
|
203
|
+
{
|
|
204
|
+
args: {
|
|
205
|
+
...Default.args,
|
|
206
|
+
stationKey: 'SelectionStoryBookExplorer_WithOpenDetailsInlineAction',
|
|
207
|
+
generateItemLink: () => `#`,
|
|
208
|
+
},
|
|
209
|
+
render: (args) =>
|
|
210
|
+
React.createElement(() => {
|
|
211
|
+
const dataProvider: ExplorerDataProvider<SelectExplorerStoryData> =
|
|
212
|
+
useMemo(generateDataProvider, []);
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<MemoryRouter>
|
|
216
|
+
<SelectionExplorer<SelectExplorerStoryData>
|
|
217
|
+
{...args}
|
|
218
|
+
dataProvider={dataProvider}
|
|
219
|
+
/>
|
|
220
|
+
</MemoryRouter>
|
|
221
|
+
);
|
|
222
|
+
}),
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export const WithInlineActions: StoryObj<SelectionExplorerStoryType> = {
|
|
226
|
+
args: {
|
|
227
|
+
...Default.args,
|
|
228
|
+
stationKey: 'SelectionStoryBookExplorer_WithInlineActions',
|
|
229
|
+
inlineMenuActions: () => {
|
|
230
|
+
return [
|
|
231
|
+
{
|
|
232
|
+
label: 'Navigation Action',
|
|
233
|
+
icon: IconName.NavigateRight,
|
|
234
|
+
path: '#',
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
label: 'Context Action',
|
|
238
|
+
icon: IconName.Ellipsis,
|
|
239
|
+
onActionSelected: noop,
|
|
240
|
+
},
|
|
241
|
+
];
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
render: (args) =>
|
|
245
|
+
React.createElement(() => {
|
|
246
|
+
const dataProvider: ExplorerDataProvider<SelectExplorerStoryData> =
|
|
247
|
+
useMemo(generateDataProvider, []);
|
|
248
|
+
|
|
249
|
+
return (
|
|
250
|
+
<MemoryRouter>
|
|
251
|
+
<SelectionExplorer<SelectExplorerStoryData>
|
|
252
|
+
{...args}
|
|
253
|
+
dataProvider={dataProvider}
|
|
254
|
+
/>
|
|
255
|
+
</MemoryRouter>
|
|
256
|
+
);
|
|
257
|
+
}),
|
|
258
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { LocationDescriptor } from 'history';
|
|
1
2
|
import React, { ForwardedRef } from 'react';
|
|
2
3
|
import { noop } from '../../../helpers/utils';
|
|
3
4
|
import { Data } from '../../../types/data';
|
|
5
|
+
import { ActionData } from '../../Actions/Actions.models';
|
|
4
6
|
import { IconName } from '../../Icons';
|
|
5
7
|
import { ListSelectMode } from '../../List';
|
|
6
8
|
import { Explorer, ExplorerProps } from '../Explorer';
|
|
@@ -23,6 +25,9 @@ export interface SelectionExplorerProps<T extends Data>
|
|
|
23
25
|
* The selected item (or items) will be passed as argument to the callback.
|
|
24
26
|
*/
|
|
25
27
|
onSelection?: (selection: ItemSelection<T>) => void;
|
|
28
|
+
|
|
29
|
+
/** When set, this function is used to generate inline menu link that navigates user to details page for each item. */
|
|
30
|
+
generateItemLink?: (data: T) => LocationDescriptor<unknown>;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
/**
|
|
@@ -38,14 +43,14 @@ export interface SelectionExplorerProps<T extends Data>
|
|
|
38
43
|
export const SelectionExplorer = React.forwardRef(function SelectionExplorer<
|
|
39
44
|
T extends Data,
|
|
40
45
|
>(
|
|
41
|
-
|
|
46
|
+
{ generateItemLink, inlineMenuActions, ...rest }: SelectionExplorerProps<T>,
|
|
42
47
|
ref: ForwardedRef<ExplorerDataProviderConnection<T>>,
|
|
43
48
|
): JSX.Element {
|
|
44
49
|
const {
|
|
45
50
|
allowBulkSelect = false,
|
|
46
51
|
onSelection = noop,
|
|
47
52
|
modalMode = true,
|
|
48
|
-
} =
|
|
53
|
+
} = rest;
|
|
49
54
|
|
|
50
55
|
const onItemClickedHandler = (item: T, mode?: ListSelectMode): void => {
|
|
51
56
|
// only if the list is not in Multi mode is this executed
|
|
@@ -54,10 +59,25 @@ export const SelectionExplorer = React.forwardRef(function SelectionExplorer<
|
|
|
54
59
|
}
|
|
55
60
|
};
|
|
56
61
|
|
|
62
|
+
let selectionExplorerActions = inlineMenuActions;
|
|
63
|
+
|
|
64
|
+
if (generateItemLink) {
|
|
65
|
+
selectionExplorerActions = (data: T): ActionData[] => {
|
|
66
|
+
return [
|
|
67
|
+
...(inlineMenuActions?.(data) ?? []),
|
|
68
|
+
{
|
|
69
|
+
label: 'Open Details',
|
|
70
|
+
path: generateItemLink(data),
|
|
71
|
+
openInNewTab: true,
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
57
77
|
return (
|
|
58
78
|
<Explorer<T>
|
|
79
|
+
{...rest}
|
|
59
80
|
ref={ref}
|
|
60
|
-
{...props}
|
|
61
81
|
modalMode={modalMode}
|
|
62
82
|
bulkActions={[
|
|
63
83
|
...(allowBulkSelect
|
|
@@ -75,6 +95,7 @@ export const SelectionExplorer = React.forwardRef(function SelectionExplorer<
|
|
|
75
95
|
]}
|
|
76
96
|
selectionMode={ListSelectMode.Single}
|
|
77
97
|
onItemClicked={onItemClickedHandler}
|
|
98
|
+
inlineMenuActions={selectionExplorerActions}
|
|
78
99
|
/>
|
|
79
100
|
);
|
|
80
101
|
});
|
|
@@ -8,18 +8,16 @@
|
|
|
8
8
|
font-size: var(--label-font-size, $label-font-size);
|
|
9
9
|
align-items: center;
|
|
10
10
|
|
|
11
|
-
.
|
|
12
|
-
background-
|
|
11
|
+
.false {
|
|
12
|
+
background-image: url("data:image/svg+xml, %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40' %3E%3Cpath vector-effect='non-scaling-stroke' fill='none' stroke='%23707070' stroke-width='2' d='M20.1,2.4c9.9,0,18,8.1,18,18s-8.1,18-18,18s-18-8.1-18-18 S10.2,2.4,20.1,2.4z M28.6,20H11.4'/%3E%3C/svg%3E");
|
|
13
13
|
height: 20px;
|
|
14
14
|
width: 20px;
|
|
15
|
-
border-radius: 100%;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
.
|
|
19
|
-
background-
|
|
17
|
+
.true {
|
|
18
|
+
background-image: url("data:image/svg+xml, %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40' %3E%3Cpath vector-effect='non-scaling-stroke' fill='none' stroke='%2395C842' stroke-width='2' d='M20,2c9.9,0,18,8.1,18,18s-8.1,18-18,18S2,29.9,2,20S10.1,2,20,2z M29,13.5 L17.8,26.3L11,19.1'/%3E%3C/svg%3E");
|
|
20
19
|
height: 20px;
|
|
21
20
|
width: 20px;
|
|
22
|
-
border-radius: 100%;
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
23
|
}
|
|
@@ -40,8 +40,8 @@ describe('BooleanViewField', () => {
|
|
|
40
40
|
/>,
|
|
41
41
|
);
|
|
42
42
|
|
|
43
|
-
const green = wrapper.find('.
|
|
44
|
-
const red = wrapper.find('.
|
|
43
|
+
const green = wrapper.find('.true');
|
|
44
|
+
const red = wrapper.find('.false');
|
|
45
45
|
const text = wrapper.find('.text');
|
|
46
46
|
|
|
47
47
|
expect(green.exists()).toBe(true);
|
|
@@ -61,8 +61,8 @@ describe('BooleanViewField', () => {
|
|
|
61
61
|
/>,
|
|
62
62
|
);
|
|
63
63
|
|
|
64
|
-
const green = wrapper.find('.
|
|
65
|
-
const red = wrapper.find('.
|
|
64
|
+
const green = wrapper.find('.true');
|
|
65
|
+
const red = wrapper.find('.false');
|
|
66
66
|
const text = wrapper.find('.text');
|
|
67
67
|
|
|
68
68
|
expect(green.exists()).toBe(false);
|
|
@@ -73,8 +73,8 @@ describe('BooleanViewField', () => {
|
|
|
73
73
|
it('defaults to show red circle', () => {
|
|
74
74
|
const wrapper = shallow(<BooleanViewField />);
|
|
75
75
|
|
|
76
|
-
const green = wrapper.find('.
|
|
77
|
-
const red = wrapper.find('.
|
|
76
|
+
const green = wrapper.find('.true');
|
|
77
|
+
const red = wrapper.find('.false');
|
|
78
78
|
|
|
79
79
|
expect(green.exists()).toBe(false);
|
|
80
80
|
expect(red.exists()).toBe(true);
|
|
@@ -31,7 +31,7 @@ export const BooleanViewField: React.FC<BooleanViewFieldProps> = ({
|
|
|
31
31
|
dataTestFieldType="BooleanView"
|
|
32
32
|
>
|
|
33
33
|
<div className={clsx(classes.value)}>
|
|
34
|
-
<div className={clsx(value ? classes.
|
|
34
|
+
<div className={clsx(value ? classes.true : classes.false)}></div>
|
|
35
35
|
<div
|
|
36
36
|
className={clsx(classes.text)}
|
|
37
37
|
data-test-id="form-field-value"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import React, { useRef, useState } from 'react';
|
|
3
3
|
import {
|
|
4
|
+
ConfirmDialog,
|
|
4
5
|
ConfirmationConfig,
|
|
5
6
|
ConfirmationMode,
|
|
6
|
-
ConfirmDialog,
|
|
7
7
|
} from '../../ConfirmDialog';
|
|
8
8
|
import { BaseFormControl, BaseInputEvents } from '../Form.models';
|
|
9
9
|
import { FormElementContainer } from '../FormElementContainer';
|
|
@@ -2,12 +2,11 @@ import { useField } from 'formik';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { useFormikError } from '../useFormikError';
|
|
4
4
|
import { Checkbox, CheckboxProps } from './Checkbox';
|
|
5
|
-
export const CheckboxField: React.FC<
|
|
6
|
-
|
|
7
|
-
) => {
|
|
8
|
-
const { name } = props;
|
|
5
|
+
export const CheckboxField: React.FC<
|
|
6
|
+
Omit<CheckboxProps, 'error' | 'onChange'>
|
|
7
|
+
> = (props) => {
|
|
9
8
|
const error = useFormikError(props.name);
|
|
10
|
-
const [field, , helpers] = useField(name);
|
|
9
|
+
const [field, , helpers] = useField(props.name);
|
|
11
10
|
|
|
12
11
|
return (
|
|
13
12
|
<Checkbox
|
|
@@ -127,7 +127,10 @@
|
|
|
127
127
|
stroke: white;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
background-color:
|
|
130
|
+
background-color: var(
|
|
131
|
+
--tag-plus-button-bg-color,
|
|
132
|
+
$tag-plus-button-bg-color
|
|
133
|
+
);
|
|
131
134
|
position: absolute;
|
|
132
135
|
right: 1px;
|
|
133
136
|
top: 1px;
|
|
@@ -146,8 +149,16 @@
|
|
|
146
149
|
|
|
147
150
|
&:enabled {
|
|
148
151
|
&:hover {
|
|
149
|
-
border: 1px solid
|
|
150
|
-
|
|
152
|
+
border: 1px solid
|
|
153
|
+
var(
|
|
154
|
+
--tag-plus-button-hover-stroke-color,
|
|
155
|
+
$tag-plus-button-hover-stroke-color
|
|
156
|
+
);
|
|
157
|
+
box-shadow: 0 0 0 2px
|
|
158
|
+
var(
|
|
159
|
+
--tag-plus-button-hover-stroke-color,
|
|
160
|
+
$tag-plus-button-hover-stroke-color
|
|
161
|
+
);
|
|
151
162
|
|
|
152
163
|
&.hasError {
|
|
153
164
|
border: 1px solid
|
|
@@ -164,7 +175,7 @@
|
|
|
164
175
|
|
|
165
176
|
.customTagEnter {
|
|
166
177
|
opacity: 0;
|
|
167
|
-
background-color:
|
|
178
|
+
background-color: var(--tag-enter-color, $tag-enter-color) !important;
|
|
168
179
|
}
|
|
169
180
|
|
|
170
181
|
.customTagEnterActive {
|
|
@@ -70,7 +70,7 @@ describe('CustomTags', () => {
|
|
|
70
70
|
|
|
71
71
|
it('displays a tag for each currently selected tag', () => {
|
|
72
72
|
const mockCurrentTags = ['1', '2', '3'];
|
|
73
|
-
const wrapper =
|
|
73
|
+
const wrapper = mount(
|
|
74
74
|
<CustomTags name={'test-name'} value={mockCurrentTags} />,
|
|
75
75
|
);
|
|
76
76
|
|
|
@@ -361,7 +361,7 @@ describe('CustomTags', () => {
|
|
|
361
361
|
const onChangeSpy = jest.fn();
|
|
362
362
|
const mockCurrentTags = ['1', '2', '3'];
|
|
363
363
|
const mockTag = '';
|
|
364
|
-
const wrapper =
|
|
364
|
+
const wrapper = mount(
|
|
365
365
|
<CustomTags
|
|
366
366
|
name={'test-name'}
|
|
367
367
|
onChange={onChangeSpy}
|
|
@@ -394,7 +394,7 @@ describe('CustomTags', () => {
|
|
|
394
394
|
const onChangeSpy = jest.fn();
|
|
395
395
|
const mockCurrentTags = ['1', '2', '3'];
|
|
396
396
|
const mockTag = '2';
|
|
397
|
-
const wrapper =
|
|
397
|
+
const wrapper = mount(
|
|
398
398
|
<CustomTags
|
|
399
399
|
name={'test-name'}
|
|
400
400
|
onChange={onChangeSpy}
|
|
@@ -56,7 +56,7 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
|
|
|
56
56
|
id,
|
|
57
57
|
name,
|
|
58
58
|
type = 'text',
|
|
59
|
-
value
|
|
59
|
+
value,
|
|
60
60
|
disabled = false,
|
|
61
61
|
placeholder,
|
|
62
62
|
error = undefined,
|
|
@@ -70,12 +70,12 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
|
|
|
70
70
|
className = '',
|
|
71
71
|
...rest
|
|
72
72
|
}) => {
|
|
73
|
-
const [currentTags, setCurrentTags] = useState<string[]>(
|
|
73
|
+
const [currentTags, setCurrentTags] = useState<string[]>([]); // Current tags the user has selected
|
|
74
74
|
const [shouldAnimate, setShouldAnimate] = useState<boolean>(false);
|
|
75
75
|
const ref = useRef<FormEvent<HTMLInputElement>>();
|
|
76
76
|
|
|
77
77
|
useEffect(() => {
|
|
78
|
-
setCurrentTags(
|
|
78
|
+
setCurrentTags(value ?? []);
|
|
79
79
|
}, [value]);
|
|
80
80
|
|
|
81
81
|
const styles = {
|
|
@@ -6,9 +6,8 @@ import { CustomTags, CustomTagsProps } from './CustomTags';
|
|
|
6
6
|
export const CustomTagsField: React.FC<
|
|
7
7
|
Omit<CustomTagsProps, 'error' | 'onChange'>
|
|
8
8
|
> = (props) => {
|
|
9
|
-
const { name } = props;
|
|
10
9
|
const error = useFormikError(props.name);
|
|
11
|
-
const [field, , helpers] = useField(name);
|
|
10
|
+
const [field, , helpers] = useField(props.name);
|
|
12
11
|
|
|
13
12
|
return (
|
|
14
13
|
<CustomTags
|
|
@@ -8,9 +8,9 @@ import { DateTimeText, DateTimeTextProps } from './DateTimeText';
|
|
|
8
8
|
* @example
|
|
9
9
|
* <Field name="title" label="Title" as={DateTimeTextField} />
|
|
10
10
|
*/
|
|
11
|
-
export const DateTimeTextField: React.FC<
|
|
12
|
-
|
|
13
|
-
) => {
|
|
11
|
+
export const DateTimeTextField: React.FC<
|
|
12
|
+
Omit<DateTimeTextProps, 'error' | 'onChange'>
|
|
13
|
+
> = (props) => {
|
|
14
14
|
const error = useFormikError(props.name);
|
|
15
15
|
const [, meta, helpers] = useField(props.name);
|
|
16
16
|
|
|
@@ -24,9 +24,8 @@ export const DynamicDataListField = <T extends Data>(
|
|
|
24
24
|
Omit<DynamicDataListControlProps<T>, 'error' | 'onChange'>
|
|
25
25
|
>,
|
|
26
26
|
): JSX.Element => {
|
|
27
|
-
const { name } = props;
|
|
28
27
|
const error = useFormikError(props.name);
|
|
29
|
-
const [field, , helpers] = useField(name);
|
|
28
|
+
const [field, , helpers] = useField(props.name);
|
|
30
29
|
|
|
31
30
|
return (
|
|
32
31
|
<DynamicDataListControl
|
|
@@ -6,9 +6,8 @@ import { FileUploadControl, FileUploadProps } from './FileUploadControl';
|
|
|
6
6
|
export const FileUploadField: React.FC<
|
|
7
7
|
Omit<FileUploadProps, 'onFileSelected' | 'error'>
|
|
8
8
|
> = (props) => {
|
|
9
|
-
const { name } = props;
|
|
10
9
|
const error = useFormikError(props.name);
|
|
11
|
-
const [field, , helpers] = useField(name);
|
|
10
|
+
const [field, , helpers] = useField(props.name);
|
|
12
11
|
|
|
13
12
|
return (
|
|
14
13
|
<FileUploadControl
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
placeholderChar={'0'}, />
|
|
18
18
|
*/
|
|
19
19
|
export const MaskedSingleLineTextField: React.FC<
|
|
20
|
-
Omit<MaskedSingleLineTextProps, 'error'>
|
|
20
|
+
Omit<MaskedSingleLineTextProps, 'error' | 'onChange'>
|
|
21
21
|
> = (props) => {
|
|
22
22
|
const error = useFormikError(props.name);
|
|
23
23
|
|
|
@@ -9,9 +9,9 @@ export const RadioField: React.FC<
|
|
|
9
9
|
transform?: (value: unknown) => unknown;
|
|
10
10
|
}
|
|
11
11
|
> = (props) => {
|
|
12
|
-
const {
|
|
12
|
+
const { transform = (value: unknown) => value } = props;
|
|
13
13
|
const error = useFormikError(props.name);
|
|
14
|
-
const [field, , helpers] = useField(name);
|
|
14
|
+
const [field, , helpers] = useField(props.name);
|
|
15
15
|
|
|
16
16
|
return (
|
|
17
17
|
<Radio
|