@squiz/resource-browser 1.32.1-alpha.14 → 1.32.1-alpha.16
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/jest.config.ts +12 -1
- package/lib/Hooks/useCategorisedSources.d.ts +14 -0
- package/lib/Hooks/useCategorisedSources.js +38 -0
- package/lib/Hooks/useChildResources.d.ts +19 -0
- package/lib/Hooks/useChildResources.js +35 -0
- package/lib/Hooks/useResourcePath.d.ts +16 -0
- package/lib/Hooks/useResourcePath.js +64 -0
- package/lib/Hooks/useSources.d.ts +16 -0
- package/lib/Hooks/useSources.js +29 -0
- package/lib/Icons/Icon.d.ts +7 -7
- package/lib/Icons/Icon.js +7 -9
- package/lib/Icons/MatrixResources/Audio.js +1 -1
- package/lib/Icons/MatrixResources/Excel.js +1 -1
- package/lib/Icons/MatrixResources/MatrixResourceMap.d.ts +6 -6
- package/lib/Icons/MatrixResources/MatrixResourceMap.js +6 -6
- package/lib/Icons/MatrixResources/Pdf.js +1 -1
- package/lib/Icons/MatrixResources/Powerpoint.js +1 -1
- package/lib/Icons/MatrixResources/Video.js +1 -1
- package/lib/Icons/MatrixResources/Word.js +1 -1
- package/lib/Modal/Modal.js +1 -1
- package/lib/PreviewPanel/PreviewModal.js +1 -1
- package/lib/PreviewPanel/PreviewPanel.d.ts +4 -6
- package/lib/PreviewPanel/PreviewPanel.js +11 -39
- package/lib/PreviewPanel/details/MatrixResource.d.ts +4 -9
- package/lib/PreviewPanel/details/MatrixResource.js +20 -16
- package/lib/ResourceBreadcrumb/ResourceBreadcrumb.d.ts +5 -5
- package/lib/ResourceBreadcrumb/ResourceBreadcrumb.js +3 -3
- package/lib/ResourceItem/ResourceItem.d.ts +6 -8
- package/lib/ResourceItem/ResourceItem.js +3 -3
- package/lib/ResourceList/ResourceList.d.ts +5 -4
- package/lib/ResourceList/ResourceList.js +3 -3
- package/lib/ResourcePickerContainer/ResourcePickerContainer.d.ts +4 -5
- package/lib/ResourcePickerContainer/ResourcePickerContainer.js +34 -89
- package/lib/SourceDropdown/SourceDropdown.d.ts +5 -5
- package/lib/SourceDropdown/SourceDropdown.js +19 -27
- package/lib/SourceList/SourceList.d.ts +4 -4
- package/lib/SourceList/SourceList.js +7 -5
- package/lib/index.css +6 -0
- package/lib/index.d.ts +6 -29
- package/lib/index.js +2 -3
- package/lib/uuid.js +1 -3
- package/package.json +3 -2
- package/src/Hooks/useCategorisedSources.spec.ts +39 -0
- package/src/Hooks/useCategorisedSources.ts +46 -0
- package/src/Hooks/useChildResources.spec.ts +49 -0
- package/src/Hooks/useChildResources.ts +43 -0
- package/src/Hooks/useResourcePath.spec.ts +124 -0
- package/src/Hooks/useResourcePath.ts +76 -0
- package/src/Hooks/useSources.spec.ts +33 -0
- package/src/Hooks/useSources.ts +33 -0
- package/src/Icons/Icon.stories.tsx +7 -7
- package/src/Icons/Icon.tsx +9 -14
- package/src/Icons/MatrixResources/Audio.tsx +1 -1
- package/src/Icons/MatrixResources/Excel.tsx +1 -1
- package/src/Icons/MatrixResources/MatrixResourceMap.ts +7 -7
- package/src/Icons/MatrixResources/Pdf.tsx +1 -1
- package/src/Icons/MatrixResources/Powerpoint.tsx +1 -1
- package/src/Icons/MatrixResources/Video.tsx +1 -1
- package/src/Icons/MatrixResources/Word.tsx +1 -1
- package/src/Modal/Modal.tsx +1 -1
- package/src/PreviewPanel/PreviewModal.tsx +1 -1
- package/src/PreviewPanel/PreviewPanel.spec.tsx +20 -62
- package/src/PreviewPanel/PreviewPanel.stories.tsx +16 -24
- package/src/PreviewPanel/PreviewPanel.tsx +15 -51
- package/src/PreviewPanel/details/MatrixResource.tsx +23 -19
- package/src/ResourceBreadcrumb/ResourceBreadcrumb.spec.tsx +13 -23
- package/src/ResourceBreadcrumb/ResourceBreadcrumb.stories.tsx +1 -1
- package/src/ResourceBreadcrumb/ResourceBreadcrumb.tsx +8 -9
- package/src/ResourceBreadcrumb/sample-hierarchy.json +15 -25
- package/src/ResourceItem/ResourceItem.tsx +10 -12
- package/src/ResourceList/ResourceList.spec.tsx +8 -53
- package/src/ResourceList/ResourceList.stories.tsx +2 -2
- package/src/ResourceList/ResourceList.tsx +12 -10
- package/src/ResourceList/sample-resources.json +551 -49
- package/src/ResourcePickerContainer/ResourcePickerContainer.spec.tsx +196 -315
- package/src/ResourcePickerContainer/ResourcePickerContainer.stories.tsx +7 -29
- package/src/ResourcePickerContainer/ResourcePickerContainer.tsx +63 -127
- package/src/SourceDropdown/SourceDropdown.spec.tsx +63 -60
- package/src/SourceDropdown/SourceDropdown.stories.tsx +4 -7
- package/src/SourceDropdown/SourceDropdown.tsx +34 -41
- package/src/SourceList/SourceList.spec.tsx +38 -32
- package/src/SourceList/SourceList.tsx +17 -19
- package/src/SourceList/sample-sources.json +186 -77
- package/src/__mocks__/MockModels.ts +30 -0
- package/src/__mocks__/StorybookHelpers.ts +46 -0
- package/src/index.stories.tsx +13 -38
- package/src/index.tsx +5 -29
- package/src/types.d.ts +71 -0
- package/src/uuid.ts +2 -4
- package/src/SourceDropdown/sample-sources.json +0 -110
@@ -1,27 +1,28 @@
|
|
1
1
|
import React, { useState, useRef } from 'react';
|
2
2
|
import { useFocusWithin, useKeyboard } from '@react-aria/interactions';
|
3
3
|
|
4
|
-
import type { Source,
|
4
|
+
import type { Source, ScopedSource } from '../types';
|
5
5
|
import Spinner from '../Spinner/Spinner';
|
6
6
|
import Icon, { IconOptions } from '../Icons/Icon';
|
7
7
|
|
8
8
|
import uuid from '../uuid';
|
9
|
+
import { useCategorisedSources } from '../Hooks/useCategorisedSources';
|
9
10
|
|
10
11
|
export default function SourceDropdown({
|
11
12
|
sources,
|
12
|
-
|
13
|
+
selectedSource,
|
13
14
|
isLoading,
|
14
15
|
onRootSelect,
|
15
16
|
onSourceSelect,
|
16
17
|
}: {
|
17
|
-
sources:
|
18
|
-
|
18
|
+
sources: Source[];
|
19
|
+
selectedSource: ScopedSource | null;
|
19
20
|
isLoading: boolean;
|
20
21
|
onRootSelect: () => void;
|
21
|
-
onSourceSelect: (
|
22
|
+
onSourceSelect: (source: ScopedSource) => void;
|
22
23
|
}) {
|
24
|
+
const categorisedSources = useCategorisedSources(sources);
|
23
25
|
const [uniqueId] = useState(uuid());
|
24
|
-
|
25
26
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
26
27
|
const [isOpen, setIsOpen] = useState(false);
|
27
28
|
|
@@ -42,10 +43,10 @@ export default function SourceDropdown({
|
|
42
43
|
},
|
43
44
|
});
|
44
45
|
|
45
|
-
const handleSourceClick = (
|
46
|
+
const handleSourceClick = (source: ScopedSource) => {
|
46
47
|
setIsOpen(false);
|
47
48
|
buttonRef.current?.focus();
|
48
|
-
onSourceSelect(
|
49
|
+
onSourceSelect(source);
|
49
50
|
};
|
50
51
|
|
51
52
|
const handleRootSelect = () => {
|
@@ -54,19 +55,6 @@ export default function SourceDropdown({
|
|
54
55
|
onRootSelect();
|
55
56
|
};
|
56
57
|
|
57
|
-
let currentResource: Resource | undefined = undefined;
|
58
|
-
|
59
|
-
for (let i = 0; i < sources.length; i++) {
|
60
|
-
const source = sources[i];
|
61
|
-
if (currentSource?.source === source.id) {
|
62
|
-
currentResource = source.nodes.find((node) => {
|
63
|
-
if (node.id.id === currentSource?.id) {
|
64
|
-
return node;
|
65
|
-
}
|
66
|
-
});
|
67
|
-
}
|
68
|
-
}
|
69
|
-
|
70
58
|
return (
|
71
59
|
<div {...focusWithinProps} {...keyboardProps} className="relative w-72 border border-2 rounded border-gray-300">
|
72
60
|
<button
|
@@ -78,15 +66,20 @@ export default function SourceDropdown({
|
|
78
66
|
onClick={() => setIsOpen(!isOpen)}
|
79
67
|
className="relative flex items-center text-sm font-semibold p-2 w-full"
|
80
68
|
>
|
81
|
-
{
|
69
|
+
{selectedSource && (
|
82
70
|
<>
|
83
71
|
<span className="sr-only">current source </span>
|
84
|
-
<Icon
|
85
|
-
|
72
|
+
<Icon
|
73
|
+
icon={selectedSource.resource?.type.code as IconOptions}
|
74
|
+
resourceSource="matrix"
|
75
|
+
aria-hidden
|
76
|
+
className="mr-2.5"
|
77
|
+
/>
|
78
|
+
<div className="truncate max-w-[200px]">{selectedSource.resource?.name || selectedSource.source.name}</div>
|
86
79
|
</>
|
87
80
|
)}
|
88
81
|
|
89
|
-
{!
|
82
|
+
{!selectedSource && (
|
90
83
|
<>
|
91
84
|
<span className="sr-only">view </span>
|
92
85
|
<Icon icon={'root' as IconOptions} aria-hidden className="mr-2.5" />
|
@@ -122,38 +115,38 @@ export default function SourceDropdown({
|
|
122
115
|
</li>
|
123
116
|
)}
|
124
117
|
{!isLoading &&
|
125
|
-
|
118
|
+
categorisedSources.map(({ key, label, sources }, index) => {
|
126
119
|
return (
|
127
|
-
<li
|
128
|
-
key={sourceId}
|
129
|
-
className={`flex flex-col text-sm font-semibold text-grey-800 ${index > 0 ? 'mt-3' : ''}`}
|
130
|
-
>
|
120
|
+
<li key={key} className={`flex flex-col text-sm font-semibold text-grey-800 ${index > 0 ? 'mt-3' : ''}`}>
|
131
121
|
<div className="relative flex justify-center before:w-full before:h-px before:bg-gray-300 before:absolute before:top-2/4 before:z-0">
|
132
|
-
<span className="z-10 bg-gray-100 px-2.5">{
|
122
|
+
<span className="z-10 bg-gray-100 px-2.5">{label}</span>
|
133
123
|
</div>
|
134
|
-
{
|
135
|
-
<ul aria-label={`${
|
136
|
-
{
|
124
|
+
{sources?.length > 0 && (
|
125
|
+
<ul aria-label={`${label} nodes`} className="flex flex-col mt-2">
|
126
|
+
{sources.map(({ source, resource }) => {
|
127
|
+
const isSelectedSource =
|
128
|
+
source.id === selectedSource?.source.id && resource?.id === selectedSource?.resource?.id;
|
129
|
+
|
137
130
|
return (
|
138
131
|
<li
|
139
|
-
key={`${
|
132
|
+
key={`${source.id}-${resource?.id}`}
|
140
133
|
className="flex items-center bg-white border border-b-0 last:border-b border-grey-200 first:rounded-t last:rounded-b"
|
141
134
|
>
|
142
135
|
<button
|
143
136
|
type="button"
|
144
|
-
onClick={() => handleSourceClick(
|
137
|
+
onClick={() => handleSourceClick({ source, resource })}
|
145
138
|
className={`relative grow flex items-center p-2.5 hover:bg-gray-100 focus:bg-gray-100 ${
|
146
|
-
|
139
|
+
isSelectedSource ? 'bg-blue-100 text-blue-400' : ''
|
147
140
|
}`}
|
148
141
|
>
|
149
142
|
<Icon
|
150
|
-
icon={type as IconOptions}
|
143
|
+
icon={resource?.type.code as IconOptions}
|
151
144
|
resourceSource="matrix"
|
152
|
-
aria-label={type}
|
145
|
+
aria-label={resource?.type.name}
|
153
146
|
className="shrink-0 mr-2.5"
|
154
147
|
/>
|
155
|
-
<span className="text-left mr-7">{
|
156
|
-
{
|
148
|
+
<span className="text-left mr-7">{resource?.name || source.name}</span>
|
149
|
+
{isSelectedSource && (
|
157
150
|
<Icon
|
158
151
|
icon={'selected' as IconOptions}
|
159
152
|
aria-label="selected"
|
@@ -2,63 +2,60 @@
|
|
2
2
|
import React from 'react';
|
3
3
|
import { screen, render, waitFor, within } from '@testing-library/react';
|
4
4
|
import userEvent from '@testing-library/user-event';
|
5
|
-
|
5
|
+
import { mockSource } from '../__mocks__/MockModels';
|
6
6
|
import { useOverlayTriggerState, OverlayTriggerState } from 'react-stately';
|
7
7
|
import SourceList from './SourceList';
|
8
|
+
import { Source } from '../types';
|
8
9
|
|
9
|
-
const sources = [
|
10
|
-
{
|
10
|
+
const sources: Source[] = [
|
11
|
+
mockSource({
|
11
12
|
id: '1',
|
12
13
|
name: 'Source 1',
|
13
14
|
nodes: [
|
14
15
|
{
|
15
|
-
id:
|
16
|
-
|
17
|
-
|
16
|
+
id: '1',
|
17
|
+
type: {
|
18
|
+
code: 'site',
|
19
|
+
name: 'Site',
|
18
20
|
},
|
19
|
-
|
20
|
-
selected: false,
|
21
|
-
label: 'Node 1',
|
21
|
+
name: 'Node 1',
|
22
22
|
childCount: 21,
|
23
23
|
},
|
24
24
|
{
|
25
|
-
id:
|
26
|
-
|
27
|
-
|
25
|
+
id: '2',
|
26
|
+
type: {
|
27
|
+
code: 'site',
|
28
|
+
name: 'Site',
|
28
29
|
},
|
29
|
-
|
30
|
-
selected: false,
|
31
|
-
label: 'Node 2',
|
30
|
+
name: 'Node 2',
|
32
31
|
childCount: 13,
|
33
32
|
},
|
34
33
|
],
|
35
|
-
},
|
36
|
-
{
|
34
|
+
}),
|
35
|
+
mockSource({
|
37
36
|
id: '2',
|
38
37
|
name: 'Source 2',
|
39
38
|
nodes: [
|
40
39
|
{
|
41
|
-
id:
|
42
|
-
|
43
|
-
|
40
|
+
id: '3',
|
41
|
+
type: {
|
42
|
+
code: 'site',
|
43
|
+
name: 'Site',
|
44
44
|
},
|
45
|
-
|
46
|
-
selected: false,
|
47
|
-
label: 'Node 3',
|
45
|
+
name: 'Node 3',
|
48
46
|
childCount: 15,
|
49
47
|
},
|
50
48
|
{
|
51
|
-
id:
|
52
|
-
|
53
|
-
|
49
|
+
id: '4',
|
50
|
+
type: {
|
51
|
+
code: 'site',
|
52
|
+
name: 'Site',
|
54
53
|
},
|
55
|
-
|
56
|
-
selected: false,
|
57
|
-
label: 'Node 4',
|
54
|
+
name: 'Node 4',
|
58
55
|
childCount: 10,
|
59
56
|
},
|
60
57
|
],
|
61
|
-
},
|
58
|
+
}),
|
62
59
|
];
|
63
60
|
|
64
61
|
function SourceListTestWrapper({
|
@@ -191,7 +188,13 @@ describe('SourceList', () => {
|
|
191
188
|
|
192
189
|
await waitFor(() => {
|
193
190
|
// Provides the item that was clicked and an id reference to the button that was clicked
|
194
|
-
expect(onSourceSelect).toHaveBeenCalledWith(
|
191
|
+
expect(onSourceSelect).toHaveBeenCalledWith(
|
192
|
+
{
|
193
|
+
source: sources[0],
|
194
|
+
resource: sources[0].nodes[0],
|
195
|
+
},
|
196
|
+
{ id: expect.any(String) },
|
197
|
+
);
|
195
198
|
});
|
196
199
|
});
|
197
200
|
|
@@ -218,7 +221,10 @@ describe('SourceList', () => {
|
|
218
221
|
user.click(screen.getByRole('button', { name: 'Drill down to Node 1 children' }));
|
219
222
|
|
220
223
|
await waitFor(() => {
|
221
|
-
expect(onSourceDrillDown).toHaveBeenCalledWith({
|
224
|
+
expect(onSourceDrillDown).toHaveBeenCalledWith({
|
225
|
+
source: sources[0],
|
226
|
+
resource: sources[0].nodes[0],
|
227
|
+
});
|
222
228
|
});
|
223
229
|
});
|
224
230
|
});
|
@@ -3,16 +3,17 @@ import { OverlayTriggerState } from 'react-stately';
|
|
3
3
|
import { DOMAttributes, FocusableElement } from '@react-types/shared';
|
4
4
|
|
5
5
|
import ResourceItem from '../ResourceItem/ResourceItem';
|
6
|
-
import {
|
6
|
+
import { Source, ScopedSource } from '../types';
|
7
7
|
import { SkeletonList } from '../Skeleton/List/SkeletonList';
|
8
8
|
import clsx from 'clsx';
|
9
|
+
import { useCategorisedSources } from '../Hooks/useCategorisedSources';
|
9
10
|
|
10
11
|
export interface SourceListProps {
|
11
|
-
sources:
|
12
|
+
sources: Source[];
|
12
13
|
previewModalState: OverlayTriggerState;
|
13
14
|
isLoading: boolean;
|
14
|
-
onSourceSelect: (node:
|
15
|
-
onSourceDrillDown: (node:
|
15
|
+
onSourceSelect: (node: ScopedSource, overlayProps: DOMAttributes<FocusableElement>) => void;
|
16
|
+
onSourceDrillDown: (node: ScopedSource) => void;
|
16
17
|
allowedTypes?: string[] | undefined;
|
17
18
|
}
|
18
19
|
|
@@ -24,6 +25,7 @@ const SourceList = function ({
|
|
24
25
|
onSourceDrillDown,
|
25
26
|
allowedTypes,
|
26
27
|
}: SourceListProps) {
|
28
|
+
const categorisedSources = useCategorisedSources(sources);
|
27
29
|
const listRef = useRef<HTMLUListElement>(null);
|
28
30
|
|
29
31
|
useEffect(() => {
|
@@ -53,26 +55,22 @@ const SourceList = function ({
|
|
53
55
|
)}
|
54
56
|
|
55
57
|
{!isLoading &&
|
56
|
-
|
58
|
+
categorisedSources.map(({ key, label, sources }, index) => {
|
57
59
|
return (
|
58
|
-
<li
|
59
|
-
key={sourceId}
|
60
|
-
className={`flex flex-col text-sm font-semibold text-grey-800 ${index > 0 ? 'mt-3' : ''}`}
|
61
|
-
>
|
60
|
+
<li key={key} className={`flex flex-col text-sm font-semibold text-grey-800 ${index > 0 ? 'mt-3' : ''}`}>
|
62
61
|
<div className="relative flex justify-center before:w-full before:h-px before:bg-gray-300 before:absolute before:top-2/4 before:z-0">
|
63
|
-
<span className="z-10 bg-gray-100 px-2.5">{
|
62
|
+
<span className="z-10 bg-gray-100 px-2.5">{label}</span>
|
64
63
|
</div>
|
65
|
-
{
|
66
|
-
<ul aria-label={`${
|
67
|
-
{
|
64
|
+
{sources.length > 0 && (
|
65
|
+
<ul aria-label={`${label} nodes`} className="flex flex-col">
|
66
|
+
{sources.map(({ source, resource }) => {
|
68
67
|
return (
|
69
68
|
<ResourceItem
|
70
|
-
key={`${
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
childCount={childCount}
|
69
|
+
key={`${source.id}-${resource?.id}`}
|
70
|
+
item={{ source, resource }}
|
71
|
+
label={resource?.name || source.name}
|
72
|
+
type={resource?.type.code || 'folder'}
|
73
|
+
childCount={resource?.childCount || 0}
|
76
74
|
previewModalState={previewModalState}
|
77
75
|
onSelect={onSourceSelect}
|
78
76
|
onDrillDown={onSourceDrillDown}
|
@@ -4,24 +4,43 @@
|
|
4
4
|
"name": "Acme corporate system",
|
5
5
|
"nodes": [
|
6
6
|
{
|
7
|
-
"id":
|
8
|
-
|
9
|
-
"
|
7
|
+
"id": "1",
|
8
|
+
"type": {
|
9
|
+
"code": "site",
|
10
|
+
"name": "Site"
|
10
11
|
},
|
11
|
-
"
|
12
|
-
|
13
|
-
|
12
|
+
"status": {
|
13
|
+
"code": "live",
|
14
|
+
"name": "Live"
|
15
|
+
},
|
16
|
+
"name": "HandyHomes Website",
|
14
17
|
"childCount": 21
|
15
18
|
},
|
16
19
|
{
|
17
|
-
"id":
|
18
|
-
|
19
|
-
"
|
20
|
+
"id": "2",
|
21
|
+
"type": {
|
22
|
+
"code": "site",
|
23
|
+
"name": "Site"
|
24
|
+
},
|
25
|
+
"status": {
|
26
|
+
"code": "live",
|
27
|
+
"name": "Live"
|
20
28
|
},
|
21
|
-
"
|
22
|
-
"selected": false,
|
23
|
-
"label": "Another Website very long title to make it wrap to multiple lines",
|
29
|
+
"name": "Another Website very long title to make it wrap to multiple lines",
|
24
30
|
"childCount": 135877
|
31
|
+
},
|
32
|
+
{
|
33
|
+
"id": "3",
|
34
|
+
"type": {
|
35
|
+
"code": "folder",
|
36
|
+
"name": "Folder"
|
37
|
+
},
|
38
|
+
"status": {
|
39
|
+
"code": "live",
|
40
|
+
"name": "Live"
|
41
|
+
},
|
42
|
+
"name": "Images",
|
43
|
+
"childCount": 100
|
25
44
|
}
|
26
45
|
]
|
27
46
|
},
|
@@ -30,81 +49,171 @@
|
|
30
49
|
"name": "Acme internal system",
|
31
50
|
"nodes": [
|
32
51
|
{
|
33
|
-
"id":
|
34
|
-
|
35
|
-
"
|
52
|
+
"id": "4",
|
53
|
+
"type": {
|
54
|
+
"code": "site",
|
55
|
+
"name": "Site"
|
56
|
+
},
|
57
|
+
"status": {
|
58
|
+
"code": "live",
|
59
|
+
"name": "Live"
|
36
60
|
},
|
37
|
-
"
|
38
|
-
"selected": false,
|
39
|
-
"label": "Intranet Website",
|
61
|
+
"name": "Intranet Website",
|
40
62
|
"childCount": 15
|
41
63
|
},
|
42
64
|
{
|
43
|
-
"id":
|
44
|
-
|
45
|
-
"
|
65
|
+
"id": "5",
|
66
|
+
"type": {
|
67
|
+
"code": "site",
|
68
|
+
"name": "Site"
|
69
|
+
},
|
70
|
+
"status": {
|
71
|
+
"code": "live",
|
72
|
+
"name": "Live"
|
46
73
|
},
|
47
|
-
"
|
48
|
-
"selected": false,
|
49
|
-
"label": "Social Website",
|
74
|
+
"name": "Social Website",
|
50
75
|
"childCount": 10
|
51
76
|
}
|
52
77
|
]
|
53
78
|
},
|
54
79
|
{
|
55
80
|
"id": "3",
|
56
|
-
"name": "
|
57
|
-
"nodes": [
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
81
|
+
"name": "Digital asset manager",
|
82
|
+
"nodes": []
|
83
|
+
},
|
84
|
+
{
|
85
|
+
"id": "4",
|
86
|
+
"name": "Unsplash image library",
|
87
|
+
"nodes": []
|
88
|
+
},
|
89
|
+
{
|
90
|
+
"id": "5",
|
91
|
+
"name": "Unsplash image library 2",
|
92
|
+
"nodes": []
|
93
|
+
},
|
94
|
+
{
|
95
|
+
"id": "6",
|
96
|
+
"name": "Unsplash image library 3",
|
97
|
+
"nodes": []
|
98
|
+
},
|
99
|
+
{
|
100
|
+
"id": "7",
|
101
|
+
"name": "Unsplash image library 4",
|
102
|
+
"nodes": []
|
103
|
+
},
|
104
|
+
{
|
105
|
+
"id": "8",
|
106
|
+
"name": "Unsplash image library 5",
|
107
|
+
"nodes": []
|
108
|
+
},
|
109
|
+
{
|
110
|
+
"id": "9",
|
111
|
+
"name": "Unsplash image library 6",
|
112
|
+
"nodes": []
|
113
|
+
},
|
114
|
+
{
|
115
|
+
"id": "10",
|
116
|
+
"name": "Unsplash image library 7",
|
117
|
+
"nodes": []
|
118
|
+
},
|
119
|
+
{
|
120
|
+
"id": "11",
|
121
|
+
"name": "Unsplash image library 8",
|
122
|
+
"nodes": []
|
123
|
+
},
|
124
|
+
{
|
125
|
+
"id": "12",
|
126
|
+
"name": "Unsplash image library 9",
|
127
|
+
"nodes": []
|
128
|
+
},
|
129
|
+
{
|
130
|
+
"id": "13",
|
131
|
+
"name": "Unsplash image library 10",
|
132
|
+
"nodes": []
|
133
|
+
},
|
134
|
+
{
|
135
|
+
"id": "14",
|
136
|
+
"name": "Unsplash image library 11",
|
137
|
+
"nodes": []
|
138
|
+
},
|
139
|
+
{
|
140
|
+
"id": "15",
|
141
|
+
"name": "Unsplash image library 12",
|
142
|
+
"nodes": []
|
143
|
+
},
|
144
|
+
{
|
145
|
+
"id": "16",
|
146
|
+
"name": "Unsplash image library 13",
|
147
|
+
"nodes": []
|
148
|
+
},
|
149
|
+
{
|
150
|
+
"id": "17",
|
151
|
+
"name": "Unsplash image library 14",
|
152
|
+
"nodes": []
|
153
|
+
},
|
154
|
+
{
|
155
|
+
"id": "18",
|
156
|
+
"name": "Unsplash image library 15",
|
157
|
+
"nodes": []
|
158
|
+
},
|
159
|
+
{
|
160
|
+
"id": "19",
|
161
|
+
"name": "Unsplash image library 16",
|
162
|
+
"nodes": []
|
163
|
+
},
|
164
|
+
{
|
165
|
+
"id": "20",
|
166
|
+
"name": "Unsplash image library 17",
|
167
|
+
"nodes": []
|
168
|
+
},
|
169
|
+
{
|
170
|
+
"id": "21",
|
171
|
+
"name": "Unsplash image library 18",
|
172
|
+
"nodes": []
|
173
|
+
},
|
174
|
+
{
|
175
|
+
"id": "22",
|
176
|
+
"name": "Unsplash image library 19",
|
177
|
+
"nodes": []
|
178
|
+
},
|
179
|
+
{
|
180
|
+
"id": "23",
|
181
|
+
"name": "Unsplash image library 20",
|
182
|
+
"nodes": []
|
183
|
+
},
|
184
|
+
{
|
185
|
+
"id": "24",
|
186
|
+
"name": "Unsplash image library 21",
|
187
|
+
"nodes": []
|
188
|
+
},
|
189
|
+
{
|
190
|
+
"id": "25",
|
191
|
+
"name": "Unsplash image library 22",
|
192
|
+
"nodes": []
|
193
|
+
},
|
194
|
+
{
|
195
|
+
"id": "26",
|
196
|
+
"name": "Unsplash image library 23",
|
197
|
+
"nodes": []
|
198
|
+
},
|
199
|
+
{
|
200
|
+
"id": "27",
|
201
|
+
"name": "Unsplash image library 24",
|
202
|
+
"nodes": []
|
203
|
+
},
|
204
|
+
{
|
205
|
+
"id": "28",
|
206
|
+
"name": "Unsplash image library 25",
|
207
|
+
"nodes": []
|
208
|
+
},
|
209
|
+
{
|
210
|
+
"id": "29",
|
211
|
+
"name": "Unsplash image library 26",
|
212
|
+
"nodes": []
|
213
|
+
},
|
214
|
+
{
|
215
|
+
"id": "30",
|
216
|
+
"name": "Unsplash image library 27",
|
217
|
+
"nodes": []
|
109
218
|
}
|
110
219
|
]
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import { DeepPartial, Resource, ScopedSource, Source } from '../types';
|
2
|
+
|
3
|
+
export const mockSource = (properties: DeepPartial<Source> = {}): Source => {
|
4
|
+
return {
|
5
|
+
id: '1',
|
6
|
+
name: 'Test source',
|
7
|
+
...properties,
|
8
|
+
nodes: properties?.nodes?.map((node) => mockResource(node as Partial<Resource>)) || [],
|
9
|
+
};
|
10
|
+
};
|
11
|
+
|
12
|
+
export const mockResource = (properties: Partial<Resource> = {}): Resource => {
|
13
|
+
return {
|
14
|
+
id: '1',
|
15
|
+
name: 'Test resource',
|
16
|
+
type: { code: 'folder', name: 'Folder' },
|
17
|
+
status: { code: 'live', name: 'Live' },
|
18
|
+
url: 'https://no-where.com',
|
19
|
+
urls: [],
|
20
|
+
childCount: 0,
|
21
|
+
...properties,
|
22
|
+
};
|
23
|
+
};
|
24
|
+
|
25
|
+
export const mockScopedSource = (properties: DeepPartial<ScopedSource> = {}): ScopedSource => {
|
26
|
+
return {
|
27
|
+
source: mockSource(properties?.source),
|
28
|
+
resource: properties?.resource ? mockResource(properties?.resource as Partial<Resource>) : null,
|
29
|
+
};
|
30
|
+
};
|