@axinom/mosaic-ui 0.43.0-rc.1 → 0.43.0-rc.11
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/Explorer.d.ts +2 -0
- package/dist/components/Explorer/Explorer.d.ts.map +1 -1
- package/dist/components/Explorer/NavigationExplorer/NavigationExplorer.d.ts +1 -1
- package/dist/components/Explorer/NavigationExplorer/NavigationExplorer.d.ts.map +1 -1
- package/dist/components/Explorer/SelectionExplorer/SelectionExplorer.d.ts +1 -1
- package/dist/components/Explorer/SelectionExplorer/SelectionExplorer.d.ts.map +1 -1
- package/dist/components/FormStation/FormStation.d.ts +3 -1
- package/dist/components/FormStation/FormStation.d.ts.map +1 -1
- package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts +1 -0
- package/dist/components/FormStation/FormStationHeader/FormStationHeader.d.ts.map +1 -1
- package/dist/components/FormStation/helpers/useDataProvider.d.ts.map +1 -1
- package/dist/components/FormStation/helpers/useTitle.d.ts +3 -0
- package/dist/components/FormStation/helpers/useTitle.d.ts.map +1 -0
- package/dist/components/PageHeader/PageHeader.d.ts.map +1 -1
- package/dist/components/PageHeader/PageHeader.model.d.ts +2 -0
- package/dist/components/PageHeader/PageHeader.model.d.ts.map +1 -1
- package/dist/hooks/useTabTitle/useTabTitle.d.ts +2 -0
- package/dist/hooks/useTabTitle/useTabTitle.d.ts.map +1 -0
- package/dist/index.es.js +4 -4
- 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 +2 -0
- package/dist/initialize.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/EmptyStation/EmptyStation.stories.tsx +1 -0
- package/src/components/Explorer/Explorer.stories.tsx +4 -0
- package/src/components/Explorer/Explorer.tsx +5 -0
- package/src/components/Explorer/NavigationExplorer/NavigationExplorer.tsx +2 -1
- package/src/components/Explorer/SelectionExplorer/SelectionExplorer.tsx +6 -1
- package/src/components/FormStation/Create/Create.stories.tsx +1 -1
- package/src/components/FormStation/FormStation.spec.tsx +2 -1
- package/src/components/FormStation/FormStation.stories.tsx +1 -0
- package/src/components/FormStation/FormStation.tsx +4 -0
- package/src/components/FormStation/FormStationHeader/FormStationHeader.tsx +6 -5
- package/src/components/FormStation/helpers/useDataProvider.ts +13 -1
- package/src/components/FormStation/helpers/useTitle.spec.ts +52 -0
- package/src/components/FormStation/helpers/useTitle.ts +20 -0
- package/src/components/PageHeader/PageHeader.model.ts +2 -0
- package/src/components/PageHeader/PageHeader.tsx +4 -0
- package/src/hooks/useTabTitle/useTabTitle.spec.tsx +39 -0
- package/src/hooks/useTabTitle/useTabTitle.tsx +13 -0
- package/src/initialize.ts +4 -0
- package/dist/common/assertError.d.ts +0 -13
- package/dist/common/assertError.d.ts.map +0 -1
- package/src/common/assert-error.spec.ts +0 -61
- package/src/common/assertError.ts +0 -33
package/dist/initialize.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare let addIndicator: AddIndicator | (() => void);
|
|
|
9
9
|
export declare let removeIndicator: RemoveIndicator | (() => void);
|
|
10
10
|
export declare let on: CustomEventEmitter['on'] | (() => void);
|
|
11
11
|
export declare let setSaveIndicator: (type: SaveIndicatorType) => void;
|
|
12
|
+
export declare let setTitle: (title?: string) => void;
|
|
12
13
|
/**
|
|
13
14
|
* Passes the PiralApi methods to the UI library.
|
|
14
15
|
* @param app {UiConfig} object containing PiralApi methods for use in UI library.
|
|
@@ -20,5 +21,6 @@ export interface UiConfig {
|
|
|
20
21
|
removeIndicator: RemoveIndicator;
|
|
21
22
|
on: CustomEventEmitter['on'];
|
|
22
23
|
setSaveIndicator: (type: SaveIndicatorType) => void;
|
|
24
|
+
setTitle: (title?: string) => void;
|
|
23
25
|
}
|
|
24
26
|
//# 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,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,
|
|
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,eAAO,IAAI,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,IAA2B,CAAC;AAErE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAShD;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;IACpD,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-ui",
|
|
3
|
-
"version": "0.43.0-rc.
|
|
3
|
+
"version": "0.43.0-rc.11",
|
|
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.16-rc.
|
|
35
|
+
"@axinom/mosaic-core": "^0.4.16-rc.11",
|
|
36
36
|
"@faker-js/faker": "^7.4.0",
|
|
37
37
|
"@popperjs/core": "^2.11.8",
|
|
38
38
|
"clsx": "^1.1.0",
|
|
@@ -105,5 +105,5 @@
|
|
|
105
105
|
"publishConfig": {
|
|
106
106
|
"access": "public"
|
|
107
107
|
},
|
|
108
|
-
"gitHead": "
|
|
108
|
+
"gitHead": "beba68da57c955c4c191acbeeb970e5b86e86ac6"
|
|
109
109
|
}
|
|
@@ -54,6 +54,7 @@ const groups = createGroups({
|
|
|
54
54
|
'onItemClicked',
|
|
55
55
|
'openBulkActionsOnStart',
|
|
56
56
|
'persistExplorerStates',
|
|
57
|
+
'setTabTitle',
|
|
57
58
|
],
|
|
58
59
|
Styling: [
|
|
59
60
|
'className',
|
|
@@ -251,6 +252,9 @@ initializeUi({
|
|
|
251
252
|
on: (event, callback) => {
|
|
252
253
|
action('on')(event, callback);
|
|
253
254
|
},
|
|
255
|
+
setTitle: (args) => {
|
|
256
|
+
action('setTitle')(args);
|
|
257
|
+
},
|
|
254
258
|
});
|
|
255
259
|
|
|
256
260
|
export const ActionErrors: StoryObj<ExplorerStoryType> = {
|
|
@@ -124,6 +124,9 @@ export interface ExplorerProps<T extends Data> {
|
|
|
124
124
|
/** Sets the default sort order for the Explorer. (default: undefined) */
|
|
125
125
|
defaultSortOrder?: SortData<T>;
|
|
126
126
|
|
|
127
|
+
/** Update the tab title using the 'title' field. (default: true) */
|
|
128
|
+
setTabTitle?: boolean;
|
|
129
|
+
|
|
127
130
|
/**
|
|
128
131
|
* When set, this function is used to generate the link that the user should be navigated to for each item.
|
|
129
132
|
*
|
|
@@ -196,6 +199,7 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
|
|
|
196
199
|
className = '',
|
|
197
200
|
|
|
198
201
|
defaultSortOrder,
|
|
202
|
+
setTabTitle = true,
|
|
199
203
|
|
|
200
204
|
onItemClicked,
|
|
201
205
|
onBulkActionsToggled = noop,
|
|
@@ -423,6 +427,7 @@ export const Explorer = React.forwardRef(function Explorer<T extends Data>(
|
|
|
423
427
|
setIsBulkOpen(isOpen);
|
|
424
428
|
onBulkActionsToggled(isOpen);
|
|
425
429
|
}}
|
|
430
|
+
setTabTitle={setTabTitle}
|
|
426
431
|
/>
|
|
427
432
|
{StationMessage}
|
|
428
433
|
<Filters<T>
|
|
@@ -9,7 +9,7 @@ import { ExplorerDataProviderConnection } from '../Explorer.model';
|
|
|
9
9
|
export interface NavigationExplorerProps<T extends Data>
|
|
10
10
|
extends Omit<
|
|
11
11
|
ExplorerProps<T>,
|
|
12
|
-
'selectionMode' | 'onBulkActionsToggled' | 'onItemClicked'
|
|
12
|
+
'selectionMode' | 'onBulkActionsToggled' | 'onItemClicked' | 'setTabTitle'
|
|
13
13
|
> {
|
|
14
14
|
/**
|
|
15
15
|
* - If a `LocationDescriptor` is provided, it will be treated as a path to the station to
|
|
@@ -54,6 +54,7 @@ export const NavigationExplorer = React.forwardRef(function NavigationExplorer<
|
|
|
54
54
|
<Explorer<T>
|
|
55
55
|
{...rest}
|
|
56
56
|
ref={ref}
|
|
57
|
+
setTabTitle={true}
|
|
57
58
|
actions={[
|
|
58
59
|
...actions,
|
|
59
60
|
...(onCreateAction && typeof onCreateAction !== 'function'
|
|
@@ -15,7 +15,11 @@ import {
|
|
|
15
15
|
export interface SelectionExplorerProps<T extends Data>
|
|
16
16
|
extends Omit<
|
|
17
17
|
ExplorerProps<T>,
|
|
18
|
-
|
|
18
|
+
| 'selectionMode'
|
|
19
|
+
| 'onItemClicked'
|
|
20
|
+
| 'onBulkActionsToggled'
|
|
21
|
+
| 'bulkActions'
|
|
22
|
+
| 'setTabTitle'
|
|
19
23
|
> {
|
|
20
24
|
/** Whether or not the selection of multiple items is allowed (default: false) */
|
|
21
25
|
allowBulkSelect?: boolean;
|
|
@@ -79,6 +83,7 @@ export const SelectionExplorer = React.forwardRef(function SelectionExplorer<
|
|
|
79
83
|
{...rest}
|
|
80
84
|
ref={ref}
|
|
81
85
|
modalMode={modalMode}
|
|
86
|
+
setTabTitle={false}
|
|
82
87
|
bulkActions={[
|
|
83
88
|
...(allowBulkSelect
|
|
84
89
|
? [
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
TagsField,
|
|
14
14
|
} from '../../FormElements';
|
|
15
15
|
import { FileUploadField } from '../../FormElements/FileUploadControl/FileUploadField';
|
|
16
|
-
import { ObjectSchemaDefinition } from '../FormStation';
|
|
16
|
+
import { ObjectSchemaDefinition } from '../FormStation.models';
|
|
17
17
|
import { Create } from './Create';
|
|
18
18
|
|
|
19
19
|
interface CreateValues {
|
|
@@ -10,7 +10,8 @@ import { ActionData, Actions } from '../Actions';
|
|
|
10
10
|
import { Action } from '../Actions/Action';
|
|
11
11
|
import { MessageBar } from '../MessageBar/MessageBar';
|
|
12
12
|
import { PageHeader, PageHeaderAction } from '../PageHeader';
|
|
13
|
-
import { FormStation
|
|
13
|
+
import { FormStation } from './FormStation';
|
|
14
|
+
import { ObjectSchemaDefinition } from './FormStation.models';
|
|
14
15
|
import { SaveOnNavigate } from './SaveOnNavigate/SaveOnNavigate';
|
|
15
16
|
|
|
16
17
|
jest.mock('../../initialize');
|
|
@@ -56,6 +56,8 @@ export interface FormStationProps<
|
|
|
56
56
|
* @example stationMessage={{type: 'info', message: 'Informative message.'}}
|
|
57
57
|
*/
|
|
58
58
|
stationMessage?: StationMessage;
|
|
59
|
+
/** Update the tab title using the 'titleProperty' or 'defaultTitle' field. (default: true) */
|
|
60
|
+
setTabTitle?: boolean;
|
|
59
61
|
/**
|
|
60
62
|
* Called whenever the form needs to be saved.
|
|
61
63
|
* This method needs to throw an exception in case the saving did not succeed.
|
|
@@ -82,6 +84,7 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
82
84
|
alwaysSubmitBeforeAction = false,
|
|
83
85
|
stationMessage,
|
|
84
86
|
className = '',
|
|
87
|
+
setTabTitle = true,
|
|
85
88
|
}: PropsWithChildren<
|
|
86
89
|
FormStationProps<TValues, TSubmitResponse>
|
|
87
90
|
>): JSX.Element => {
|
|
@@ -123,6 +126,7 @@ export const FormStation = <TValues extends Data, TSubmitResponse = unknown>({
|
|
|
123
126
|
subtitle={subtitle}
|
|
124
127
|
cancelNavigationUrl={cancelNavigationUrl}
|
|
125
128
|
className={classes.header}
|
|
129
|
+
setTabTitle={setTabTitle}
|
|
126
130
|
/>
|
|
127
131
|
<SaveOnNavigate
|
|
128
132
|
isSubmitting={isFormSubmitting}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
PageHeaderActionType,
|
|
9
9
|
PageHeaderProps,
|
|
10
10
|
} from '../../PageHeader';
|
|
11
|
+
import { useTitle } from '../helpers/useTitle';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Handles showRefresh and cancel buttons based on form states
|
|
@@ -17,6 +18,7 @@ export const FormStationHeader: React.FC<
|
|
|
17
18
|
titleProperty?: string;
|
|
18
19
|
defaultTitle?: string;
|
|
19
20
|
cancelNavigationUrl?: string;
|
|
21
|
+
setTabTitle?: boolean;
|
|
20
22
|
}
|
|
21
23
|
> = ({
|
|
22
24
|
titleProperty,
|
|
@@ -24,8 +26,9 @@ export const FormStationHeader: React.FC<
|
|
|
24
26
|
subtitle,
|
|
25
27
|
cancelNavigationUrl,
|
|
26
28
|
className,
|
|
29
|
+
setTabTitle,
|
|
27
30
|
}) => {
|
|
28
|
-
const { dirty, resetForm
|
|
31
|
+
const { dirty, resetForm } = useFormikContext<FormikValues>();
|
|
29
32
|
|
|
30
33
|
useEffect(() => {
|
|
31
34
|
// Set the save indicator to dirty depending on the form state
|
|
@@ -44,16 +47,14 @@ export const FormStationHeader: React.FC<
|
|
|
44
47
|
|
|
45
48
|
const history = useHistory();
|
|
46
49
|
|
|
47
|
-
const title =
|
|
48
|
-
titleProperty && values[titleProperty] !== ''
|
|
49
|
-
? values[titleProperty]
|
|
50
|
-
: defaultTitle ?? '';
|
|
50
|
+
const title = useTitle(titleProperty, defaultTitle);
|
|
51
51
|
|
|
52
52
|
return (
|
|
53
53
|
<PageHeader
|
|
54
54
|
title={title}
|
|
55
55
|
subtitle={subtitle}
|
|
56
56
|
className={className}
|
|
57
|
+
setTabTitle={setTabTitle}
|
|
57
58
|
actions={[
|
|
58
59
|
...(dirty === true // add undo action if form as been altered
|
|
59
60
|
? [
|
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
useRef,
|
|
8
8
|
useState,
|
|
9
9
|
} from 'react';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
SaveIndicatorType,
|
|
12
|
+
setSaveIndicator,
|
|
13
|
+
showNotification,
|
|
14
|
+
} from '../../../initialize';
|
|
11
15
|
import { Data } from '../../../types';
|
|
12
16
|
import { ErrorTypeToStationError } from '../../../utils/ErrorTypeToStationError';
|
|
13
17
|
import { ErrorType } from '../../models';
|
|
@@ -91,6 +95,14 @@ export const useDataProvider: FormStationDataProvider = <
|
|
|
91
95
|
if (response) {
|
|
92
96
|
lastSubmittedResponse.current = response;
|
|
93
97
|
}
|
|
98
|
+
|
|
99
|
+
showNotification({
|
|
100
|
+
title: 'Your changes were saved successfully.',
|
|
101
|
+
options: {
|
|
102
|
+
type: 'success',
|
|
103
|
+
autoClose: 1500,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
94
106
|
}
|
|
95
107
|
} catch (error) {
|
|
96
108
|
setStationError(
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useFormikContext } from 'formik';
|
|
2
|
+
import { useTitle } from './useTitle';
|
|
3
|
+
|
|
4
|
+
jest.mock('formik', () => ({
|
|
5
|
+
useFormikContext: jest.fn(),
|
|
6
|
+
}));
|
|
7
|
+
|
|
8
|
+
describe('useTitle', () => {
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
jest.clearAllMocks();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should return default title when titleProperty is not provided', () => {
|
|
14
|
+
const defaultTitle = 'Default Title';
|
|
15
|
+
(useFormikContext as jest.Mock).mockReturnValueOnce({});
|
|
16
|
+
|
|
17
|
+
const result = useTitle(undefined, defaultTitle);
|
|
18
|
+
|
|
19
|
+
expect(result).toBe(defaultTitle);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return title from formik context when titleProperty is provided', () => {
|
|
23
|
+
const titleProperty = 'title';
|
|
24
|
+
const titleValue = 'Form Title';
|
|
25
|
+
(useFormikContext as jest.Mock).mockReturnValueOnce({
|
|
26
|
+
values: { [titleProperty]: titleValue },
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const result = useTitle(titleProperty);
|
|
30
|
+
|
|
31
|
+
expect(result).toBe(titleValue);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return default title when titleProperty is provided but not found in formik context', () => {
|
|
35
|
+
const titleProperty = 'title';
|
|
36
|
+
const defaultTitle = 'Default Title';
|
|
37
|
+
(useFormikContext as jest.Mock).mockReturnValueOnce({ values: {} });
|
|
38
|
+
|
|
39
|
+
const result = useTitle(titleProperty, defaultTitle);
|
|
40
|
+
|
|
41
|
+
expect(result).toBe(defaultTitle);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should prepend an * when dirty is true', () => {
|
|
45
|
+
const defaultTitle = 'Default Title';
|
|
46
|
+
(useFormikContext as jest.Mock).mockReturnValueOnce({ dirty: true });
|
|
47
|
+
|
|
48
|
+
const result = useTitle(undefined, defaultTitle);
|
|
49
|
+
|
|
50
|
+
expect(result).toBe(`*${defaultTitle}`);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useFormikContext } from 'formik';
|
|
2
|
+
import { Data } from '../../../types';
|
|
3
|
+
|
|
4
|
+
export const useTitle = <TValues extends Data>(
|
|
5
|
+
titleProperty?: string,
|
|
6
|
+
defaultTitle?: string,
|
|
7
|
+
): string | undefined => {
|
|
8
|
+
const { values, dirty } = useFormikContext<TValues>();
|
|
9
|
+
|
|
10
|
+
const title: string | undefined =
|
|
11
|
+
titleProperty && values[titleProperty] !== '' && values[titleProperty]
|
|
12
|
+
? values[titleProperty]
|
|
13
|
+
: defaultTitle ?? '';
|
|
14
|
+
|
|
15
|
+
if (dirty) {
|
|
16
|
+
return `*${title}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return title;
|
|
20
|
+
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import React, { useEffect, useState } from 'react';
|
|
3
3
|
import { noop } from '../../helpers/utils';
|
|
4
|
+
import { useTabTitle } from '../../hooks/useTabTitle/useTabTitle';
|
|
4
5
|
import { useWindowSize } from '../../hooks/useWindowSize/useWindowSize';
|
|
5
6
|
import { PageHeaderProps } from './PageHeader.model';
|
|
6
7
|
import classes from './PageHeader.scss';
|
|
@@ -21,6 +22,7 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
|
|
|
21
22
|
openBulkActionsOnStart = false,
|
|
22
23
|
onBulkActionsToggled = noop,
|
|
23
24
|
className = '',
|
|
25
|
+
setTabTitle = true,
|
|
24
26
|
}) => {
|
|
25
27
|
const [containerScrollWidth, setContainerScrollWidth] = useState<number>(0);
|
|
26
28
|
const [childrenScrollWidth, setChildrenScrollWidth] = useState<number>(0);
|
|
@@ -39,6 +41,8 @@ export const PageHeader: React.FC<PageHeaderProps> = ({
|
|
|
39
41
|
}
|
|
40
42
|
};
|
|
41
43
|
|
|
44
|
+
useTabTitle(title, setTabTitle);
|
|
45
|
+
|
|
42
46
|
useEffect(() => {
|
|
43
47
|
// only perform calculation if there are bulkActions
|
|
44
48
|
if (bulkActions.length > 0) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { mount } from 'enzyme';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { setTitle } from '../../initialize';
|
|
4
|
+
import { useTabTitle } from './useTabTitle';
|
|
5
|
+
|
|
6
|
+
jest.mock('../../initialize');
|
|
7
|
+
|
|
8
|
+
const TestWrapper: React.FC<{ title?: string; setTabTitle: boolean }> = ({
|
|
9
|
+
title,
|
|
10
|
+
setTabTitle,
|
|
11
|
+
}) => {
|
|
12
|
+
useTabTitle(title, setTabTitle);
|
|
13
|
+
|
|
14
|
+
return null;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
describe('useTabTitle', () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
jest.resetAllMocks();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should set the title when setTabTitle is true', () => {
|
|
23
|
+
const title = 'Test Title';
|
|
24
|
+
const setTabTitle = true;
|
|
25
|
+
|
|
26
|
+
mount(<TestWrapper title={title} setTabTitle={setTabTitle} />);
|
|
27
|
+
|
|
28
|
+
expect(setTitle).toHaveBeenCalledWith('Test Title');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should not set the title when setTabTitle is false', () => {
|
|
32
|
+
const title = 'Test Title';
|
|
33
|
+
const setTabTitle = false;
|
|
34
|
+
|
|
35
|
+
mount(<TestWrapper title={title} setTabTitle={setTabTitle} />);
|
|
36
|
+
|
|
37
|
+
expect(setTitle).not.toHaveBeenCalled();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { setTitle } from '../../initialize';
|
|
3
|
+
|
|
4
|
+
export const useTabTitle = (
|
|
5
|
+
title: string | undefined,
|
|
6
|
+
setTabTitle: boolean | undefined,
|
|
7
|
+
): void => {
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (setTabTitle) {
|
|
10
|
+
setTitle(title);
|
|
11
|
+
}
|
|
12
|
+
}, [setTabTitle, title]);
|
|
13
|
+
};
|
package/src/initialize.ts
CHANGED
|
@@ -24,6 +24,8 @@ export let on: CustomEventEmitter['on'] | (() => void) = polyfill('on');
|
|
|
24
24
|
export let setSaveIndicator: (type: SaveIndicatorType) => void =
|
|
25
25
|
polyfill('setSaveIndicator');
|
|
26
26
|
|
|
27
|
+
export let setTitle: (title?: string) => void = polyfill('setTitle');
|
|
28
|
+
|
|
27
29
|
/**
|
|
28
30
|
* Passes the PiralApi methods to the UI library.
|
|
29
31
|
* @param app {UiConfig} object containing PiralApi methods for use in UI library.
|
|
@@ -35,6 +37,7 @@ export function initializeUi(app: UiConfig): void {
|
|
|
35
37
|
removeIndicator = polyfill('removeIndicator'),
|
|
36
38
|
on = polyfill('on'),
|
|
37
39
|
setSaveIndicator = polyfill('setSaveIndicator'),
|
|
40
|
+
setTitle = polyfill('setTitle'),
|
|
38
41
|
} = app);
|
|
39
42
|
}
|
|
40
43
|
|
|
@@ -44,6 +47,7 @@ export interface UiConfig {
|
|
|
44
47
|
removeIndicator: RemoveIndicator;
|
|
45
48
|
on: CustomEventEmitter['on'];
|
|
46
49
|
setSaveIndicator: (type: SaveIndicatorType) => void;
|
|
50
|
+
setTitle: (title?: string) => void;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
function polyfill(methodName: string): () => void {
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { ErrorType } from '../components/models';
|
|
2
|
-
/**
|
|
3
|
-
* Type assertion function that throws an error if provided parameter is not an instance of an Error, and asserts value to an Error type if no error is thrown.
|
|
4
|
-
* This is a copy of assertError() in @axinom/service-common to avoid dependencies.
|
|
5
|
-
*/
|
|
6
|
-
export declare const assertError: (error: unknown) => asserts error is Error;
|
|
7
|
-
/**
|
|
8
|
-
* Asserts if the passed error is of ErrorType.
|
|
9
|
-
*
|
|
10
|
-
* @param error error object of type unknown
|
|
11
|
-
*/
|
|
12
|
-
export declare const assertErrorType: (error: unknown) => asserts error is ErrorType;
|
|
13
|
-
//# sourceMappingURL=assertError.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"assertError.d.ts","sourceRoot":"","sources":["../../src/common/assertError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgB,MAAM,sBAAsB,CAAC;AAE/D;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,KAAK,IAAI,KAM9D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,KAAK,IAAI,SAalE,CAAC"}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/* eslint-disable jest/no-conditional-expect */
|
|
2
|
-
import 'jest-extended';
|
|
3
|
-
import { StationError } from '../components/models';
|
|
4
|
-
import { assertError, assertErrorType } from './assertError';
|
|
5
|
-
|
|
6
|
-
describe('assertError', () => {
|
|
7
|
-
it('StationError type error is thrown -> ErrorType asserted', async () => {
|
|
8
|
-
try {
|
|
9
|
-
throw {
|
|
10
|
-
title: 'test title',
|
|
11
|
-
body: 'test body',
|
|
12
|
-
};
|
|
13
|
-
} catch (error) {
|
|
14
|
-
assertErrorType(error);
|
|
15
|
-
expect((error as StationError).title).toBe('test title');
|
|
16
|
-
expect((error as StationError).body).toBe('test body');
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('Error is thrown -> ErrorType asserted', async () => {
|
|
21
|
-
try {
|
|
22
|
-
throw new Error('test error');
|
|
23
|
-
} catch (error) {
|
|
24
|
-
assertErrorType(error);
|
|
25
|
-
expect((error as Error).message).toBe('test error');
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('string is thrown -> ErrorType asserted', async () => {
|
|
30
|
-
try {
|
|
31
|
-
throw 'test error';
|
|
32
|
-
} catch (error) {
|
|
33
|
-
assertErrorType(error);
|
|
34
|
-
expect(error as string).toBe('test error');
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('error-like object is thrown -> ErrorType asserted', async () => {
|
|
39
|
-
try {
|
|
40
|
-
throw { message: 'test error' };
|
|
41
|
-
} catch (error) {
|
|
42
|
-
assertErrorType(error);
|
|
43
|
-
expect(Object(error).message).toBe('test error');
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('number is thrown -> ErrorType assertion failed', async () => {
|
|
48
|
-
try {
|
|
49
|
-
throw 123;
|
|
50
|
-
} catch (error) {
|
|
51
|
-
try {
|
|
52
|
-
assertErrorType(error);
|
|
53
|
-
} catch (assertionError) {
|
|
54
|
-
assertError(assertionError);
|
|
55
|
-
expect(assertionError.message).toBe(
|
|
56
|
-
'The caught error is not an instance of ErrorType.',
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { ErrorType, StationError } from '../components/models';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Type assertion function that throws an error if provided parameter is not an instance of an Error, and asserts value to an Error type if no error is thrown.
|
|
5
|
-
* This is a copy of assertError() in @axinom/service-common to avoid dependencies.
|
|
6
|
-
*/
|
|
7
|
-
export const assertError: (error: unknown) => asserts error is Error = (
|
|
8
|
-
error: unknown,
|
|
9
|
-
): asserts error is Error => {
|
|
10
|
-
if (!(error instanceof Error)) {
|
|
11
|
-
throw new Error('A caught error is not an instance of an Error class.');
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Asserts if the passed error is of ErrorType.
|
|
17
|
-
*
|
|
18
|
-
* @param error error object of type unknown
|
|
19
|
-
*/
|
|
20
|
-
export const assertErrorType: (error: unknown) => asserts error is ErrorType = (
|
|
21
|
-
error: unknown,
|
|
22
|
-
): asserts error is ErrorType => {
|
|
23
|
-
if (
|
|
24
|
-
!(
|
|
25
|
-
error instanceof Error ||
|
|
26
|
-
typeof error === 'string' ||
|
|
27
|
-
(error as StationError).title !== undefined ||
|
|
28
|
-
error instanceof Object
|
|
29
|
-
)
|
|
30
|
-
) {
|
|
31
|
-
throw new Error('The caught error is not an instance of ErrorType.');
|
|
32
|
-
}
|
|
33
|
-
};
|