@squiz/resource-browser 1.69.1 → 2.1.8-rc.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.
Files changed (141) hide show
  1. package/CHANGELOG.md +88 -35
  2. package/LICENSE.md +15 -0
  3. package/README.md +9 -0
  4. package/jest.config.ts +22 -21
  5. package/lib/Hooks/useSelectedState.d.ts +15 -0
  6. package/lib/Hooks/useSelectedState.js +16 -0
  7. package/lib/Hooks/useSources.d.ts +5 -4
  8. package/lib/Hooks/useSources.js +25 -1
  9. package/lib/MainContainer/MainContainer.d.ts +17 -0
  10. package/lib/MainContainer/MainContainer.js +61 -0
  11. package/lib/Plugin/Plugin.d.ts +13 -0
  12. package/lib/Plugin/Plugin.js +17 -0
  13. package/lib/ResourceBrowserContext/ResourceBrowserContext.d.ts +2 -3
  14. package/lib/ResourceBrowserContext/ResourceBrowserContext.js +4 -17
  15. package/lib/ResourceBrowserInput/ResourceBrowserInput.d.ts +24 -0
  16. package/lib/ResourceBrowserInput/ResourceBrowserInput.js +16 -0
  17. package/lib/ResourcePicker/ResourcePicker.d.ts +6 -4
  18. package/lib/ResourcePicker/ResourcePicker.js +14 -8
  19. package/lib/ResourcePicker/States/Selected.d.ts +10 -4
  20. package/lib/ResourcePicker/States/Selected.js +11 -32
  21. package/lib/SourceDropdown/SourceDropdown.d.ts +5 -11
  22. package/lib/SourceDropdown/SourceDropdown.js +20 -99
  23. package/lib/SourceList/SourceList.d.ts +5 -16
  24. package/lib/SourceList/SourceList.js +14 -75
  25. package/lib/index.css +42 -202
  26. package/lib/index.d.ts +7 -7
  27. package/lib/index.js +69 -13
  28. package/lib/types.d.ts +41 -59
  29. package/package.json +82 -80
  30. package/src/Hooks/useSelectedState.spec.ts +46 -0
  31. package/src/Hooks/useSelectedState.ts +22 -0
  32. package/src/Hooks/useSources.spec.ts +30 -12
  33. package/src/Hooks/useSources.ts +33 -4
  34. package/src/Icons/CircledLoopIcon.tsx +8 -8
  35. package/src/MainContainer/MainContainer.spec.tsx +203 -0
  36. package/src/MainContainer/MainContainer.stories.tsx +62 -0
  37. package/src/MainContainer/MainContainer.tsx +101 -0
  38. package/src/Plugin/Plugin.spec.tsx +46 -0
  39. package/src/Plugin/Plugin.tsx +20 -0
  40. package/src/ResourceBrowserContext/ResourceBrowserContext.spec.tsx +65 -106
  41. package/src/ResourceBrowserContext/ResourceBrowserContext.tsx +24 -39
  42. package/src/ResourceBrowserInput/ResourceBrowserInput.spec.tsx +192 -0
  43. package/src/ResourceBrowserInput/ResourceBrowserInput.tsx +81 -0
  44. package/src/ResourcePicker/ResourcePicker.spec.tsx +159 -116
  45. package/src/ResourcePicker/ResourcePicker.stories.tsx +28 -24
  46. package/src/ResourcePicker/ResourcePicker.tsx +79 -59
  47. package/src/ResourcePicker/States/Error.tsx +8 -8
  48. package/src/ResourcePicker/States/Loading.tsx +3 -3
  49. package/src/ResourcePicker/States/Selected.tsx +66 -73
  50. package/src/ResourcePicker/mock-image-resource.json +25 -47
  51. package/src/ResourcePicker/mock-resource.json +11 -13
  52. package/src/ResourcePicker/resource-picker.scss +13 -13
  53. package/src/SourceDropdown/SourceDropdown.spec.tsx +65 -391
  54. package/src/SourceDropdown/SourceDropdown.stories.tsx +21 -24
  55. package/src/SourceDropdown/SourceDropdown.tsx +80 -258
  56. package/src/SourceList/SourceList.spec.tsx +37 -430
  57. package/src/SourceList/SourceList.stories.tsx +17 -37
  58. package/src/SourceList/SourceList.tsx +28 -155
  59. package/src/__mocks__/MockModels.ts +56 -25
  60. package/src/__mocks__/PluginExample.tsx +98 -0
  61. package/src/__mocks__/StorybookHelpers.tsx +141 -0
  62. package/src/__mocks__/renderWithContext.tsx +14 -18
  63. package/src/__mocks__/sample-sources.json +32 -0
  64. package/src/index.scss +18 -8
  65. package/src/index.spec.tsx +277 -99
  66. package/src/index.stories.tsx +65 -39
  67. package/src/index.tsx +119 -57
  68. package/src/types.ts +54 -63
  69. package/tailwind.config.cjs +92 -92
  70. package/vite.config.js +12 -12
  71. package/lib/Hooks/useCategorisedSources.d.ts +0 -14
  72. package/lib/Hooks/useCategorisedSources.js +0 -38
  73. package/lib/Hooks/useChildResources.d.ts +0 -16
  74. package/lib/Hooks/useChildResources.js +0 -13
  75. package/lib/Hooks/usePreselectedResourcePath.d.ts +0 -20
  76. package/lib/Hooks/usePreselectedResourcePath.js +0 -31
  77. package/lib/Hooks/useRecentLocations.d.ts +0 -5
  78. package/lib/Hooks/useRecentLocations.js +0 -38
  79. package/lib/Hooks/useRecentResourcesPaths.d.ts +0 -20
  80. package/lib/Hooks/useRecentResourcesPaths.js +0 -30
  81. package/lib/Hooks/useResource.d.ts +0 -28
  82. package/lib/Hooks/useResource.js +0 -23
  83. package/lib/Hooks/useResourcePath.d.ts +0 -16
  84. package/lib/Hooks/useResourcePath.js +0 -64
  85. package/lib/Icons/HistoryIcon.d.ts +0 -4
  86. package/lib/Icons/HistoryIcon.js +0 -13
  87. package/lib/PreviewPanel/PreviewPanel.d.ts +0 -5
  88. package/lib/PreviewPanel/PreviewPanel.js +0 -8
  89. package/lib/PreviewPanel/details/MatrixResource.d.ts +0 -7
  90. package/lib/PreviewPanel/details/MatrixResource.js +0 -35
  91. package/lib/ResourceBreadcrumb/ResourceBreadcrumb.d.ts +0 -9
  92. package/lib/ResourceBreadcrumb/ResourceBreadcrumb.js +0 -54
  93. package/lib/ResourceList/ResourceList.d.ts +0 -18
  94. package/lib/ResourceList/ResourceList.js +0 -49
  95. package/lib/ResourcePickerContainer/ResourcePickerContainer.d.ts +0 -17
  96. package/lib/ResourcePickerContainer/ResourcePickerContainer.js +0 -166
  97. package/lib/StatusIndicator/StatusIndicator.d.ts +0 -8
  98. package/lib/StatusIndicator/StatusIndicator.js +0 -27
  99. package/lib/utils/findBestMatchLineage.d.ts +0 -2
  100. package/lib/utils/findBestMatchLineage.js +0 -28
  101. package/lib/utils/uuid.d.ts +0 -1
  102. package/lib/utils/uuid.js +0 -6
  103. package/src/Hooks/useCategorisedSources.spec.ts +0 -39
  104. package/src/Hooks/useCategorisedSources.ts +0 -46
  105. package/src/Hooks/useChildResources.spec.ts +0 -29
  106. package/src/Hooks/useChildResources.ts +0 -21
  107. package/src/Hooks/usePreselectedResourcePath.ts +0 -54
  108. package/src/Hooks/useRecentLocations.spec.ts +0 -81
  109. package/src/Hooks/useRecentLocations.ts +0 -44
  110. package/src/Hooks/useRecentResourcesPaths.ts +0 -54
  111. package/src/Hooks/useResource.spec.ts +0 -61
  112. package/src/Hooks/useResource.ts +0 -38
  113. package/src/Hooks/useResourcePath.spec.ts +0 -120
  114. package/src/Hooks/useResourcePath.ts +0 -76
  115. package/src/Icons/HistoryIcon.tsx +0 -17
  116. package/src/PreviewPanel/PreviewPanel.spec.tsx +0 -198
  117. package/src/PreviewPanel/PreviewPanel.stories.tsx +0 -76
  118. package/src/PreviewPanel/PreviewPanel.tsx +0 -6
  119. package/src/PreviewPanel/details/MatrixResource.tsx +0 -54
  120. package/src/PreviewPanel/details/matrix-resource.scss +0 -16
  121. package/src/ResourceBreadcrumb/ResourceBreadcrumb.spec.tsx +0 -133
  122. package/src/ResourceBreadcrumb/ResourceBreadcrumb.stories.tsx +0 -24
  123. package/src/ResourceBreadcrumb/ResourceBreadcrumb.tsx +0 -79
  124. package/src/ResourceBreadcrumb/resource-breadcrumb.scss +0 -28
  125. package/src/ResourceBreadcrumb/sample-hierarchy.json +0 -27
  126. package/src/ResourceList/ResourceList.spec.tsx +0 -202
  127. package/src/ResourceList/ResourceList.stories.tsx +0 -40
  128. package/src/ResourceList/ResourceList.tsx +0 -83
  129. package/src/ResourceList/sample-resources.json +0 -851
  130. package/src/ResourcePickerContainer/ResourcePickerContainer.spec.tsx +0 -780
  131. package/src/ResourcePickerContainer/ResourcePickerContainer.stories.tsx +0 -45
  132. package/src/ResourcePickerContainer/ResourcePickerContainer.tsx +0 -290
  133. package/src/SourceList/sample-sources.json +0 -251
  134. package/src/StatusIndicator/StatusIndicator.stories.tsx +0 -83
  135. package/src/StatusIndicator/StatusIndicator.tsx +0 -38
  136. package/src/__mocks__/JestHelpers.ts +0 -65
  137. package/src/__mocks__/StorybookHelpers.ts +0 -128
  138. package/src/__mocks__/jestHelpers.spec.ts +0 -38
  139. package/src/utils/findBestMatchLineage.spec.ts +0 -81
  140. package/src/utils/findBestMatchLineage.ts +0 -30
  141. package/src/utils/uuid.ts +0 -5
