@seafile/seafile-database 0.0.47 → 0.0.49

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/dist/api/api.js CHANGED
@@ -300,5 +300,16 @@ class SeafileAPI {
300
300
  const url = this.server + '/api/v2.1/repos/' + repoID + '/metadata/';
301
301
  return this.req.get(url);
302
302
  }
303
+ listDirRecursive(repoID) {
304
+ const url = this.server + '/api/v2.1/repos/' + repoID + '/dir/';
305
+ const params = {
306
+ p: '/',
307
+ recursive: 1,
308
+ t: 'd'
309
+ };
310
+ return this.req.get(url, {
311
+ params
312
+ });
313
+ }
303
314
  }
304
315
  var _default = exports.default = SeafileAPI;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.fetchAllParentDirs = void 0;
7
+ const EXCLUDED_PARENT_DIRS = ['/images', '/_Internal'];
8
+ const normalizeParentDir = path => {
9
+ if (typeof path !== 'string') return '/';
10
+ let normalized = path.trim();
11
+ if (!normalized) return '/';
12
+ if (!normalized.startsWith('/')) normalized = `/${normalized}`;
13
+ normalized = normalized.replace(/\/+$/g, '');
14
+ return normalized || '/';
15
+ };
16
+ const isExcludedParentDir = path => {
17
+ return EXCLUDED_PARENT_DIRS.some(root => path === root || path.startsWith(`${root}/`));
18
+ };
19
+ const getParentDirAncestors = path => {
20
+ const normalized = normalizeParentDir(path);
21
+ if (normalized === '/') return ['/'];
22
+ const segments = normalized.split('/').filter(Boolean);
23
+ const ancestors = ['/'];
24
+ let current = '';
25
+ segments.forEach(segment => {
26
+ current = `${current}/${segment}`;
27
+ ancestors.push(current);
28
+ });
29
+ return ancestors;
30
+ };
31
+ const getParentDirDepth = path => {
32
+ if (path === '/') return 0;
33
+ return path.split('/').filter(Boolean).length;
34
+ };
35
+ const sortParentDirs = (a, b) => {
36
+ if (a === '/') return -1;
37
+ if (b === '/') return 1;
38
+ const depthDiff = getParentDirDepth(a) - getParentDirDepth(b);
39
+ if (depthDiff !== 0) return depthDiff;
40
+ return a.localeCompare(b);
41
+ };
42
+ const fetchAllParentDirs = async context => {
43
+ try {
44
+ var _res$data;
45
+ const res = await context.listDirRecursive();
46
+ const dirents = (res === null || res === void 0 ? void 0 : (_res$data = res.data) === null || _res$data === void 0 ? void 0 : _res$data.dirent_list) || [];
47
+ const dirSet = new Set(['/']);
48
+ dirents.forEach(dirent => {
49
+ const fullPath = `${dirent.parent_dir}/${dirent.name}`.replace(/\/+/g, '/');
50
+ if (isExcludedParentDir(fullPath)) {
51
+ return;
52
+ }
53
+ getParentDirAncestors(fullPath).forEach(dirPath => dirSet.add(dirPath));
54
+ });
55
+ return Array.from(dirSet).sort(sortParentDirs);
56
+ } catch (error) {
57
+ return ['/'];
58
+ }
59
+ };
60
+ exports.fetchAllParentDirs = fetchAllParentDirs;
@@ -11,6 +11,7 @@ var _reactstrap = require("reactstrap");
11
11
  var _translate = _interopRequireDefault(require("../../../../lang/translate"));
12
12
  var _column = require("../../../../utils/column");
13
13
  var _constants = require("../../../../constants");
14
+ var _parentDirFilter = _interopRequireDefault(require("./parent-dir-filter"));
14
15
  var _stateFilter = _interopRequireDefault(require("./state-filter"));
15
16
  var _tagsFilter = _interopRequireDefault(require("./tags-filter"));
16
17
  var _typeFilter = _interopRequireDefault(require("./type-filter"));
@@ -42,6 +43,16 @@ const BasicFilters = _ref => {
42
43
  };
43
44
  onChange && onChange(newFilters);
44
45
  }, [filters, onChange]);
