@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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.3.10
4
+
5
+ ### Patch Changes
6
+
7
+ - 8d3c8e0: source alias support
8
+ - Updated dependencies [8d3c8e0]
9
+ - @squiz/resource-browser-ui-lib@1.2.6
10
+
3
11
  ## 3.3.9
4
12
 
5
13
  ### Patch Changes
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 = sources.find((source) => source.id === value?.sourceId) || null;
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
- const source = sources.find((source) => source.id === value?.sourceId) || null;
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.sourceId === source.id ? value : null) : null, isOtherSourceValue: value && source ? (value.sourceId !== source.id ? 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 }));
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
@@ -13,6 +13,7 @@ export interface ResourceBrowserSource {
13
13
  name?: string;
14
14
  id: string;
15
15
  type: ResourceBrowserPluginType;
16
+ aliases?: string[];
16
17
  }
17
18
  export interface ResourceBrowserSourceWithPlugin extends ResourceBrowserSource {
18
19
  plugin: ResourceBrowserPlugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squiz/resource-browser",
3
- "version": "3.3.9",
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.5",
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",
@@ -3,7 +3,8 @@
3
3
  "name": "Bynder #1",
4
4
  "id": "c90feac1-55f3-4e1f-9b56-c22829e3f510",
5
5
  "type": "dam",
6
- "group": "DAM"
6
+ "group": "DAM",
7
+ "aliases": ["bynder-789"]
7
8
  },
8
9
  {
9
10
  "name": "Bynder #2",
@@ -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
  });
@@ -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 = sources.find((source) => source.id === value?.sourceId) || null;
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
- const source = sources.find((source) => source.id === value?.sourceId) || null;
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.sourceId === source.id ? value : null) : null} // Don't pass value if value isn't for selected source
172
- isOtherSourceValue={value && source ? (value.sourceId !== source.id ? true : false) : false} // Block render of existing asset if not from this source
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 {