@squiz/resource-browser 3.2.3 → 3.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9e6268d: Allow users to restrict plugin usage
8
+
3
9
  ## 3.2.3
4
10
 
5
11
  ### Patch Changes
package/lib/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ResourceBrowserContext, ResourceBrowserContextProvider } from './ResourceBrowserContext/ResourceBrowserContext';
3
- import { InlineType, ResourceBrowserUnresolvedResource, ResourceBrowserResource } from './types';
3
+ import { InlineType, ResourceBrowserUnresolvedResource, ResourceBrowserResource, ResourceBrowserPluginType } from './types';
4
4
  import { AuthProvider, useAuthContext, AuthContext } from './ResourceBrowserContext/AuthProvider';
5
5
  import BrowseToSource from './BrowseToSource/BrowseToSource';
6
6
  import SourceDropdown from './SourceDropdown/SourceDropdown';
@@ -10,6 +10,7 @@ export * from './types';
10
10
  export type ResourceBrowserProps = {
11
11
  modalTitle: string;
12
12
  allowedTypes?: string[];
13
+ allowedPlugins?: ResourceBrowserPluginType[];
13
14
  isDisabled?: boolean;
14
15
  value: ResourceBrowserUnresolvedResource | null;
15
16
  inline?: boolean;
package/lib/index.js CHANGED
@@ -48,11 +48,19 @@ const SourceDropdownContainer_1 = __importDefault(require("./SourceDropdownConta
48
48
  exports.SourceDropdownContainer = SourceDropdownContainer_1.default;
49
49
  __exportStar(require("./types"), exports);
50
50
  const ResourceBrowser = (props) => {
51
- const { value, inline, inlineType } = props;
51
+ const { value, inline, inlineType, allowedPlugins } = props;
52
52
  const [error, setError] = (0, react_1.useState)(null);
53
- const { onRequestSources, searchEnabled, plugins } = (0, react_1.useContext)(ResourceBrowserContext_1.ResourceBrowserContext);
53
+ const { onRequestSources, searchEnabled, plugins: allPlugins } = (0, react_1.useContext)(ResourceBrowserContext_1.ResourceBrowserContext);
54
54
  const [isModalOpen, setIsModalOpen] = (0, react_1.useState)(false);
55
55
  const [source, setSource] = (0, react_1.useState)(null);
56
+ const plugins = (0, react_1.useMemo)(() => {
57
+ // Allow some usages e.g. plugin specific like MatrixAssetWidget restrict what plugins show
58
+ if (!allowedPlugins)
59
+ return allPlugins; // No restrictions, return all
60
+ return allPlugins.filter((plugin) => {
61
+ return allowedPlugins.includes(plugin.type); // Restrict based on plugin type
62
+ });
63
+ }, [allowedPlugins, allPlugins]);
56
64
  const [mode, setMode] = (0, react_1.useState)(null);
57
65
  const { data: sources, isLoading, error: sourcesError, reload: reloadSources } = (0, useSources_1.useSources)({ onRequestSources, plugins });
58
66
  const plugin = source?.plugin || null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squiz/resource-browser",
3
- "version": "3.2.3",
3
+ "version": "3.3.0",
4
4
  "main": "lib/index.js",
5
5
  "types": "lib/index.d.ts",
6
6
  "private": false,
@@ -10,6 +10,9 @@ jest.spyOn(RBI, 'ResourceBrowserInput');
10
10
 
11
11
  import * as Plugin from './Plugin/Plugin';
12
12
 
13
+ import * as useSources from './Hooks/useSources';
14
+ jest.spyOn(useSources, 'useSources');
15
+
13
16
  var useSourceReloadMock = jest.fn();
14
17
  jest.mock('./Hooks/useSources', () => {
15
18
  const actual = jest.requireActual('./Hooks/useSources');
@@ -57,12 +60,14 @@ describe('Resource browser input', () => {
57
60
  renderResourceLauncher: jest.fn(),
58
61
  } as ResourceBrowserPlugin;
59
62
 
63
+ const plugins = [mockMatrixPlugin, mockDamPlugin];
64
+
60
65
  const renderComponent = (props: Partial<ResourceBrowserProps> = {}, searchEnabled?: boolean) => {
61
66
  return renderWithContext(
62
67
  <ResourceBrowser modalTitle="Asset picker" value={null} onChange={mockChange} onClear={mockOnClear} {...props} />,
63
68
  {
64
69
  onRequestSources: mockRequestSources,
65
- plugins: [mockMatrixPlugin, mockDamPlugin],
70
+ plugins,
66
71
  searchEnabled: !!searchEnabled,
67
72
  },
68
73
  );
@@ -76,6 +81,32 @@ describe('Resource browser input', () => {
76
81
  };
77
82
  };
78
83
 
84
+ it('allowedPlugins will restrict which plugins are used', async () => {
85
+ // Works as expected with no restriction
86
+ (useSources.useSources as jest.Mock).mockClear();
87
+ renderComponent();
88
+ let expectedPlugins = plugins;
89
+ await waitFor(() => {
90
+ expect(useSources.useSources).toHaveBeenLastCalledWith(
91
+ expect.objectContaining({
92
+ plugins: expectedPlugins,
93
+ }),
94
+ );
95
+ });
96
+
97
+ // Works as expected with restrictions
98
+ (useSources.useSources as jest.Mock).mockClear();
99
+ renderComponent({ allowedPlugins: ['matrix'] });
100
+ expectedPlugins = plugins.filter((plugin) => plugin.type === 'matrix');
101
+ await waitFor(() => {
102
+ expect(useSources.useSources).toHaveBeenLastCalledWith(
103
+ expect.objectContaining({
104
+ plugins: expectedPlugins,
105
+ }),
106
+ );
107
+ });
108
+ });
109
+
79
110
  it('If only one valid source is provided will default to its Source and Plugin', async () => {
80
111
  const source = mockSource({ type: 'dam' });
81
112
  mockRequestSources.mockResolvedValueOnce([source]);
@@ -86,6 +86,13 @@ SingleSource.args = {
86
86
  singleSource: true,
87
87
  };
88
88
 
89
+ export const RestrictedSource = Template.bind({});
90
+ RestrictedSource.args = {
91
+ ...Primary.args,
92
+ allowedPlugins: ['matrix'],
93
+ searchEnabled: true,
94
+ };
95
+
89
96
  export const SearchEnabled = Template.bind({});
90
97
  SearchEnabled.args = {
91
98
  ...Primary.args,
package/src/index.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState, useContext, useEffect, useCallback } from 'react';
1
+ import React, { useState, useContext, useEffect, useCallback, useMemo } from 'react';
2
2
 
3
3
  import { ResourceBrowserContext, ResourceBrowserContextProvider } from './ResourceBrowserContext/ResourceBrowserContext';
4
4
  import {
@@ -7,6 +7,7 @@ import {
7
7
  ResourceBrowserUnresolvedResource,
8
8
  ResourceBrowserResource,
9
9
  ResourceBrowserSourceWithPlugin,
10
+ ResourceBrowserPluginType,
10
11
  } from './types';
11
12
  import { useSources } from './Hooks/useSources';
12
13
  import { PluginRender } from './Plugin/Plugin';
@@ -31,6 +32,7 @@ export * from './types';
31
32
  export type ResourceBrowserProps = {
32
33
  modalTitle: string;
33
34
  allowedTypes?: string[];
35
+ allowedPlugins?: ResourceBrowserPluginType[];
34
36
  isDisabled?: boolean;
35
37
  value: ResourceBrowserUnresolvedResource | null;
36
38
  inline?: boolean; // Will render open button only, no input / showing of existing selection
@@ -40,12 +42,19 @@ export type ResourceBrowserProps = {
40
42
  };
41
43
 
42
44
  export const ResourceBrowser = (props: ResourceBrowserProps) => {
43
- const { value, inline, inlineType } = props;
45
+ const { value, inline, inlineType, allowedPlugins } = props;
44
46
  const [error, setError] = useState<Error | null>(null);
45
- const { onRequestSources, searchEnabled, plugins } = useContext(ResourceBrowserContext);
47
+ const { onRequestSources, searchEnabled, plugins: allPlugins } = useContext(ResourceBrowserContext);
46
48
 
47
49
  const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
48
50
  const [source, setSource] = useState<ResourceBrowserSourceWithPlugin | null>(null);
51
+ const plugins = useMemo(() => {
52
+ // Allow some usages e.g. plugin specific like MatrixAssetWidget restrict what plugins show
53
+ if (!allowedPlugins) return allPlugins; // No restrictions, return all
54
+ return allPlugins.filter((plugin) => {
55
+ return allowedPlugins.includes(plugin.type); // Restrict based on plugin type
56
+ });
57
+ }, [allowedPlugins, allPlugins]);
49
58
  const [mode, setMode] = useState<PluginLaunchMode | null>(null);
50
59
  const { data: sources, isLoading, error: sourcesError, reload: reloadSources } = useSources({ onRequestSources, plugins });
51
60
  const plugin = source?.plugin || null;