46
+ const onParentDirChange = (0, _react.useCallback)(newValue => {
47
+ const filterIndex = filters.findIndex(filter => filter.column_key === '_parent_dir');
48
+ const filter = filters[filterIndex];
49
+ const newFilters = filters.slice(0);
50
+ newFilters[filterIndex] = {
51
+ ...filter,
52
+ filter_term: newValue
53
+ };
54
+ onChange && onChange(newFilters);
55
+ }, [filters, onChange]);
45
56
  const onTagsChange = (0, _react.useCallback)(newValue => {
46
57
  const filterIndex = filters.findIndex(filter => filter.column_key === '_tags');
47
58
  const filter = filters[filterIndex];
@@ -91,6 +102,14 @@ const BasicFilters = _ref => {
91
102
  onChange: onTagsChange
92
103
  });
93
104
  }
105
+ if (column_key === '_parent_dir') {
106
+ return /*#__PURE__*/_react.default.createElement(_parentDirFilter.default, {
107
+ readOnly: readOnly,
108
+ value: filter_term,
109
+ key: column_key,
110
+ onChange: onParentDirChange
111
+ });
112
+ }
94
113
  return null;
95
114
  }))));
96
115
  };
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _classnames = _interopRequireDefault(require("classnames"));
11
+ var _components = require("../../../../common/components");
12
+ var _hooks = require("../../../../hooks");
13
+ var _translate = _interopRequireDefault(require("../../../../lang/translate"));
14
+ var _helper = require("./helper");
15
+ const ParentDirFilter = _ref => {
16
+ let {
17
+ readOnly,
18
+ value = [],
19
+ onChange: onChangeAPI
20
+ } = _ref;
21
+ const {
22
+ context
23
+ } = (0, _hooks.useFileViewContext)();
24
+ const [isLoading, setIsLoading] = (0, _react.useState)(false);
25
+ const [directories, setDirectories] = (0, _react.useState)([]);
26
+ const [isInitialized, setIsInitialized] = (0, _react.useState)(false);
27
+ (0, _react.useEffect)(() => {
28
+ let isCanceled = false;
29
+ const loadParentDirs = async () => {
30
+ setIsLoading(true);
31
+ try {
32
+ const allDirs = await (0, _helper.fetchAllParentDirs)(context);
33
+ if (!isCanceled) {
34
+ setDirectories(allDirs);
35
+ }
36
+ } catch (error) {
37
+ if (!isCanceled) {
38
+ setDirectories([]);
39
+ }
40
+ } finally {
41
+ if (!isCanceled) {
42
+ setIsLoading(false);
43
+ }
44
+ }
45
+ };
46
+ loadParentDirs();
47
+ return () => {
48
+ isCanceled = true;
49
+ };
50
+ }, [context]);
51
+
52
+ // If selected value is 0, default to select root directory "/"
53
+ (0, _react.useEffect)(() => {
54
+ if (directories.length > 0 && value.length === 0 && !isLoading && !isInitialized) {
55
+ setIsInitialized(true);
56
+ onChangeAPI(['/']);
57
+ }
58
+ }, [directories, value.length, isLoading, isInitialized, onChangeAPI]);
59
+ const options = (0, _react.useMemo)(() => {
60
+ if (isLoading && directories.length === 0) {
61
+ return [{
62
+ value: '__loading__',
63
+ label: /*#__PURE__*/_react.default.createElement("div", {
64
+ className: "select-basic-filter-option"
65
+ }, /*#__PURE__*/_react.default.createElement("div", {
66
+ className: "select-basic-filter-option-name"
67
+ }, _translate.default.gettext('Loading...')))
68
+ }];
69
+ }
70
+ if (directories.length === 0) {
71
+ return [{
72
+ value: '__empty__',
73
+ label: /*#__PURE__*/_react.default.createElement("div", {
74
+ className: "select-basic-filter-option"
75
+ }, /*#__PURE__*/_react.default.createElement("div", {
76
+ className: "select-basic-filter-option-name"
77
+ }, _translate.default.gettext('No options')))
78
+ }];
79
+ }
80
+ return directories.map(dirPath => {
81
+ return {
82
+ value: dirPath,
83
+ label: /*#__PURE__*/_react.default.createElement("div", {
84
+ className: "select-basic-filter-option"
85
+ }, /*#__PURE__*/_react.default.createElement("div", {
86
+ className: "select-basic-filter-option-checkbox mr-2"
87
+ }, /*#__PURE__*/_react.default.createElement("input", {
88
+ type: "checkbox",
89
+ className: "form-check-input",
90
+ checked: value.includes(dirPath),
91
+ readOnly: true
92
+ })), /*#__PURE__*/_react.default.createElement("div", {
93
+ className: "select-basic-filter-option-name",
94
+ title: dirPath,
95
+ "aria-label": dirPath
96
+ }, dirPath))
97
+ };
98
+ });
99
+ }, [directories, isLoading, value]);
100
+ const displayValue = (0, _react.useMemo)(() => {
101
+ return {
102
+ label: /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, _translate.default.gettext('Parent folder'))
103
+ };
104
+ }, []);
105
+ const onChange = (0, _react.useCallback)(newValue => {
106
+ if (newValue === '__loading__' || newValue === '__empty__') return;
107
+ if (value.includes(newValue)) {
108
+ onChangeAPI(value.filter(v => v !== newValue));
109
+ } else {
110
+ onChangeAPI([...value, newValue]);
111
+ }
112
+ }, [value, onChangeAPI]);
113
+ return /*#__PURE__*/_react.default.createElement(_components.CustomizeSelect, {
114
+ disabled: readOnly,
115
+ supportMultipleSelect: true,
116
+ className: (0, _classnames.default)('sea-metadata-basic-filters-select sea-metadata-table-view-basic-filter-folder-type-select mr-4', {
117
+ highlighted: value.length > 0
118
+ }),
119
+ value: displayValue,
120
+ options: options,
121
+ onChange: onChange
122
+ });
123
+ };
124
+ var _default = exports.default = ParentDirFilter;
@@ -23,7 +23,7 @@ const getOptions = () => [{
23
23
  }];
