@ndla/ui 19.0.1 → 19.2.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/es/Breadcrumb/ActionBreadcrumb.js +9 -3
- package/es/MyNdla/Resource/Folder.js +7 -7
- package/es/Resource/ListResource.js +7 -7
- package/es/TreeStructure/FolderItem.js +54 -38
- package/es/TreeStructure/FolderItems.js +29 -35
- package/es/TreeStructure/FolderNameInput.js +11 -15
- package/es/TreeStructure/TreeStructure.js +64 -91
- package/es/TreeStructure/arrowNavigation.js +44 -0
- package/es/TreeStructure/helperFunctions.js +41 -35
- package/es/locale/messages-en.js +10 -1
- package/es/locale/messages-nb.js +10 -1
- package/es/locale/messages-nn.js +10 -1
- package/es/locale/messages-se.js +10 -1
- package/es/locale/messages-sma.js +10 -1
- package/lib/Breadcrumb/ActionBreadcrumb.js +9 -3
- package/lib/MyNdla/Resource/Folder.js +7 -7
- package/lib/Resource/ListResource.js +7 -7
- package/lib/TreeStructure/FolderItem.d.ts +6 -3
- package/lib/TreeStructure/FolderItem.js +55 -38
- package/lib/TreeStructure/FolderItems.d.ts +1 -1
- package/lib/TreeStructure/FolderItems.js +29 -35
- package/lib/TreeStructure/FolderNameInput.d.ts +3 -2
- package/lib/TreeStructure/FolderNameInput.js +11 -15
- package/lib/TreeStructure/TreeStructure.d.ts +1 -6
- package/lib/TreeStructure/TreeStructure.js +63 -92
- package/lib/TreeStructure/TreeStructure.types.d.ts +13 -20
- package/lib/TreeStructure/arrowNavigation.d.ts +9 -0
- package/lib/TreeStructure/arrowNavigation.js +54 -0
- package/lib/TreeStructure/helperFunctions.d.ts +3 -4
- package/lib/TreeStructure/helperFunctions.js +45 -35
- package/lib/locale/messages-en.d.ts +10 -1
- package/lib/locale/messages-en.js +10 -1
- package/lib/locale/messages-nb.d.ts +10 -1
- package/lib/locale/messages-nb.js +10 -1
- package/lib/locale/messages-nn.d.ts +10 -1
- package/lib/locale/messages-nn.js +10 -1
- package/lib/locale/messages-se.d.ts +10 -1
- package/lib/locale/messages-se.js +10 -1
- package/lib/locale/messages-sma.d.ts +10 -1
- package/lib/locale/messages-sma.js +10 -1
- package/package.json +5 -5
- package/src/Breadcrumb/ActionBreadcrumb.tsx +3 -0
- package/src/MyNdla/Resource/Folder.tsx +1 -1
- package/src/Resource/ListResource.tsx +4 -2
- package/src/TreeStructure/FolderItem.tsx +63 -40
- package/src/TreeStructure/FolderItems.tsx +26 -19
- package/src/TreeStructure/FolderNameInput.tsx +9 -11
- package/src/TreeStructure/TreeStructure.tsx +56 -71
- package/src/TreeStructure/TreeStructure.types.ts +13 -17
- package/src/TreeStructure/arrowNavigation.ts +53 -0
- package/src/TreeStructure/helperFunctions.ts +17 -25
- package/src/locale/messages-en.ts +10 -1
- package/src/locale/messages-nb.ts +10 -1
- package/src/locale/messages-nn.ts +10 -1
- package/src/locale/messages-se.ts +10 -1
- package/src/locale/messages-sma.ts +10 -1
- package/es/TreeStructure/keyboardNavigation/keyboardNavigation.js +0 -194
- package/es/TreeStructure/keyboardNavigation/keyboardNavigation.types.js +0 -0
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.d.ts +0 -11
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.js +0 -198
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.types.d.ts +0 -26
- package/lib/TreeStructure/keyboardNavigation/keyboardNavigation.types.js +0 -1
- package/src/TreeStructure/keyboardNavigation/keyboardNavigation.ts +0 -161
- package/src/TreeStructure/keyboardNavigation/keyboardNavigation.types.ts +0 -28
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import React, { useEffect, useState, useRef, useMemo } from 'react';
|
|
10
|
-
import { uuid } from '@ndla/util';
|
|
11
10
|
import { AddButton } from '@ndla/button';
|
|
12
11
|
import Tooltip from '@ndla/tooltip';
|
|
13
12
|
import { useTranslation } from 'react-i18next';
|
|
@@ -16,9 +15,8 @@ import { spacing, fonts } from '@ndla/core';
|
|
|
16
15
|
import { uniq } from 'lodash';
|
|
17
16
|
import TreeStructureStyledWrapper from './TreeStructureWrapper';
|
|
18
17
|
import FolderItems from './FolderItems';
|
|
19
|
-
import {
|
|
20
|
-
import
|
|
21
|
-
import { NewFolderProps, TreeStructureProps } from './TreeStructure.types';
|
|
18
|
+
import { getPathOfFolder, getFolderName, flattenFolders } from './helperFunctions';
|
|
19
|
+
import { TreeStructureProps } from './TreeStructure.types';
|
|
22
20
|
|
|
23
21
|
export const MAX_LEVEL_FOR_FOLDERS = 4;
|
|
24
22
|
|
|
@@ -32,26 +30,32 @@ const AddFolderWrapper = styled.div`
|
|
|
32
30
|
`;
|
|
33
31
|
|
|
34
32
|
const TreeStructure = ({
|
|
35
|
-
|
|
33
|
+
folders,
|
|
36
34
|
label,
|
|
37
35
|
editable,
|
|
38
36
|
loading,
|
|
39
37
|
onNewFolder,
|
|
38
|
+
onSelectFolder,
|
|
40
39
|
openOnFolderClick,
|
|
41
40
|
framed,
|
|
42
41
|
folderIdMarkedByDefault,
|
|
43
42
|
defaultOpenFolders,
|
|
44
43
|
folderChild,
|
|
45
|
-
maximumLevelsOfFoldersAllowed,
|
|
44
|
+
maximumLevelsOfFoldersAllowed = MAX_LEVEL_FOR_FOLDERS,
|
|
46
45
|
}: TreeStructureProps) => {
|
|
47
46
|
const { t } = useTranslation();
|
|
48
|
-
const [
|
|
47
|
+
const [newFolderParentId, setNewFolderParentId] = useState<string | undefined>();
|
|
49
48
|
const [openFolders, setOpenFolders] = useState<string[]>(defaultOpenFolders || []);
|
|
50
49
|
const [focusedFolderId, setFocusedFolderId] = useState<string | undefined>();
|
|
51
|
-
const [markedFolderId, setMarkedFolderId] = useState<string | undefined>(folderIdMarkedByDefault ||
|
|
50
|
+
const [markedFolderId, setMarkedFolderId] = useState<string | undefined>(folderIdMarkedByDefault || folders[0]?.id);
|
|
52
51
|
const treestructureRef = useRef<HTMLDivElement>(null);
|
|
53
52
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
54
|
-
const rootLevelId =
|
|
53
|
+
const rootLevelId = 'treestructure-root';
|
|
54
|
+
|
|
55
|
+
const visibleFolders = useMemo(
|
|
56
|
+
() => flattenFolders(folders, openFolders).map((folder) => folder.id),
|
|
57
|
+
[folders, openFolders],
|
|
58
|
+
);
|
|
55
59
|
|
|
56
60
|
useEffect(() => {
|
|
57
61
|
if (defaultOpenFolders) {
|
|
@@ -63,54 +67,51 @@ const TreeStructure = ({
|
|
|
63
67
|
|
|
64
68
|
useEffect(() => {
|
|
65
69
|
if (!loading) {
|
|
66
|
-
|
|
70
|
+
setNewFolderParentId(undefined);
|
|
67
71
|
}
|
|
68
72
|
}, [loading]);
|
|
69
73
|
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (
|
|
74
|
+
const onCloseFolder = (id: string) => {
|
|
75
|
+
// Did we just closed a folder with a marked folder inside it?
|
|
76
|
+
// If so, we need to mark the folder we just closed.
|
|
77
|
+
if (markedFolderId) {
|
|
78
|
+
const closingFolderPath = getPathOfFolder(folders, id);
|
|
79
|
+
const markedFolderPath = getPathOfFolder(folders, markedFolderId);
|
|
80
|
+
const markedFolderIsSubPath = closingFolderPath.every(
|
|
81
|
+
(folderId, _index) => markedFolderPath[_index] === folderId,
|
|
82
|
+
);
|
|
83
|
+
if (markedFolderIsSubPath) {
|
|
84
|
+
if (onSelectFolder) {
|
|
81
85
|
setMarkedFolderId(closingFolderPath[closingFolderPath.length - 1]);
|
|
86
|
+
onSelectFolder(closingFolderPath[closingFolderPath.length - 1]);
|
|
87
|
+
} else {
|
|
88
|
+
setFocusedFolderId(closingFolderPath[closingFolderPath.length - 1]);
|
|
82
89
|
}
|
|
83
90
|
}
|
|
84
|
-
setOpenFolders(openFolders.filter((folder) => folder !== id));
|
|
85
|
-
} else {
|
|
86
|
-
setOpenFolders(uniq([...openFolders, id]));
|
|
87
91
|
}
|
|
92
|
+
setOpenFolders(openFolders.filter((folder) => folder !== id));
|
|
88
93
|
};
|
|
89
94
|
|
|
90
|
-
const
|
|
91
|
-
|
|
95
|
+
const onOpenFolder = (id: string) => {
|
|
96
|
+
setOpenFolders(uniq(openFolders.concat(id)));
|
|
92
97
|
};
|
|
93
98
|
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
}
|
|
99
|
+
const onCreateNewFolder = (parentId: string) => {
|
|
100
|
+
setNewFolderParentId(parentId);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const onSaveNewFolder = (name: string, parentId: string) => {
|
|
104
|
+
onNewFolder(name, parentId).then((newFolderId) => {
|
|
105
|
+
if (newFolderId) {
|
|
106
|
+
setMarkedFolderId(newFolderId);
|
|
107
|
+
setFocusedFolderId(newFolderId);
|
|
108
|
+
setOpenFolders(uniq(openFolders.concat(parentId)));
|
|
109
|
+
}
|
|
110
|
+
});
|
|
110
111
|
};
|
|
111
112
|
|
|
112
113
|
const onCancelNewFolder = () => {
|
|
113
|
-
|
|
114
|
+
setNewFolderParentId(undefined);
|
|
114
115
|
};
|
|
115
116
|
|
|
116
117
|
const onMarkFolder = (id: string) => {
|
|
@@ -118,35 +119,25 @@ const TreeStructure = ({
|
|
|
118
119
|
setFocusedFolderId(id);
|
|
119
120
|
};
|
|
120
121
|
|
|
121
|
-
const paths = getPathOfFolder(
|
|
122
|
+
const paths = getPathOfFolder(folders, markedFolderId || '');
|
|
122
123
|
const canAddFolder = editable && paths.length < (maximumLevelsOfFoldersAllowed || 1);
|
|
123
124
|
|
|
124
125
|
return (
|
|
125
|
-
<div
|
|
126
|
-
ref={treestructureRef}
|
|
127
|
-
onKeyDown={(e) => {
|
|
128
|
-
if (wrapperRef.current?.contains(document.activeElement) && KEYBOARD_KEYS_OF_INTEREST.includes(e.key)) {
|
|
129
|
-
keyboardNavigation({
|
|
130
|
-
e,
|
|
131
|
-
data,
|
|
132
|
-
setFocusedFolderId,
|
|
133
|
-
focusedFolderId,
|
|
134
|
-
onToggleOpen,
|
|
135
|
-
openFolders,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
}}>
|
|
126
|
+
<div ref={treestructureRef}>
|
|
139
127
|
{label && <StyledLabel htmlFor={rootLevelId}>{label}</StyledLabel>}
|
|
140
128
|
<TreeStructureStyledWrapper ref={wrapperRef} id={rootLevelId} aria-label="Menu tree" role="tree" framed={framed}>
|
|
141
129
|
<FolderItems
|
|
142
|
-
|
|
143
|
-
|
|
130
|
+
onSelectFolder={onSelectFolder}
|
|
131
|
+
level={1}
|
|
132
|
+
folders={folders}
|
|
144
133
|
editable={editable}
|
|
145
|
-
|
|
146
|
-
|
|
134
|
+
onOpenFolder={onOpenFolder}
|
|
135
|
+
onCloseFolder={onCloseFolder}
|
|
136
|
+
newFolderParentId={newFolderParentId}
|
|
147
137
|
onCreateNewFolder={onCreateNewFolder}
|
|
148
138
|
onCancelNewFolder={onCancelNewFolder}
|
|
149
139
|
onSaveNewFolder={onSaveNewFolder}
|
|
140
|
+
visibleFolders={visibleFolders}
|
|
150
141
|
openFolders={openFolders}
|
|
151
142
|
markedFolderId={markedFolderId}
|
|
152
143
|
onMarkFolder={onMarkFolder}
|
|
@@ -154,7 +145,6 @@ const TreeStructure = ({
|
|
|
154
145
|
loading={loading}
|
|
155
146
|
focusedFolderId={focusedFolderId}
|
|
156
147
|
setFocusedFolderId={setFocusedFolderId}
|
|
157
|
-
firstLevel
|
|
158
148
|
folderChild={folderChild}
|
|
159
149
|
maximumLevelsOfFoldersAllowed={maximumLevelsOfFoldersAllowed}
|
|
160
150
|
/>
|
|
@@ -165,16 +155,15 @@ const TreeStructure = ({
|
|
|
165
155
|
tooltip={
|
|
166
156
|
canAddFolder
|
|
167
157
|
? t('myNdla.newFolderUnder', {
|
|
168
|
-
folderName: getFolderName(
|
|
158
|
+
folderName: getFolderName(folders, markedFolderId),
|
|
169
159
|
})
|
|
170
|
-
: t('
|
|
160
|
+
: t('treeStructure.maxFoldersAlreadyAdded')
|
|
171
161
|
}>
|
|
172
162
|
<AddButton
|
|
173
163
|
disabled={!canAddFolder}
|
|
174
164
|
aria-label={t('myNdla.newFolder')}
|
|
175
165
|
onClick={() => {
|
|
176
|
-
|
|
177
|
-
setNewFolder({ idPaths, parentId: paths[paths.length - 1] });
|
|
166
|
+
setNewFolderParentId(markedFolderId);
|
|
178
167
|
}}>
|
|
179
168
|
{t('myNdla.newFolder')}
|
|
180
169
|
</AddButton>
|
|
@@ -185,8 +174,4 @@ const TreeStructure = ({
|
|
|
185
174
|
);
|
|
186
175
|
};
|
|
187
176
|
|
|
188
|
-
TreeStructure.defaultProps = {
|
|
189
|
-
maximumLevelsOfFoldersAllowed: MAX_LEVEL_FOR_FOLDERS,
|
|
190
|
-
};
|
|
191
|
-
|
|
192
177
|
export default TreeStructure;
|
|
@@ -11,35 +11,29 @@ import React, { ReactNode } from 'react';
|
|
|
11
11
|
export interface FolderStructureProps {
|
|
12
12
|
id: string;
|
|
13
13
|
name: string;
|
|
14
|
-
|
|
15
|
-
data?: FolderStructureProps[];
|
|
14
|
+
subfolders: FolderStructureProps[];
|
|
16
15
|
isFavorite?: boolean;
|
|
17
16
|
status?: string;
|
|
18
17
|
openAsDefault?: boolean;
|
|
19
|
-
url?: string;
|
|
20
18
|
icon?: ReactNode;
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
export interface NewFolderProps {
|
|
24
|
-
parentId?: string;
|
|
25
|
-
idPaths: number[];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
21
|
interface CommonFolderProps {
|
|
29
|
-
data: FolderStructureProps[];
|
|
30
22
|
editable?: boolean;
|
|
31
23
|
loading?: boolean;
|
|
32
24
|
openOnFolderClick?: boolean;
|
|
25
|
+
onSelectFolder?: (id: string) => void;
|
|
33
26
|
}
|
|
34
27
|
|
|
35
28
|
export interface TreeStructureProps extends CommonFolderProps {
|
|
29
|
+
folders: FolderStructureProps[];
|
|
36
30
|
framed?: boolean;
|
|
37
31
|
label?: string;
|
|
38
32
|
folderIdMarkedByDefault?: string;
|
|
39
|
-
onNewFolder: (
|
|
33
|
+
onNewFolder: (name: string, parentId: string) => Promise<string>;
|
|
40
34
|
defaultOpenFolders?: string[];
|
|
41
35
|
folderChild?: FolderChildFuncType;
|
|
42
|
-
maximumLevelsOfFoldersAllowed
|
|
36
|
+
maximumLevelsOfFoldersAllowed?: number;
|
|
43
37
|
}
|
|
44
38
|
|
|
45
39
|
export type onCreateNewFolderProp = ({
|
|
@@ -56,18 +50,20 @@ export type SetFocusedFolderId = React.Dispatch<React.SetStateAction<string | un
|
|
|
56
50
|
export type FolderChildFuncType = (id: string, tabIndex: number) => ReactNode;
|
|
57
51
|
|
|
58
52
|
export interface FolderItemsProps extends CommonFolderProps {
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
folders: FolderStructureProps[];
|
|
54
|
+
onCloseFolder: (id: string) => void;
|
|
55
|
+
onOpenFolder: (id: string) => void;
|
|
56
|
+
onSaveNewFolder: (name: string, parentId: string) => void;
|
|
61
57
|
onCancelNewFolder: () => void;
|
|
62
|
-
onCreateNewFolder:
|
|
63
|
-
|
|
58
|
+
onCreateNewFolder: (parentId: string) => void;
|
|
59
|
+
newFolderParentId: string | undefined;
|
|
60
|
+
visibleFolders: string[];
|
|
64
61
|
openFolders: string[];
|
|
65
62
|
markedFolderId?: string;
|
|
66
63
|
onMarkFolder: (id: string) => void;
|
|
67
|
-
|
|
64
|
+
level: number;
|
|
68
65
|
focusedFolderId: string | undefined;
|
|
69
66
|
setFocusedFolderId: SetFocusedFolderId;
|
|
70
|
-
firstLevel: boolean;
|
|
71
67
|
keyNavigationFocusIsCreateFolderButton?: boolean;
|
|
72
68
|
icon?: ReactNode;
|
|
73
69
|
folderChild?: FolderChildFuncType;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2022-present, NDLA.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the GPLv3 license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { KeyboardEvent } from 'react';
|
|
10
|
+
|
|
11
|
+
const navigateVertical = (
|
|
12
|
+
visibleFolders: string[],
|
|
13
|
+
folderId: string,
|
|
14
|
+
setFocusedFolderId: (id: string) => void,
|
|
15
|
+
direction: 1 | -1,
|
|
16
|
+
) => {
|
|
17
|
+
const currentIndex = visibleFolders.findIndex((id) => id === folderId);
|
|
18
|
+
const target = visibleFolders[currentIndex + direction];
|
|
19
|
+
if (target !== undefined) {
|
|
20
|
+
setFocusedFolderId(target);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const arrowKeys = ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'];
|
|
25
|
+
|
|
26
|
+
export const arrowNavigation = (
|
|
27
|
+
e: KeyboardEvent<HTMLElement>,
|
|
28
|
+
id: string,
|
|
29
|
+
visibleFolders: string[],
|
|
30
|
+
setFocusedFolderId: (id: string) => void,
|
|
31
|
+
onOpen: (id: string) => void,
|
|
32
|
+
onClose: (id: string) => void,
|
|
33
|
+
) => {
|
|
34
|
+
if (!arrowKeys.includes(e.key)) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
e.stopPropagation();
|
|
40
|
+
|
|
41
|
+
switch (e.key) {
|
|
42
|
+
case 'ArrowUp':
|
|
43
|
+
return navigateVertical(visibleFolders, id, setFocusedFolderId, -1);
|
|
44
|
+
case 'ArrowDown':
|
|
45
|
+
return navigateVertical(visibleFolders, id, setFocusedFolderId, 1);
|
|
46
|
+
case 'ArrowLeft':
|
|
47
|
+
return onClose(id);
|
|
48
|
+
case 'ArrowRight':
|
|
49
|
+
return onOpen(id);
|
|
50
|
+
default:
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { FolderStructureProps } from './TreeStructure.types';
|
|
2
2
|
|
|
3
|
-
const getPathOfFolder = (data: FolderStructureProps[], findId: string): string[] => {
|
|
4
|
-
const paths = (
|
|
5
|
-
for (const { id,
|
|
3
|
+
export const getPathOfFolder = (data: FolderStructureProps[], findId: string): string[] => {
|
|
4
|
+
const paths = (folders: FolderStructureProps[], path: string[]): string[] => {
|
|
5
|
+
for (const { id, subfolders } of folders) {
|
|
6
6
|
if (id === findId) {
|
|
7
7
|
return [...path, id];
|
|
8
|
-
} else if (
|
|
9
|
-
return paths(
|
|
8
|
+
} else if (subfolders?.length) {
|
|
9
|
+
return paths(subfolders, [...path, id]);
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
return [];
|
|
@@ -14,33 +14,18 @@ const getPathOfFolder = (data: FolderStructureProps[], findId: string): string[]
|
|
|
14
14
|
return paths(data, []);
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
let currentPath: number[] = [];
|
|
19
|
-
const paths = (dataChildren: FolderStructureProps[], path: number[]) => {
|
|
20
|
-
dataChildren.forEach(({ id, data: dataChildrenSub }, _index) => {
|
|
21
|
-
if (id === findId) {
|
|
22
|
-
currentPath = [...path, _index];
|
|
23
|
-
} else if (dataChildrenSub?.length) {
|
|
24
|
-
paths(dataChildrenSub, [...path, _index]);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
paths(data, []);
|
|
29
|
-
return currentPath;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const getFolderName = (data: FolderStructureProps[], findId: string | undefined): string | undefined => {
|
|
17
|
+
export const getFolderName = (data: FolderStructureProps[], findId: string | undefined): string | undefined => {
|
|
33
18
|
if (!findId) {
|
|
34
19
|
return undefined;
|
|
35
20
|
}
|
|
36
21
|
let folderName: string | undefined;
|
|
37
22
|
const paths = (dataChildren: FolderStructureProps[]) => {
|
|
38
|
-
dataChildren.some(({ id, name,
|
|
23
|
+
dataChildren.some(({ id, name, subfolders }, _index) => {
|
|
39
24
|
if (id === findId) {
|
|
40
25
|
folderName = name;
|
|
41
26
|
return true;
|
|
42
|
-
} else if (
|
|
43
|
-
return paths(
|
|
27
|
+
} else if (subfolders?.length) {
|
|
28
|
+
return paths(subfolders);
|
|
44
29
|
}
|
|
45
30
|
return false;
|
|
46
31
|
});
|
|
@@ -49,4 +34,11 @@ const getFolderName = (data: FolderStructureProps[], findId: string | undefined)
|
|
|
49
34
|
return folderName;
|
|
50
35
|
};
|
|
51
36
|
|
|
52
|
-
export
|
|
37
|
+
export const flattenFolders = (folders: FolderStructureProps[], openFolders?: string[]): FolderStructureProps[] => {
|
|
38
|
+
return folders.reduce((acc, { subfolders, id, ...rest }) => {
|
|
39
|
+
if (!subfolders || (openFolders && !openFolders.includes(id))) {
|
|
40
|
+
return acc.concat({ subfolders, id, ...rest });
|
|
41
|
+
}
|
|
42
|
+
return acc.concat({ subfolders, id, ...rest }, flattenFolders(subfolders, openFolders));
|
|
43
|
+
}, [] as FolderStructureProps[]);
|
|
44
|
+
};
|
|
@@ -989,7 +989,13 @@ const messages = {
|
|
|
989
989
|
resources_plural: '{{count}} Resources',
|
|
990
990
|
folders: '{{count}} Folder',
|
|
991
991
|
folders_plural: '{{count}} Folders',
|
|
992
|
-
folder:
|
|
992
|
+
folder: {
|
|
993
|
+
folder: 'Folder',
|
|
994
|
+
delete: 'Delete',
|
|
995
|
+
edit: 'Edit',
|
|
996
|
+
},
|
|
997
|
+
confirmDeleteFolder: 'Are you sure you want to delete this folder? This process cannot be undone.',
|
|
998
|
+
confirmDeleteTag: 'Are you sure you want to delete this tag? This process cannot be undone.',
|
|
993
999
|
myFolders: 'My folders',
|
|
994
1000
|
myTags: 'My tags',
|
|
995
1001
|
newFolder: 'New folder',
|
|
@@ -1031,6 +1037,9 @@ const messages = {
|
|
|
1031
1037
|
},
|
|
1032
1038
|
},
|
|
1033
1039
|
resource: {
|
|
1040
|
+
add: 'Add folder/tag',
|
|
1041
|
+
remove: 'Remove',
|
|
1042
|
+
copyLink: 'Copy link to this page',
|
|
1034
1043
|
addToMyNdla: 'Add to My NDLA',
|
|
1035
1044
|
addedToMyNdla: 'Added to My NDLA',
|
|
1036
1045
|
},
|
|
@@ -987,7 +987,13 @@ const messages = {
|
|
|
987
987
|
resources_plural: '{{count}} ressurser',
|
|
988
988
|
folders: '{{count}} mappe',
|
|
989
989
|
folders_plural: '{{count}} mapper',
|
|
990
|
-
folder:
|
|
990
|
+
folder: {
|
|
991
|
+
folder: 'Mappe',
|
|
992
|
+
delete: 'Slett',
|
|
993
|
+
edit: 'Rediger',
|
|
994
|
+
},
|
|
995
|
+
confirmDeleteFolder: 'Er du sikker på at du vil slette mappen? Denne handlingen kan ikke angres.',
|
|
996
|
+
confirmDeleteTag: 'Er du sikker på at du vil slette tag? Denne handlingen kan ikke angres.',
|
|
991
997
|
myFolders: 'Mine mapper',
|
|
992
998
|
myTags: 'Mine tags',
|
|
993
999
|
newFolder: 'Ny mappe',
|
|
@@ -1028,6 +1034,9 @@ const messages = {
|
|
|
1028
1034
|
},
|
|
1029
1035
|
},
|
|
1030
1036
|
resource: {
|
|
1037
|
+
add: 'Legg til mappe/tag',
|
|
1038
|
+
remove: 'Fjern',
|
|
1039
|
+
copyLink: 'Kopier lenke til siden',
|
|
1031
1040
|
addToMyNdla: 'Legg i Min NDLA',
|
|
1032
1041
|
addedToMyNdla: 'Lagt i Min NDLA',
|
|
1033
1042
|
},
|
|
@@ -988,7 +988,13 @@ const messages = {
|
|
|
988
988
|
resources_plural: '{{count}} ressursar',
|
|
989
989
|
folders: '{{count}} mappe',
|
|
990
990
|
folders_plural: '{{count}} mapper',
|
|
991
|
-
folder:
|
|
991
|
+
folder: {
|
|
992
|
+
folder: 'Mappe',
|
|
993
|
+
delete: 'Slett',
|
|
994
|
+
edit: 'Rediger',
|
|
995
|
+
},
|
|
996
|
+
confirmDeleteFolder: 'Er du sikker på at du vil slette mappa? Denne handlinga kan ikkje angres.',
|
|
997
|
+
confirmDeleteTag: 'Er du sikker på at du vil slette tag? Denne handlinga kan ikkje angres.',
|
|
992
998
|
myFolders: 'Mine mapper',
|
|
993
999
|
myTags: 'Mine tags',
|
|
994
1000
|
newFolder: 'Ny mappe',
|
|
@@ -1029,6 +1035,9 @@ const messages = {
|
|
|
1029
1035
|
},
|
|
1030
1036
|
},
|
|
1031
1037
|
resource: {
|
|
1038
|
+
add: 'Legg til mappe/tag',
|
|
1039
|
+
remove: 'Fjern',
|
|
1040
|
+
copyLink: 'Kopier lenke til sida',
|
|
1032
1041
|
addToMyNdla: 'Legg i Min NDLA',
|
|
1033
1042
|
addedToMyNdla: 'Lagt i Min NDLA',
|
|
1034
1043
|
},
|
|
@@ -987,7 +987,13 @@ const messages = {
|
|
|
987
987
|
resources_plural: '{{count}} ressurser',
|
|
988
988
|
folders: '{{count}} mappe',
|
|
989
989
|
folders_plural: '{{count}} mapper',
|
|
990
|
-
folder:
|
|
990
|
+
folder: {
|
|
991
|
+
folder: 'Mappe',
|
|
992
|
+
delete: 'Slett',
|
|
993
|
+
edit: 'Rediger',
|
|
994
|
+
},
|
|
995
|
+
confirmDeleteFolder: 'Er du sikker på at du vil slette mappen? Denne handlingen kan ikke angres.',
|
|
996
|
+
confirmDeleteTag: 'Er du sikker på at du vil slette tag? Denne handlingen kan ikke angres.',
|
|
991
997
|
myFolders: 'Mine mapper',
|
|
992
998
|
myTags: 'Mine tags',
|
|
993
999
|
newFolder: 'Ny mappe',
|
|
@@ -1028,6 +1034,9 @@ const messages = {
|
|
|
1028
1034
|
},
|
|
1029
1035
|
},
|
|
1030
1036
|
resource: {
|
|
1037
|
+
add: 'Legg til mappe/tag',
|
|
1038
|
+
remove: 'Fjern',
|
|
1039
|
+
copyLink: 'Kopier lenke til siden',
|
|
1031
1040
|
addToMyNdla: 'Legg i Min NDLA',
|
|
1032
1041
|
addedToMyNdla: 'Lagt i Min NDLA',
|
|
1033
1042
|
},
|
|
@@ -987,7 +987,13 @@ const messages = {
|
|
|
987
987
|
resources_plural: '{{count}} ressurser',
|
|
988
988
|
folders: '{{count}} mappe',
|
|
989
989
|
folders_plural: '{{count}} mapper',
|
|
990
|
-
folder:
|
|
990
|
+
folder: {
|
|
991
|
+
folder: 'Mappe',
|
|
992
|
+
delete: 'Slett',
|
|
993
|
+
edit: 'Rediger',
|
|
994
|
+
},
|
|
995
|
+
confirmDeleteFolder: 'Er du sikker på at du vil slette mappen? Denne handlingen kan ikke angres.',
|
|
996
|
+
confirmDeleteTag: 'Er du sikker på at du vil slette tag? Denne handlingen kan ikke angres.',
|
|
991
997
|
myFolders: 'Mine mapper',
|
|
992
998
|
myTags: 'Mine tags',
|
|
993
999
|
newFolder: 'Ny mappe',
|
|
@@ -1028,6 +1034,9 @@ const messages = {
|
|
|
1028
1034
|
},
|
|
1029
1035
|
},
|
|
1030
1036
|
resource: {
|
|
1037
|
+
add: 'Legg til mappe/tag',
|
|
1038
|
+
remove: 'Fjern',
|
|
1039
|
+
copyLink: 'Kopier lenke til siden',
|
|
1031
1040
|
addToMyNdla: 'Legg i Min NDLA',
|
|
1032
1041
|
addedToMyNdla: 'Lagt i Min NDLA',
|
|
1033
1042
|
},
|