@axinom/mosaic-ui 0.43.0-rc.9 → 0.43.1
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/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.spec.tsx +3 -1
- package/src/components/EmptyStation/EmptyStation.stories.tsx +1 -0
- package/src/components/Explorer/Explorer.spec.tsx +2 -0
- package/src/components/Explorer/Explorer.stories.tsx +4 -0
- package/src/components/Explorer/Explorer.tsx +5 -0
- package/src/components/Explorer/NavigationExplorer/NavigationExplorer.spec.tsx +2 -0
- package/src/components/Explorer/NavigationExplorer/NavigationExplorer.tsx +2 -1
- package/src/components/Explorer/SelectionExplorer/SelectionExplorer.spec.tsx +2 -0
- 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/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.spec.tsx +2 -0
- package/src/components/PageHeader/PageHeader.tsx +4 -0
- package/src/hooks/useTabTitle/useTabTitle.spec.tsx +84 -0
- package/src/hooks/useTabTitle/useTabTitle.tsx +15 -0
- package/src/initialize.ts +4 -0
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.
|
|
3
|
+
"version": "0.43.1",
|
|
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
|
|
35
|
+
"@axinom/mosaic-core": "^0.4.16",
|
|
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": "6df139c63de76d40be27d5a49ec2f159c15657dd"
|
|
109
109
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { mount, shallow } from 'enzyme';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { MessageBar } from '../MessageBar';
|
|
4
|
-
import { StationError } from '../models';
|
|
5
4
|
import { PageHeader } from '../PageHeader';
|
|
5
|
+
import { StationError } from '../models';
|
|
6
6
|
import { EmptyStation, EmptyStationProps } from './EmptyStation';
|
|
7
7
|
|
|
8
|
+
jest.mock('../../hooks/useTabTitle/useTabTitle');
|
|
9
|
+
|
|
8
10
|
describe('EmptyStation', () => {
|
|
9
11
|
const defaultProps: EmptyStationProps = {
|
|
10
12
|
title: 'test-title',
|
|
@@ -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>
|
|
@@ -12,6 +12,8 @@ import { Explorer } from '../Explorer';
|
|
|
12
12
|
import { ExplorerDataProvider } from '../Explorer.model';
|
|
13
13
|
import { NavigationExplorer } from './NavigationExplorer';
|
|
14
14
|
|
|
15
|
+
jest.mock('../../../hooks/useTabTitle/useTabTitle');
|
|
16
|
+
|
|
15
17
|
interface NavExplorerTestData {
|
|
16
18
|
id: string;
|
|
17
19
|
desc: string;
|
|
@@ -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'
|
|
@@ -11,6 +11,8 @@ import { Explorer } from '../Explorer';
|
|
|
11
11
|
import { ExplorerDataProvider } from '../Explorer.model';
|
|
12
12
|
import { SelectionExplorer } from './SelectionExplorer';
|
|
13
13
|
|
|
14
|
+
jest.mock('../../../hooks/useTabTitle/useTabTitle');
|
|
15
|
+
|
|
14
16
|
interface SelectExplorerTestData {
|
|
15
17
|
id: string;
|
|
16
18
|
desc: string;
|
|
@@ -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
|
? [
|
|
@@ -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
|
+
};
|
|
@@ -6,6 +6,8 @@ import { PageHeaderAction } from './PageHeaderAction/PageHeaderAction';
|
|
|
6
6
|
import { PageHeaderActionProps } from './PageHeaderAction/PageHeaderAction.model';
|
|
7
7
|
import { PageHeaderBulkActions } from './PageHeaderBulkActions/PageHeaderBulkActions';
|
|
8
8
|
|
|
9
|
+
jest.mock('../../hooks/useTabTitle/useTabTitle');
|
|
10
|
+
|
|
9
11
|
const defaultbulkActions: PageHeaderActionProps[] = [
|
|
10
12
|
{
|
|
11
13
|
label: 'Bulk Action 1',
|
|
@@ -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,84 @@
|
|
|
1
|
+
import { mount } from 'enzyme';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4
|
+
import { useHistory } from 'react-router-dom';
|
|
5
|
+
import { setTitle } from '../../initialize';
|
|
6
|
+
import { useTabTitle } from './useTabTitle';
|
|
7
|
+
|
|
8
|
+
jest.mock('../../initialize');
|
|
9
|
+
jest.mock('react-router-dom');
|
|
10
|
+
|
|
11
|
+
const TestWrapper: React.FC<{ title?: string; setTabTitle: boolean }> = ({
|
|
12
|
+
title,
|
|
13
|
+
setTabTitle,
|
|
14
|
+
}) => {
|
|
15
|
+
useTabTitle(title, setTabTitle);
|
|
16
|
+
|
|
17
|
+
return null;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
describe('useTabTitle', () => {
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
jest.clearAllMocks();
|
|
23
|
+
(useHistory as jest.Mock) = jest.fn().mockReturnValue({
|
|
24
|
+
location: {
|
|
25
|
+
pathname: '/test',
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should set the tab title when setTabTitle is true', () => {
|
|
31
|
+
const firstTitle = 'First Title';
|
|
32
|
+
const secondTitle = 'Second Title';
|
|
33
|
+
|
|
34
|
+
const setTabTitle = true;
|
|
35
|
+
|
|
36
|
+
const wrapper = mount(
|
|
37
|
+
<TestWrapper title={firstTitle} setTabTitle={setTabTitle} />,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
expect(setTitle).toHaveBeenCalledWith(firstTitle);
|
|
41
|
+
|
|
42
|
+
wrapper.setProps({ title: secondTitle });
|
|
43
|
+
|
|
44
|
+
expect(setTitle).toHaveBeenNthCalledWith(2, secondTitle);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should not set the tab title when setTabTitle is false', () => {
|
|
48
|
+
const title = 'Test Title';
|
|
49
|
+
const setTabTitle = false;
|
|
50
|
+
|
|
51
|
+
mount(<TestWrapper title={title} setTabTitle={setTabTitle} />);
|
|
52
|
+
|
|
53
|
+
expect(setTitle).not.toHaveBeenCalled();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should not set the tab title when the URL has changed', () => {
|
|
57
|
+
(useHistory as jest.Mock) = jest
|
|
58
|
+
.fn()
|
|
59
|
+
.mockReturnValueOnce({
|
|
60
|
+
location: {
|
|
61
|
+
pathname: '/test',
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
.mockReturnValueOnce({
|
|
65
|
+
location: {
|
|
66
|
+
pathname: '/test2',
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const firstTitle = 'First Title';
|
|
71
|
+
const secondTitle = 'Second Title';
|
|
72
|
+
const setTabTitle = true;
|
|
73
|
+
|
|
74
|
+
const wrapper = mount(
|
|
75
|
+
<TestWrapper title={firstTitle} setTabTitle={setTabTitle} />,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(setTitle).toHaveBeenCalledWith(firstTitle);
|
|
79
|
+
|
|
80
|
+
wrapper.setProps({ title: secondTitle });
|
|
81
|
+
|
|
82
|
+
expect(setTitle).toHaveBeenCalledTimes(1);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { useHistory } from 'react-router-dom';
|
|
3
|
+
import { setTitle } from '../../initialize';
|
|
4
|
+
|
|
5
|
+
export const useTabTitle = (
|
|
6
|
+
title: string | undefined,
|
|
7
|
+
setTabTitle: boolean | undefined,
|
|
8
|
+
): void => {
|
|
9
|
+
const { location: currentLocation } = useHistory();
|
|
10
|
+
const [initialLocation] = useState(currentLocation);
|
|
11
|
+
|
|
12
|
+
if (setTabTitle && currentLocation.pathname === initialLocation.pathname) {
|
|
13
|
+
setTitle(title);
|
|
14
|
+
}
|
|
15
|
+
};
|
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 {
|