24
24
  const StateFilter = _ref => {
25
25
  let {
26
- readOnly = true,
26
+ readOnly,
27
27
  value = 'all',
28
28
  onChange: onChangeAPI
29
29
  } = _ref;
@@ -9,21 +9,42 @@ exports.default = void 0;
9
9
  var _react = _interopRequireWildcard(require("react"));
10
10
  var _classnames = _interopRequireDefault(require("classnames"));
11
11
  var _components = require("../../../../common/components");
12
+ var _constants = require("../../../../constants");
12
13
  var _translate = _interopRequireDefault(require("../../../../lang/translate"));
13
14
  const TypeFilter = _ref => {
14
15
  let {
15
- readOnly = true,
16
+ readOnly,
16
17
  value = [],
17
- column,
18
18
  onChange: onChangeAPI
19
19
  } = _ref;
20
+ const FILE_TYPE_OPTIONS = (0, _react.useMemo)(() => [{
21
+ value: _constants.PREDEFINED_FILE_TYPE_OPTION_KEY.PICTURE,
22
+ name: _translate.default.gettext('Picture')
23
+ }, {
24
+ value: _constants.PREDEFINED_FILE_TYPE_OPTION_KEY.DOCUMENT,
25
+ name: _translate.default.gettext('Document')
26
+ }, {
27
+ value: _constants.PREDEFINED_FILE_TYPE_OPTION_KEY.VIDEO,
28
+ name: _translate.default.gettext('Video')
29
+ }, {
30
+ value: _constants.PREDEFINED_FILE_TYPE_OPTION_KEY.AUDIO,
31
+ name: _translate.default.gettext('Audio')
32
+ }, {
33
+ value: _constants.PREDEFINED_FILE_TYPE_OPTION_KEY.CODE,
34
+ name: _translate.default.gettext('Code')
35
+ }, {
36
+ value: _constants.PREDEFINED_FILE_TYPE_OPTION_KEY.COMPRESSED,
37
+ name: _translate.default.gettext('Compressed')
38
+ }, {
39
+ value: _constants.PREDEFINED_FILE_TYPE_OPTION_KEY.DIAGRAM,
40
+ name: _translate.default.gettext('Diagram')
41
+ }], []);
20
42
  const options = (0, _react.useMemo)(() => {
21
- return column.data.options.map(o => {
22
- const {
23
- name
24
- } = o;
43
+ return FILE_TYPE_OPTIONS.map(option => {
44
+ const optionValue = option.value;
45
+ const name = option.name;
25
46
  return {
26
- value: o.id,
47
+ value: optionValue,
27
48
  label: /*#__PURE__*/_react.default.createElement("div", {
28
49
  className: "select-basic-filter-option"
29
50
  }, /*#__PURE__*/_react.default.createElement("div", {
@@ -31,7 +52,7 @@ const TypeFilter = _ref => {
31
52
  }, /*#__PURE__*/_react.default.createElement("input", {
32
53
  type: "checkbox",
33
54
  className: "form-check-input",
34
- checked: value.includes(o.id),
55
+ checked: value.includes(optionValue),
35
56
  readOnly: true
36
57
  })), /*#__PURE__*/_react.default.createElement("div", {
37
58
  className: "select-basic-filter-option-name",
@@ -40,7 +61,7 @@ const TypeFilter = _ref => {
40
61
  }, name))
41
62
  };
42
63
  });
43
- }, [column.data.options, value]);
64
+ }, [value, FILE_TYPE_OPTIONS]);
44
65
  const displayValue = (0, _react.useMemo)(() => {
45
66
  return {
46
67
  label: /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, _translate.default.gettext('File type'))
@@ -56,7 +77,7 @@ const TypeFilter = _ref => {
56
77
  return /*#__PURE__*/_react.default.createElement(_components.CustomizeSelect, {
57
78
  disabled: readOnly,
58
79
  supportMultipleSelect: true,
59
- className: (0, _classnames.default)('sea-metadata-basic-filters-select sea-metadata-table-view-basic-checkbox-select mr-4', {
80
+ className: (0, _classnames.default)('sea-metadata-basic-filters-select sea-metadata-table-view-basic-filter-file-type-select mr-4', {
60
81
  'highlighted': value.length > 0
61
82
  }),
62
83
  value: displayValue,
@@ -107,6 +107,10 @@ const VIEW_TYPE_DEFAULT_BASIC_FILTER = exports.VIEW_TYPE_DEFAULT_BASIC_FILTER =
107
107
  column_key: '_tags',
108
108
  filter_predicate: _filter.FILTER_PREDICATE_TYPE.HAS_ANY_OF,
109
109
  filter_term: []
110
+ }, {
111
+ column_key: '_parent_dir',
112
+ filter_predicate: _filter.FILTER_PREDICATE_TYPE.IS,
113
+ filter_term: []
110
114
  }],
111
115
  [VIEW_TYPE.CARD]: [{
112
116
  column_key: _column.PRIVATE_COLUMN_KEY.IS_DIR,
@@ -120,6 +124,10 @@ const VIEW_TYPE_DEFAULT_BASIC_FILTER = exports.VIEW_TYPE_DEFAULT_BASIC_FILTER =
120
124
  column_key: _column.PRIVATE_COLUMN_KEY.TAGS,
121
125
  filter_predicate: _filter.FILTER_PREDICATE_TYPE.HAS_ALL_OF,
122
126
  filter_term: []
127
+ }, {
128
+ column_key: '_parent_dir',
129
+ filter_predicate: _filter.FILTER_PREDICATE_TYPE.IS,
130
+ filter_term: []
123
131
  }],
124
132
  [VIEW_TYPE.GALLERY]: [],
125
133
  [VIEW_TYPE.KANBAN]: []
package/dist/context.js CHANGED
@@ -364,6 +364,13 @@ class Context {
364
364
  this.permission = _settings.permission || 'r';
365
365
  this.isViewComputedOnServer = isViewComputedOnServer;
366
366
  }
367
+ listDirRecursive() {
368
+ if (!this.api) return null;
369
+ const {
370
+ repoID
371
+ } = this.settings;
372
+ return this.api.listDirRecursive(repoID);
373
+ }
367
374
  }
368
375
 
369
376
  // const context = new Context();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seafile/seafile-database",
3
- "version": "0.0.47",
3
+ "version": "0.0.49",
4
4
  "private": false,
5
5
  "description": "This is a seafile database components",
6
6
  "main": "dist/index.js",
@@ -125,7 +125,7 @@
125
125
  "resolve": "^1.20.0",
126
126
  "resolve-url-loader": "5.0.0",
127
127
  "sass-loader": "^12.3.0",
128
- "seafile-js": "0.2.238",
128
+ "seafile-js": "0.2.239",
129
129
  "source-map-loader": "^3.0.0",
130
130
  "style-loader": "^3.3.1",
131
131
  "tailwindcss": "^3.0.2",