package/lib/types.d.ts CHANGED
@@ -1,74 +1,56 @@
1
+ import React, { ReactElement } from 'react';
1
2
  import { SquizImageType } from '@squiz/dx-json-schema-lib';
2
- export type Status = {
3
- code: string;
4
- name: string;
3
+ export type OnRequestSources = () => Promise<ResourceBrowserSource[]>;
4
+ export type ResourceBrowserPluginType = 'dam' | 'matrix';
5
+ export type ResourceBrowserSource = {
6
+ name?: string;
7
+ id: string;
8
+ type: ResourceBrowserPluginType;
5
9
  };
6
- /**
7
- * Represents a resource that has been picked from a source.
8
- */
9
- export type Resource = {
10
+ export type ResourceBrowserUnresolvedResource = {
11
+ sourceId: string;
12
+ resourceId: string;
13
+ };
14
+ export type ResourceBrowserResource = {
10
15
  id: string;
11
16
  name: string;
17
+ url: string;
18
+ source: ResourceBrowserSource;
12
19
  type: {
13
20
  code: string;
14
21
  name: string;
15
22
  };
16
- status: Status;
17
- url: string;
18
- urls: string[];
19
- childCount: number;
20
23
  squizImage?: SquizImageType['__shape__'];
21
- lineages?: ResourceLineage[];
22
- };
23
- export type ResourceLineage = {
24
- resourceIds: string[];
25
- };
26
- /**
27
- * Represents a system that resources can be picked from.
28
- * Optionally, may indicate a list of "nodes" that can be used to scope the source to a subset of its resources.
29
- */
30
- export type Source = {
31
- id: string;
32
- name: string;
33
- nodes: Resource[];
34
24
  };
35
- /**
36
- * Represents a source that has been optionally scoped to one of its "nodes".
37
- */
38
- export type ScopedSource = {
39
- source: Source;
40
- resource: Resource | null;
25
+ export type ResourceBrowserSelectedState = {
26
+ showThumbnail?: boolean;
27
+ icon?: ReactElement;
28
+ label: string;
29
+ description: Array<ReactElement>;
41
30
  };
42
- /**
43
- * A non-hydrated resource reference.
44
- */
45
- export type ResourceReference = {
46
- source: string;
47
- resource: string;
31
+ export type ResourceBrowserUIProps = {
32
+ source: ResourceBrowserSource;
33
+ allowedTypes?: string[];
34
+ headerPortal?: Element;
35
+ preselectedResource?: ResourceBrowserResource;
36
+ onSelected: (resource: ResourceBrowserResource) => void;
48
37
  };
49
- /**
50
- * A hydrated resource reference.
51
- */
52
- export type HydratedResourceReference = {
53
- source: Source;
54
- resource: Resource;
38
+ export type useResolveResourceResponse = {
39
+ data: ResourceBrowserResource | null;
40
+ error: Error | null;
41
+ isLoading: boolean;
55
42
  };
56
43
  /**
57
- * Represents the hierarchy within the asset picker.
58
- * Within the picker T will be ScopedSource|Resource.
59
- * ScopedSource will be the first item in the array, Resource will be every other item.
60
- */
61
- export type Hierarchy<T> = Array<{
62
- key: string;
63
- label: string;
64
- node: T;
65
- }>;
66
- /**
67
- * Augments a type so that all properties are optional.
44
+ * If you change this interface please update the example here: src/__mocks__/PluginExample.tsx
68
45
  */
69
- export type DeepPartial<T> = {
70
- [P in keyof T]?: T[P] extends Array<infer U> ? Array<DeepPartial<U>> : T[P] extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : DeepPartial<T[P]>;
71
- };
72
- export type OnRequestSources = () => Promise<Source[]>;
73
- export type OnRequestResource = (reference: ResourceReference) => Promise<Resource>;
74
- export type OnRequestChildren = (source: Source, resource: Resource | null) => Promise<Resource[]>;
46
+ export interface ResourceBrowserPlugin {
47
+ /** Datasource type this plugin should be used for */
48
+ type: ResourceBrowserPluginType;
49
+ createHeaderPortal?: boolean;
50
+ /** React Functional Component to provde the UI to render to allow a user to select a resource to use */
51
+ sourceBrowserComponent: () => React.FunctionComponent<ResourceBrowserUIProps>;
52
+ /** Function to provde the the summary information to show what resource is currently selected */
53
+ renderSelectedResource: (resource: ResourceBrowserResource) => Promise<ResourceBrowserSelectedState>;
54
+ /** Function to resolve a resource and source id into a fully resolved output reference */
55
+ useResolveResource: (resourceId: string | null, source: ResourceBrowserSource | null) => useResolveResourceResponse;
56
+ }
package/package.json CHANGED
@@ -1,83 +1,85 @@
1
1
  {
2
- "name": "@squiz/resource-browser",
3
- "version": "1.69.1",
4
- "main": "lib/index.js",
5
- "types": "lib/index.d.ts",
6
- "private": false,
7
- "publishConfig": {
8
- "access": "public"
9
- },
10
- "scripts": {
11
- "compile": "npm run clean && npm run compile:styles && npm run compile:code",
12
- "compile:code": "tsc",
13
- "compile:styles": "node build.js",
14
- "dev": "vite compile",
15
- "storybook": "storybook dev -p 6006",
16
- "test": "jest",
17
- "test:watch": "jest --watch",
18
- "clean": "rimraf ./lib"
19
- },
20
- "dependencies": {
21
- "@mui/icons-material": "5.11.16",
22
- "@squiz/dx-json-schema-lib": "^1.67.0",
23
- "@squiz/generic-browser-lib": "^1.67.0",
24
- "expiry-map": "^2.0.0",
25
- "p-memoize": "^4.0.4",
26
- "pretty-bytes": "5.6.0",
27
- "react-aria": "3.23.1",
28
- "react-responsive": "9.0.2",
29
- "react-stately": "3.21.0"
30
- },
31
- "devDependencies": {
32
- "@storybook/addon-essentials": "^7.5.3",
33
- "@storybook/addon-interactions": "^7.5.3",
34
- "@storybook/addon-links": "^7.5.3",
35
- "@storybook/addon-styling": "1.0.1",
36
- "@storybook/blocks": "^7.5.3",
37
- "@storybook/react": "^7.5.3",
38
- "@storybook/react-vite": "^7.5.3",
39
- "@storybook/testing-library": "0.0.14-next.1",
40
- "@testing-library/jest-dom": "5.16.5",
41
- "@testing-library/react": "14.0.0",
42
- "@testing-library/user-event": "14.4.3",
43
- "@types/postcss-js": "4.0.0",
44
- "@types/react": "^18.2.45",
45
- "@types/react-dom": "^18.2.18",
46
- "@vitejs/plugin-react-swc": "3.0.0",
47
- "autoprefixer": "10.4.14",
48
- "esbuild": "^0.20.2",
49
- "esbuild-sass-plugin": "2.8.0",
50
- "jest": "29.4.1",
51
- "jest-environment-jsdom": "29.4.1",
52
- "postcss": "8.4.31",
53
- "postcss-loader": "7.2.4",
54
- "postcss-nested": "6.0.1",
55
- "postcss-prefix-selector": "1.16.0",
56
- "prop-types": "15.8.1",
57
- "react": "18.2.0",
58
- "react-dom": "18.2.0",
59
- "rimraf": "4.1.2",
60
- "storybook": "^7.5.3",
61
- "tailwindcss": "3.3.1",
62
- "ts-jest": "29.0.5",
63
- "typescript": "4.9.3",
64
- "vite": "^4.5.0"
65
- },
66
- "peerDependencies": {
67
- "@types/react": "^16.14.0 || ^17 || ^18",
68
- "@types/react-dom": "^16.9.0 || ^17 || ^18",
69
- "react": "^16.14.0 || ^17 || ^18",
70
- "react-dom": "^16.14.0 || ^17 || ^18"
71
- },
72
- "peerDependenciesMeta": {
73
- "@types/react": {
74
- "optional": true
2
+ "name": "@squiz/resource-browser",
3
+ "version": "2.1.8-rc.0",
4
+ "main": "lib/index.js",
5
+ "types": "lib/index.d.ts",
6
+ "private": false,
7
+ "publishConfig": {
8
+ "access": "public"
75
9
  },
76
- "@types/react-dom": {
77
- "optional": true
78
- }
79
- },
80
- "volta": {
81
- "node": "18.15.0"
82
- }
10
+ "scripts": {
11
+ "compile": "npm run compile:styles && npm run compile:code",
12
+ "compile:code": "tsc",
13
+ "compile:styles": "node build.js",
14
+ "storybook": "storybook dev -p 6006",
15
+ "test": "jest",
16
+ "test:unit": "jest",
17
+ "test:watch": "jest --watch"
18
+ },
19
+ "dependencies": {
20
+ "@emotion/styled": "^11.11.5",
21
+ "@mui/icons-material": "5.11.16",
22
+ "@react-aria/interactions": "^3.21.1",
23
+ "@react-types/shared": "^3.22.1",
24
+ "@squiz/dx-json-schema-lib": "^1.67.0",
25
+ "@squiz/generic-browser-lib": "^1.66.0",
26
+ "@squiz/resource-browser-ui-lib": "^0.8.1-rc.0",
27
+ "clsx": "^2.1.0",
28
+ "expiry-map": "^2.0.0",
29
+ "p-memoize": "^4.0.4",
30
+ "react-aria": "3.23.1",
31
+ "react-responsive": "9.0.2",
32
+ "react-stately": "3.21.0"
33
+ },
34
+ "devDependencies": {
35
+ "@storybook/addon-essentials": "^7.5.3",
36
+ "@storybook/addon-interactions": "^7.5.3",
37
+ "@storybook/addon-links": "^7.5.3",
38
+ "@storybook/addon-styling": "1.0.1",
39
+ "@storybook/blocks": "^7.5.3",
40
+ "@storybook/react": "^7.5.3",
41
+ "@storybook/react-vite": "^7.5.3",
42
+ "@storybook/testing-library": "0.0.14-next.1",
43
+ "@testing-library/jest-dom": "5.16.5",
44
+ "@testing-library/react": "14.0.0",
45
+ "@testing-library/user-event": "14.4.3",
46
+ "@types/postcss-js": "4.0.0",
47
+ "@types/react": "^18.2.45",
48
+ "@types/react-dom": "^18.2.18",
49
+ "autoprefixer": "10.4.14",
50
+ "esbuild": "^0.19.3",
51
+ "esbuild-sass-plugin": "^2.8.0",
52
+ "jest": "29.4.1",
53
+ "jest-environment-jsdom": "29.4.1",
54
+ "postcss": "8.4.31",
55
+ "postcss-loader": "7.2.4",
56
+ "postcss-nested": "6.0.1",
57
+ "postcss-prefix-selector": "1.16.0",
58
+ "prop-types": "15.8.1",
59
+ "react": "^18.0.0",
60
+ "react-dom": "^18.0.0",
61
+ "storybook": "^7.5.3",
62
+ "tailwindcss": "3.3.1",
63
+ "ts-jest": "29.0.5",
64
+ "typescript": "4.9.3",
65
+ "vite": "^4.5.0"
66
+ },
67
+ "peerDependencies": {
68
+ "@types/react": "^16.14.0 || ^17 || ^18",
69
+ "@types/react-dom": "^16.9.0 || ^17 || ^18",
70
+ "react": "^16.14.0 || ^17 || ^18",
71
+ "react-dom": "^16.14.0 || ^17 || ^18"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "@types/react": {
75
+ "optional": true
76
+ },
77
+ "@types/react-dom": {
78
+ "optional": true
79
+ }
80
+ },
81
+ "volta": {
82
+ "node": "18.18.0"
83
+ },
84
+ "gitHead": "95c233207d4a87157029512d0bd9edacaf15826d"
83
85
  }
@@ -0,0 +1,46 @@
1
+ import { renderHook, waitFor } from '@testing-library/react';
2
+ import { ResourceBrowserPlugin } from '../types';
3
+ import { mockResource } from '../__mocks__/MockModels';
4
+ import { useSelectedState } from './useSelectedState';
5
+
6
+ describe('useSelectedState', () => {
7
+ it('Should load the selectedState from the plugin', async () => {
8
+ const selectedStateResponse = {};
9
+ const resource = mockResource({ id: '1' });
10
+ const mockRenderSelectedResource = jest.fn().mockResolvedValue(selectedStateResponse);
11
+ const secondMockRenderSelectedResource = jest.fn();
12
+ const plugin: Partial<ResourceBrowserPlugin> = {
13
+ type: 'dam',
14
+ renderSelectedResource: mockRenderSelectedResource,
15
+ };
16
+
17
+ const { result } = renderHook(() => useSelectedState({ plugin: plugin as ResourceBrowserPlugin, resource }));
18
+
19
+ expect(result.current.isLoading).toBe(true);
20
+ expect(result.current.error).toBe(null);
21
+ expect(result.current.data).toEqual(null);
22
+
23
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
24
+
25
+ expect(mockRenderSelectedResource).toHaveBeenCalledTimes(1);
26
+ expect(secondMockRenderSelectedResource).not.toHaveBeenCalled();
27
+
28
+ expect(result.current.isLoading).toBe(false);
29
+ expect(result.current.data).toBe(selectedStateResponse);
30
+ });
31
+
32
+ it('Should not load the resource if no reference provided', async () => {
33
+ const mockRenderSelectedResource = jest.fn();
34
+ const plugin: Partial<ResourceBrowserPlugin> = {
35
+ type: 'dam',
36
+ renderSelectedResource: mockRenderSelectedResource,
37
+ };
38
+
39
+ const { result } = renderHook(() => useSelectedState({ plugin: plugin as ResourceBrowserPlugin, resource: null }));
40
+
41
+ expect(result.current.isLoading).toBe(false);
42
+ expect(result.current.error).toBe(null);
43
+ expect(result.current.data).toEqual(null);
44
+ expect(mockRenderSelectedResource).not.toHaveBeenCalled();
45
+ });
46
+ });
@@ -0,0 +1,22 @@
1
+ import { useAsync } from '@squiz/generic-browser-lib';
2
+ import { ResourceBrowserPlugin, ResourceBrowserResource } from '../types';
3
+
4
+ type UseResourceProps = {
5
+ plugin: ResourceBrowserPlugin | null;
6
+ resource: ResourceBrowserResource | null;
7
+ };
8
+
9
+ /**
10
+ * Loads the selected state for the provided resource
11
+ */
12
+ export const useSelectedState = ({ plugin, resource }: UseResourceProps) => {
13
+ // Find the resolver for this resource
14
+ const renderSelectedResource = resource && plugin?.renderSelectedResource;
15
+ return useAsync(
16
+ {
17
+ callback: () => (resource && renderSelectedResource ? renderSelectedResource(resource) : null),
18
+ defaultValue: null,
19
+ },
20
+ [resource],
21
+ );
22
+ };
@@ -1,20 +1,38 @@
1
1
  import { renderHook, waitFor } from '@testing-library/react';
2
- import { mockSource } from '../__mocks__/MockModels';
2
+ import { mockSource, mockPlugin } from '../__mocks__/MockModels';
3
3
  import { useSources } from './useSources';
4
4
 
5
5
  describe('useSources', () => {
6
- it('Should trigger and load the sources', async () => {
7
- const sources = [mockSource()];
8
- const onRequestSources = jest.fn().mockResolvedValue(sources);
9
- const { result } = renderHook(() => useSources({ onRequestSources }));
6
+ it('Should trigger and load the sources', async () => {
7
+ const sources = [mockSource()];
8
+ const plugins = [mockPlugin()];
9
+ const onRequestSources = jest.fn().mockResolvedValue(sources);
10
+ const { result } = renderHook(() => useSources({ onRequestSources, plugins }));
10
11
 
11
- expect(result.current.isLoading).toBe(true);
12
- expect(result.current.error).toBe(null);
13
- expect(result.current.data).toEqual([]);
12
+ expect(result.current.isLoading).toBe(true);
13
+ expect(result.current.error).toBe(null);
14
+ expect(result.current.data).toEqual([]);
14
15
 
15
- await waitFor(() => expect(result.current.isLoading).toBe(false));
16
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
16
17
 
17
- expect(result.current.isLoading).toBe(false);
18
- expect(result.current.data).toBe(sources);
19
- });
18
+ expect(result.current.isLoading).toBe(false);
19
+ expect(result.current.data).toEqual(sources);
20
+ });
21
+
22
+ it('Should filters sources that plugins dont exist for', async () => {
23
+ const sources = [mockSource({ type: 'dam' }), mockSource({ id: '2', type: 'matrix' })];
24
+ const plugins = [mockPlugin({ type: 'dam' })];
25
+ const onRequestSources = jest.fn().mockResolvedValue(sources);
26
+ const { result } = renderHook(() => useSources({ onRequestSources, plugins }));
27
+
28
+ expect(result.current.isLoading).toBe(true);
29
+ expect(result.current.error).toBe(null);
30
+ expect(result.current.data).toEqual([]);
31
+
32
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
33
+
34
+ expect(result.current.isLoading).toBe(false);
35
+ expect(result.current.data).toEqual([sources[0]]);
36
+ expect(result.current.data.length).toEqual(1);
37
+ });
20
38
  });
@@ -1,12 +1,41 @@
1
- import { Source } from '../types';
1
+ import { ResourceBrowserSource, ResourceBrowserPlugin } from '../types';
2
2
  import { useAsync } from '@squiz/generic-browser-lib';
3
3
 
4
4
  type UseSourcesProps = {
5
- onRequestSources: () => Promise<Source[]>;
5
+ onRequestSources: () => Promise<ResourceBrowserSource[]>;
6
+ plugins: Array<ResourceBrowserPlugin>;
6
7
  };
7
8
 
8
9
  /**
9
10
  * Loads and caches the source list when a component using the hook is mounted.
10
11
  */
11
- export const useSources = ({ onRequestSources }: UseSourcesProps) =>
12
- useAsync({ callback: onRequestSources, defaultValue: [] as Source[] }, []);
12
+ export const useSources = ({ onRequestSources, plugins }: UseSourcesProps) => {
13
+ return useAsync(
14
+ {
15
+ callback: () => {
16
+ return new Promise<ResourceBrowserSource[]>((resolve, reject) => {
17
+ // Get all the sources from the outer context
18
+ onRequestSources()
19
+ .then((sources: ResourceBrowserSource[]) => {
20
+ // Remove any sources which we don't have a plugin to handle
21
+ resolve(
22
+ sources.filter((source) => {
23
+ return !!plugins.find((plugin) => {
24
+ if (plugin.type === source.type) {
25
+ return true;
26
+ }
27
+ return false;
28
+ });
29
+ }),
30
+ );
31
+ })
32
+ .catch((e: unknown) => {
33
+ reject(e);
34
+ });
35
+ });
36
+ },
37
+ defaultValue: [] as ResourceBrowserSource[],
38
+ },
39
+ [plugins],
40
+ );
41
+ };
@@ -3,12 +3,12 @@ import React, { SVGAttributes } from 'react';
3
3
  type CircledLoopIconProps = SVGAttributes<SVGElement>;
4
4
 
5
5
  export const CircledLoopIcon = (props: CircledLoopIconProps) => {
6
- return (
7
- <svg fill="none" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" {...props}>
8
- <path
9
- d="M8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM8 14C4.6925 14 2 11.3075 2 8C2 4.6925 4.6925 2 8 2C11.3075 2 14 4.6925 14 8C14 11.3075 11.3075 14 8 14ZM11.1275 10.07L10.3025 9.245C10.835 8.2475 10.7 6.9875 9.86 6.1475C9.3425 5.63 8.675 5.375 8 5.375C7.9775 5.375 7.955 5.3825 7.9325 5.3825L8.75 6.2L7.955 6.995L5.8325 4.8725L7.955 2.75L8.75 3.545L8.03 4.265C8.9825 4.2725 9.9275 4.625 10.655 5.345C11.93 6.6275 12.0875 8.615 11.1275 10.07ZM10.1675 11.1275L8.045 13.25L7.25 12.455L7.9625 11.7425C7.0175 11.735 6.0725 11.3675 5.3525 10.6475C4.07 9.365 3.9125 7.385 4.8725 5.93L5.6975 6.755C5.165 7.7525 5.3 9.0125 6.14 9.8525C6.665 10.3775 7.3625 10.6325 8.06 10.61L7.25 9.8L8.045 9.005L10.1675 11.1275Z"
10
- fill="#949494"
11
- />
12
- </svg>
13
- );
6
+ return (
7
+ <svg fill="none" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" {...props}>
8
+ <path
9
+ d="M8 0.5C3.86 0.5 0.5 3.86 0.5 8C0.5 12.14 3.86 15.5 8 15.5C12.14 15.5 15.5 12.14 15.5 8C15.5 3.86 12.14 0.5 8 0.5ZM8 14C4.6925 14 2 11.3075 2 8C2 4.6925 4.6925 2 8 2C11.3075 2 14 4.6925 14 8C14 11.3075 11.3075 14 8 14ZM11.1275 10.07L10.3025 9.245C10.835 8.2475 10.7 6.9875 9.86 6.1475C9.3425 5.63 8.675 5.375 8 5.375C7.9775 5.375 7.955 5.3825 7.9325 5.3825L8.75 6.2L7.955 6.995L5.8325 4.8725L7.955 2.75L8.75 3.545L8.03 4.265C8.9825 4.2725 9.9275 4.625 10.655 5.345C11.93 6.6275 12.0875 8.615 11.1275 10.07ZM10.1675 11.1275L8.045 13.25L7.25 12.455L7.9625 11.7425C7.0175 11.735 6.0725 11.3675 5.3525 10.6475C4.07 9.365 3.9125 7.385 4.8725 5.93L5.6975 6.755C5.165 7.7525 5.3 9.0125 6.14 9.8525C6.665 10.3775 7.3625 10.6325 8.06 10.61L7.25 9.8L8.045 9.005L10.1675 11.1275Z"
10
+ fill="#949494"
11
+ />
12
+ </svg>
13
+ );
14
14
  };