@squiz/resource-browser 3.3.9 → 3.3.10
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/CHANGELOG.md +8 -0
- package/lib/index.js +20 -4
- package/lib/types.d.ts +1 -0
- package/package.json +2 -2
- package/src/__mocks__/sample-sources.json +2 -1
- package/src/index.spec.tsx +129 -0
- package/src/index.stories.tsx +9 -0
- package/src/index.tsx +23 -5
- package/src/types.ts +3 -0
package/CHANGELOG.md
CHANGED
package/lib/index.js
CHANGED
|
@@ -64,6 +64,23 @@ exports.ResourceBrowser = react_1.default.forwardRef((props, forwardRef) => {
|
|
|
64
64
|
const [mode, setMode] = (0, react_1.useState)(null);
|
|
65
65
|
const { data: sources, isLoading, error: sourcesError, reload: reloadSources } = (0, useSources_1.useSources)({ onRequestSources, plugins });
|
|
66
66
|
const plugin = source?.plugin || null;
|
|
67
|
+
// Find source by its id or alias
|
|
68
|
+
const findSourceById = (value, sources) => {
|
|
69
|
+
let newSource = sources.find((source) => source.id === value?.sourceId) || null;
|
|
70
|
+
if (!newSource) {
|
|
71
|
+
newSource =
|
|
72
|
+
sources.find((source) => {
|
|
73
|
+
if (!source.aliases)
|
|
74
|
+
return false;
|
|
75
|
+
return source.aliases.includes(value.sourceId);
|
|
76
|
+
}) || null;
|
|
77
|
+
}
|
|
78
|
+
return newSource;
|
|
79
|
+
};
|
|
80
|
+
// Check if the value is for the source
|
|
81
|
+
const isValueForSource = (value, source) => {
|
|
82
|
+
return value?.sourceId === source.id || (source.aliases && source.aliases.includes(value?.sourceId));
|
|
83
|
+
};
|
|
67
84
|
// MainContainer will render a list of sources of one is not provided to it, callback to allow it to set the source once a user selects
|
|
68
85
|
const handleSourceSelect = (0, react_1.useCallback)((source, mode) => {
|
|
69
86
|
setSource(source);
|
|
@@ -79,7 +96,7 @@ exports.ResourceBrowser = react_1.default.forwardRef((props, forwardRef) => {
|
|
|
79
96
|
// If there is a provided value try to use its source
|
|
80
97
|
if (value) {
|
|
81
98
|
// Search the sources for it matching against the value.source property
|
|
82
|
-
newSource =
|
|
99
|
+
newSource = findSourceById(value, sources);
|
|
83
100
|
// If the source is null and we arent loading the sources
|
|
84
101
|
if (newSource === null && !isLoading) {
|
|
85
102
|
// Set an error as the passed in value's source wasnt returned by onRequestSources
|
|
@@ -110,8 +127,7 @@ exports.ResourceBrowser = react_1.default.forwardRef((props, forwardRef) => {
|
|
|
110
127
|
setMode(null);
|
|
111
128
|
// If there is a value passed in, reset the source so the preselected asset preview renders correctly
|
|
112
129
|
if (value && value.sourceId !== source?.id) {
|
|
113
|
-
|
|
114
|
-
setSource(source);
|
|
130
|
+
setSource(findSourceById(value, sources));
|
|
115
131
|
}
|
|
116
132
|
}
|
|
117
133
|
}, [sources, isModalOpen]);
|
|
@@ -129,6 +145,6 @@ exports.ResourceBrowser = react_1.default.forwardRef((props, forwardRef) => {
|
|
|
129
145
|
};
|
|
130
146
|
}, isModalOpen: isModalOpen, onModalStateChange: handleModalStateChange, onRetry: handleReset }),
|
|
131
147
|
plugins.map((thisPlugin) => {
|
|
132
|
-
return (react_1.default.createElement(Plugin_1.PluginRender, { key: thisPlugin.type, ref: forwardRef, type: thisPlugin.type, render: thisPlugin.type === plugin?.type, inline: !!inline, inlineType: inlineType, ...props, value: value && source ? (value
|
|
148
|
+
return (react_1.default.createElement(Plugin_1.PluginRender, { key: thisPlugin.type, ref: forwardRef, type: thisPlugin.type, render: thisPlugin.type === plugin?.type, inline: !!inline, inlineType: inlineType, ...props, value: value && source ? (isValueForSource(value, source) ? value : null) : null, isOtherSourceValue: value && source ? (!isValueForSource(value, source) ? true : false) : false, source: source, sources: sources, setSource: handleSourceSelect, isLoading: isLoading, error: sourcesError || error, plugin: plugin, pluginMode: mode, searchEnabled: searchEnabled, useResource: thisPlugin.useResolveResource, isModalOpen: isModalOpen, onModalStateChange: handleModalStateChange, onRetry: handleReset }));
|
|
133
149
|
})));
|
|
134
150
|
});
|
package/lib/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squiz/resource-browser",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.10",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"private": false,
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@react-types/shared": "^3.23.1",
|
|
29
29
|
"@squiz/dx-json-schema-lib": "^1.67.0",
|
|
30
30
|
"@squiz/generic-browser-lib": "^1.67.5",
|
|
31
|
-
"@squiz/resource-browser-ui-lib": "^1.2.
|
|
31
|
+
"@squiz/resource-browser-ui-lib": "^1.2.6",
|
|
32
32
|
"clsx": "^2.1.0",
|
|
33
33
|
"expiry-map": "^2.0.0",
|
|
34
34
|
"p-memoize": "^4.0.4",
|
package/src/index.spec.tsx
CHANGED
|
@@ -141,6 +141,24 @@ describe('Resource browser input', () => {
|
|
|
141
141
|
});
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
+
it('If an aliased resource is provided will default to its true Source and Plugin to match', async () => {
|
|
145
|
+
const source = mockSource({ type: 'dam', aliases: ['alias-source-id'] });
|
|
146
|
+
mockRequestSources.mockResolvedValueOnce([source, mockSource({ type: 'matrix' })]);
|
|
147
|
+
mockResolveResource.mockResolvedValueOnce(mockResource({ source }));
|
|
148
|
+
renderComponent({ value: { sourceId: 'alias-source-id', resourceId: '100' } });
|
|
149
|
+
|
|
150
|
+
await waitFor(() => {
|
|
151
|
+
expect(RBI.ResourceBrowserInput).toHaveBeenCalledWith(
|
|
152
|
+
expect.objectContaining({
|
|
153
|
+
source: calculateExpectedSource(source),
|
|
154
|
+
plugin: mockDamPlugin,
|
|
155
|
+
pluginMode: null,
|
|
156
|
+
}),
|
|
157
|
+
{},
|
|
158
|
+
);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
144
162
|
it('If a resource is provided but its Source cannot be found it will error', async () => {
|
|
145
163
|
const source = mockSource({ type: 'dam' });
|
|
146
164
|
mockRequestSources.mockResolvedValueOnce([source, mockSource({ type: 'matrix' })]);
|
|
@@ -510,6 +528,73 @@ describe('Resource browser input', () => {
|
|
|
510
528
|
});
|
|
511
529
|
});
|
|
512
530
|
|
|
531
|
+
it('onModalStateChange called with false will reset the Source and Plugin to the aliases true source if the value uses an alias', async () => {
|
|
532
|
+
const originalSource = mockSource({
|
|
533
|
+
id: 'original-source-id',
|
|
534
|
+
name: 'Original Source',
|
|
535
|
+
type: 'dam',
|
|
536
|
+
aliases: ['alias-source-id'],
|
|
537
|
+
});
|
|
538
|
+
const aliasSourceId = 'alias-source-id';
|
|
539
|
+
const valueWithAlias = {
|
|
540
|
+
sourceId: aliasSourceId,
|
|
541
|
+
resourceId: '123456',
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
const sourcesInput = [originalSource, mockSource({ id: '2' })];
|
|
545
|
+
const calculatedSources = sourcesInput.map((source) => calculateExpectedSource(source));
|
|
546
|
+
mockRequestSources.mockResolvedValueOnce(sourcesInput);
|
|
547
|
+
|
|
548
|
+
renderComponent({ value: valueWithAlias });
|
|
549
|
+
|
|
550
|
+
await waitFor(() => {
|
|
551
|
+
expect(RBI.ResourceBrowserInput).toHaveBeenCalledWith(
|
|
552
|
+
expect.objectContaining({
|
|
553
|
+
value: valueWithAlias,
|
|
554
|
+
sources: calculatedSources,
|
|
555
|
+
source: calculatedSources[0],
|
|
556
|
+
plugin: mockDamPlugin,
|
|
557
|
+
}),
|
|
558
|
+
{},
|
|
559
|
+
);
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
const { onModalStateChange, setSource } = (RBI.ResourceBrowserInput as unknown as jest.SpyInstance).mock.calls[0][0];
|
|
563
|
+
// Invoke open and close the modal
|
|
564
|
+
act(() => {
|
|
565
|
+
onModalStateChange(true);
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
// Change the source
|
|
569
|
+
act(() => {
|
|
570
|
+
setSource(calculatedSources[1]);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
await waitFor(() => {
|
|
574
|
+
expect(RBI.ResourceBrowserInput).toHaveBeenCalledWith(
|
|
575
|
+
expect.objectContaining({
|
|
576
|
+
source: calculatedSources[1],
|
|
577
|
+
plugin: mockDamPlugin,
|
|
578
|
+
}),
|
|
579
|
+
{},
|
|
580
|
+
);
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
act(() => {
|
|
584
|
+
onModalStateChange(false);
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
await waitFor(() => {
|
|
588
|
+
expect(RBI.ResourceBrowserInput).toHaveBeenLastCalledWith(
|
|
589
|
+
expect.objectContaining({
|
|
590
|
+
source: calculatedSources[0],
|
|
591
|
+
plugin: mockDamPlugin,
|
|
592
|
+
}),
|
|
593
|
+
{},
|
|
594
|
+
);
|
|
595
|
+
});
|
|
596
|
+
});
|
|
597
|
+
|
|
513
598
|
it('onModalStateChange called with false will reset the Mode', async () => {
|
|
514
599
|
const sourcesInput = [mockSource({ type: 'dam' }), mockSource()];
|
|
515
600
|
mockRequestSources.mockResolvedValueOnce(sourcesInput);
|
|
@@ -780,5 +865,49 @@ describe('Resource browser input', () => {
|
|
|
780
865
|
);
|
|
781
866
|
});
|
|
782
867
|
});
|
|
868
|
+
|
|
869
|
+
it('When resource browser is called with a value containing an alias source, Plugin is called with the original source not the alias value', async () => {
|
|
870
|
+
const originalSource = mockSource({
|
|
871
|
+
id: 'original-source-id',
|
|
872
|
+
name: 'Original Source',
|
|
873
|
+
type: 'dam',
|
|
874
|
+
aliases: ['alias-source-id'],
|
|
875
|
+
});
|
|
876
|
+
const aliasSourceId = 'alias-source-id';
|
|
877
|
+
|
|
878
|
+
mockRequestSources.mockResolvedValueOnce([originalSource]);
|
|
879
|
+
|
|
880
|
+
// Create a value that uses the alias source ID
|
|
881
|
+
const valueWithAlias = {
|
|
882
|
+
sourceId: aliasSourceId,
|
|
883
|
+
resourceId: '123456',
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
renderComponent({ value: valueWithAlias });
|
|
887
|
+
|
|
888
|
+
await waitFor(() => {
|
|
889
|
+
expect(RBI.ResourceBrowserInput).toHaveBeenCalledWith(
|
|
890
|
+
expect.objectContaining({
|
|
891
|
+
value: valueWithAlias,
|
|
892
|
+
source: calculateExpectedSource(originalSource), // Should be the original source, not alias
|
|
893
|
+
plugin: mockDamPlugin,
|
|
894
|
+
}),
|
|
895
|
+
{},
|
|
896
|
+
);
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
// Verify that the PluginRender is called with the original source
|
|
900
|
+
await waitFor(() => {
|
|
901
|
+
expect(PluginRenderSpy).toHaveBeenCalledWith(
|
|
902
|
+
expect.objectContaining({
|
|
903
|
+
render: true,
|
|
904
|
+
type: 'dam',
|
|
905
|
+
source: calculateExpectedSource(originalSource), // Should be the original source
|
|
906
|
+
isOtherSourceValue: false,
|
|
907
|
+
}),
|
|
908
|
+
null,
|
|
909
|
+
);
|
|
910
|
+
});
|
|
911
|
+
});
|
|
783
912
|
});
|
|
784
913
|
});
|
package/src/index.stories.tsx
CHANGED
|
@@ -103,6 +103,15 @@ RestrictedSource.args = {
|
|
|
103
103
|
searchEnabled: true,
|
|
104
104
|
};
|
|
105
105
|
|
|
106
|
+
export const SourceByAlias = Template.bind({});
|
|
107
|
+
SourceByAlias.args = {
|
|
108
|
+
...Primary.args,
|
|
109
|
+
value: {
|
|
110
|
+
resourceId: '1f7a25b4-380f-4540-9555-8be2dcab4019',
|
|
111
|
+
sourceId: 'bynder-789',
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
106
115
|
export const SearchEnabled = Template.bind({});
|
|
107
116
|
SearchEnabled.args = {
|
|
108
117
|
...Primary.args,
|
package/src/index.tsx
CHANGED
|
@@ -60,6 +60,24 @@ export const ResourceBrowser = React.forwardRef<HTMLButtonElement, ResourceBrows
|
|
|
60
60
|
const { data: sources, isLoading, error: sourcesError, reload: reloadSources } = useSources({ onRequestSources, plugins });
|
|
61
61
|
const plugin = source?.plugin || null;
|
|
62
62
|
|
|
63
|
+
// Find source by its id or alias
|
|
64
|
+
const findSourceById = (value: ResourceBrowserUnresolvedResource, sources: ResourceBrowserSourceWithPlugin[]) => {
|
|
65
|
+
let newSource = sources.find((source) => source.id === value?.sourceId) || null;
|
|
66
|
+
if (!newSource) {
|
|
67
|
+
newSource =
|
|
68
|
+
sources.find((source) => {
|
|
69
|
+
if (!source.aliases) return false;
|
|
70
|
+
return source.aliases.includes(value.sourceId);
|
|
71
|
+
}) || null;
|
|
72
|
+
}
|
|
73
|
+
return newSource;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Check if the value is for the source
|
|
77
|
+
const isValueForSource = (value: ResourceBrowserUnresolvedResource, source: ResourceBrowserSourceWithPlugin) => {
|
|
78
|
+
return value?.sourceId === source.id || (source.aliases && source.aliases.includes(value?.sourceId));
|
|
79
|
+
};
|
|
80
|
+
|
|
63
81
|
// MainContainer will render a list of sources of one is not provided to it, callback to allow it to set the source once a user selects
|
|
64
82
|
const handleSourceSelect = useCallback(
|
|
65
83
|
(source: ResourceBrowserSourceWithPlugin, mode?: PluginLaunchMode) => {
|
|
@@ -80,7 +98,8 @@ export const ResourceBrowser = React.forwardRef<HTMLButtonElement, ResourceBrows
|
|
|
80
98
|
// If there is a provided value try to use its source
|
|
81
99
|
if (value) {
|
|
82
100
|
// Search the sources for it matching against the value.source property
|
|
83
|
-
newSource =
|
|
101
|
+
newSource = findSourceById(value, sources);
|
|
102
|
+
|
|
84
103
|
// If the source is null and we arent loading the sources
|
|
85
104
|
if (newSource === null && !isLoading) {
|
|
86
105
|
// Set an error as the passed in value's source wasnt returned by onRequestSources
|
|
@@ -116,8 +135,7 @@ export const ResourceBrowser = React.forwardRef<HTMLButtonElement, ResourceBrows
|
|
|
116
135
|
|
|
117
136
|
// If there is a value passed in, reset the source so the preselected asset preview renders correctly
|
|
118
137
|
if (value && value.sourceId !== source?.id) {
|
|
119
|
-
|
|
120
|
-
setSource(source);
|
|
138
|
+
setSource(findSourceById(value, sources));
|
|
121
139
|
}
|
|
122
140
|
}
|
|
123
141
|
}, [sources, isModalOpen]);
|
|
@@ -168,8 +186,8 @@ export const ResourceBrowser = React.forwardRef<HTMLButtonElement, ResourceBrows
|
|
|
168
186
|
inline={!!inline}
|
|
169
187
|
inlineType={inlineType}
|
|
170
188
|
{...props}
|
|
171
|
-
value={value && source ? (value
|
|
172
|
-
isOtherSourceValue={value && source ? (value
|
|
189
|
+
value={value && source ? (isValueForSource(value, source) ? value : null) : null} // Don't pass value if value isn't for selected source
|
|
190
|
+
isOtherSourceValue={value && source ? (!isValueForSource(value, source) ? true : false) : false} // Block render of existing asset if not from this source
|
|
173
191
|
source={source}
|
|
174
192
|
sources={sources}
|
|
175
193
|
setSource={handleSourceSelect}
|
package/src/types.ts
CHANGED
|
@@ -19,6 +19,9 @@ export interface ResourceBrowserSource {
|
|
|
19
19
|
id: string;
|
|
20
20
|
// Source type e.g. Matrix, DAM etc determines what plugin will be used for resource selection
|
|
21
21
|
type: ResourceBrowserPluginType;
|
|
22
|
+
|
|
23
|
+
//alias' for the source to identify plugin to use for the source
|
|
24
|
+
aliases?: string[];
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
export interface ResourceBrowserSourceWithPlugin extends ResourceBrowserSource {
|