@iobroker/adapter-react-v5 4.13.4 → 4.13.5
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/Components/FileBrowser.js +162 -101
- package/README.md +1 -1
- package/package.json +1 -1
|
@@ -378,6 +378,17 @@ const styles = (theme) => ({
|
|
|
378
378
|
},
|
|
379
379
|
});
|
|
380
380
|
const USER_DATA = '0_userdata.0';
|
|
381
|
+
function getParentDir(dir) {
|
|
382
|
+
const parts = (dir || '').split('/');
|
|
383
|
+
parts.length && parts.pop();
|
|
384
|
+
return parts.join('/');
|
|
385
|
+
}
|
|
386
|
+
function isFile(path) {
|
|
387
|
+
const ext = Utils_1.default.getFileExtension(path);
|
|
388
|
+
return !!((ext === null || ext === void 0 ? void 0 : ext.toLowerCase().match(/[a-z]+/)) && ext.length < 5);
|
|
389
|
+
}
|
|
390
|
+
const TABLE = 'Table';
|
|
391
|
+
const TILE = 'Tile';
|
|
381
392
|
function sortFolders(a, b) {
|
|
382
393
|
if (a.folder && b.folder) {
|
|
383
394
|
return a.name > b.name ? 1 : (a.name < b.name ? -1 : 0);
|
|
@@ -390,17 +401,6 @@ function sortFolders(a, b) {
|
|
|
390
401
|
}
|
|
391
402
|
return a.name > b.name ? 1 : (a.name < b.name ? -1 : 0);
|
|
392
403
|
}
|
|
393
|
-
function getParentDir(dir) {
|
|
394
|
-
const parts = (dir || '').split('/');
|
|
395
|
-
parts.length && parts.pop();
|
|
396
|
-
return parts.join('/');
|
|
397
|
-
}
|
|
398
|
-
function isFile(path) {
|
|
399
|
-
const ext = Utils_1.default.getFileExtension(path);
|
|
400
|
-
return !!((ext === null || ext === void 0 ? void 0 : ext.toLowerCase().match(/[a-z]+/)) && ext.length < 5);
|
|
401
|
-
}
|
|
402
|
-
const TABLE = 'Table';
|
|
403
|
-
const TILE = 'Tile';
|
|
404
404
|
/**
|
|
405
405
|
* @extends {React.Component<import('./types').FileBrowserProps>}
|
|
406
406
|
*/
|
|
@@ -454,11 +454,11 @@ class FileBrowser extends react_1.Component {
|
|
|
454
454
|
return null;
|
|
455
455
|
}
|
|
456
456
|
};
|
|
457
|
-
|
|
457
|
+
const expandedStr = (window._localStorage || window.localStorage).getItem('files.expanded') || '[]';
|
|
458
458
|
if (this.props.limitPath) {
|
|
459
459
|
const parts = this.props.limitPath.split('/');
|
|
460
460
|
this.limitToObjectID = parts[0];
|
|
461
|
-
this.limitToPath = !parts.length ? null :
|
|
461
|
+
this.limitToPath = !parts.length ? null : parts.length === 1 && parts[0] === '' ? null : parts.join('/');
|
|
462
462
|
if (this.limitToPath && this.limitToPath.endsWith('/')) {
|
|
463
463
|
this.limitToPath.substring(0, this.limitToPath.length - 1);
|
|
464
464
|
}
|
|
@@ -467,7 +467,11 @@ class FileBrowser extends react_1.Component {
|
|
|
467
467
|
try {
|
|
468
468
|
expanded = JSON.parse(expandedStr);
|
|
469
469
|
if (this.limitToPath) {
|
|
470
|
-
expanded = expanded.filter(id => {
|
|
470
|
+
expanded = expanded.filter(id => {
|
|
471
|
+
var _a;
|
|
472
|
+
return id.startsWith(`${this.limitToPath}/`) ||
|
|
473
|
+
id === this.limitToPath || ((_a = this.limitToPath) === null || _a === void 0 ? void 0 : _a.startsWith(`${id}/`));
|
|
474
|
+
});
|
|
471
475
|
}
|
|
472
476
|
}
|
|
473
477
|
catch (e) {
|
|
@@ -480,8 +484,10 @@ class FileBrowser extends react_1.Component {
|
|
|
480
484
|
else {
|
|
481
485
|
viewType = TABLE;
|
|
482
486
|
}
|
|
483
|
-
let selected = this.props.selected ||
|
|
484
|
-
|
|
487
|
+
let selected = this.props.selected ||
|
|
488
|
+
(window._localStorage || window.localStorage).getItem('files.selected') ||
|
|
489
|
+
USER_DATA;
|
|
490
|
+
let currentDir;
|
|
485
491
|
if (props.restrictToFolder) {
|
|
486
492
|
selected = props.restrictToFolder;
|
|
487
493
|
currentDir = props.restrictToFolder;
|
|
@@ -587,14 +593,12 @@ class FileBrowser extends react_1.Component {
|
|
|
587
593
|
el && el.scrollIntoView();
|
|
588
594
|
}
|
|
589
595
|
}
|
|
590
|
-
componentDidMount() {
|
|
596
|
+
async componentDidMount() {
|
|
591
597
|
this.mounted = true;
|
|
592
|
-
this.loadFolders()
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
this.supportSubscribes && this.props.socket.subscribeFiles('*', '*', this.onFileChange);
|
|
597
|
-
});
|
|
598
|
+
this.loadFolders()
|
|
599
|
+
.catch(error => console.error(`Cannot load folders: ${error}`));
|
|
600
|
+
this.supportSubscribes = await this.props.socket.checkFeatureSupported('BINARY_STATE_EVENT');
|
|
601
|
+
this.supportSubscribes && (await this.props.socket.subscribeFiles('*', '*', this.onFileChange));
|
|
598
602
|
}
|
|
599
603
|
componentWillUnmount() {
|
|
600
604
|
this.supportSubscribes && this.props.socket.unsubscribeFiles('*', '*', this.onFileChange);
|
|
@@ -627,7 +631,7 @@ class FileBrowser extends react_1.Component {
|
|
|
627
631
|
let newFoldersNotNull;
|
|
628
632
|
if (!_newFolders) {
|
|
629
633
|
newFoldersNotNull = {};
|
|
630
|
-
Object.keys(this.state.folders).forEach(folder => newFoldersNotNull[folder] = this.state.folders[folder]);
|
|
634
|
+
Object.keys(this.state.folders).forEach(folder => (newFoldersNotNull[folder] = this.state.folders[folder]));
|
|
631
635
|
}
|
|
632
636
|
else {
|
|
633
637
|
newFoldersNotNull = _newFolders;
|
|
@@ -641,7 +645,8 @@ class FileBrowser extends react_1.Component {
|
|
|
641
645
|
}
|
|
642
646
|
readDirSerial(adapter, relPath) {
|
|
643
647
|
return new Promise((resolve, reject) => {
|
|
644
|
-
if (this.browseList) {
|
|
648
|
+
if (this.browseList) {
|
|
649
|
+
// if component still mounted
|
|
645
650
|
this.browseList.push({
|
|
646
651
|
resolve: resolve,
|
|
647
652
|
reject,
|
|
@@ -665,9 +670,11 @@ class FileBrowser extends react_1.Component {
|
|
|
665
670
|
this.setState({ queueLength: this.browseList.length });
|
|
666
671
|
}
|
|
667
672
|
this.browseList[0].processing = true;
|
|
668
|
-
this.props.socket
|
|
673
|
+
this.props.socket
|
|
674
|
+
.readDir(this.browseList[0].adapter, this.browseList[0].relPath)
|
|
669
675
|
.then(files => {
|
|
670
|
-
if (this.browseList) {
|
|
676
|
+
if (this.browseList) {
|
|
677
|
+
// if component still mounted
|
|
671
678
|
const item = this.browseList.shift();
|
|
672
679
|
if (item) {
|
|
673
680
|
const resolve = item.resolve;
|
|
@@ -695,7 +702,8 @@ class FileBrowser extends react_1.Component {
|
|
|
695
702
|
}
|
|
696
703
|
})
|
|
697
704
|
.catch(e => {
|
|
698
|
-
if (this.browseList) {
|
|
705
|
+
if (this.browseList) {
|
|
706
|
+
// if component still mounted
|
|
699
707
|
const item = this.browseList.shift();
|
|
700
708
|
if (item) {
|
|
701
709
|
const reject = item.reject;
|
|
@@ -828,7 +836,10 @@ class FileBrowser extends react_1.Component {
|
|
|
828
836
|
level,
|
|
829
837
|
};
|
|
830
838
|
if (this.state.restrictToFolder) {
|
|
831
|
-
if (item.folder &&
|
|
839
|
+
if (item.folder &&
|
|
840
|
+
(item.id.startsWith(`${this.state.restrictToFolder}/`) ||
|
|
841
|
+
item.id === this.state.restrictToFolder ||
|
|
842
|
+
this.state.restrictToFolder.startsWith(`${item.id}/`))) {
|
|
832
843
|
_folders.push(item);
|
|
833
844
|
}
|
|
834
845
|
else if (item.id.startsWith(`${this.state.restrictToFolder}/`)) {
|
|
@@ -836,7 +847,10 @@ class FileBrowser extends react_1.Component {
|
|
|
836
847
|
}
|
|
837
848
|
}
|
|
838
849
|
else if (this.limitToPath) {
|
|
839
|
-
if (item.folder &&
|
|
850
|
+
if (item.folder &&
|
|
851
|
+
(item.id.startsWith(`${this.limitToPath}/`) ||
|
|
852
|
+
item.id === this.limitToPath ||
|
|
853
|
+
this.limitToPath.startsWith(`${item.id}/`))) {
|
|
840
854
|
_folders.push(item);
|
|
841
855
|
}
|
|
842
856
|
else if (item.id.startsWith(`${this.limitToPath}/`)) {
|
|
@@ -873,7 +887,9 @@ class FileBrowser extends react_1.Component {
|
|
|
873
887
|
if (!item.temp) {
|
|
874
888
|
this.browseFolder(item.id)
|
|
875
889
|
.then(folders => this.setState({ expanded, folders }))
|
|
876
|
-
.catch(err => window.alert(err === NOT_FOUND
|
|
890
|
+
.catch(err => window.alert(err === NOT_FOUND
|
|
891
|
+
? this.props.t('ra_Cannot find "%s"', item.id)
|
|
892
|
+
: this.props.t('ra_Cannot read "%s"', item.id)));
|
|
877
893
|
}
|
|
878
894
|
else {
|
|
879
895
|
this.setState({ expanded });
|
|
@@ -921,7 +937,8 @@ class FileBrowser extends react_1.Component {
|
|
|
921
937
|
if (this.props.onSelect) {
|
|
922
938
|
const ext = Utils_1.default.getFileExtension(id);
|
|
923
939
|
if ((!this.props.filterFiles || (ext && this.props.filterFiles.includes(ext))) &&
|
|
924
|
-
(!this.state.filterByType ||
|
|
940
|
+
(!this.state.filterByType ||
|
|
941
|
+
(ext && FileViewer_1.EXTENSIONS[this.state.filterByType].includes(ext)))) {
|
|
925
942
|
this.props.onSelect(id, false, !!this.state.folders[id]);
|
|
926
943
|
}
|
|
927
944
|
else {
|
|
@@ -944,34 +961,41 @@ class FileBrowser extends react_1.Component {
|
|
|
944
961
|
if (this.state.viewType === TABLE &&
|
|
945
962
|
this.state.filterEmpty &&
|
|
946
963
|
(!this.state.folders[item.id] || !this.state.folders[item.id].length) &&
|
|
947
|
-
item.id !== USER_DATA &&
|
|
964
|
+
item.id !== USER_DATA &&
|
|
965
|
+
!item.temp) {
|
|
948
966
|
return null;
|
|
949
967
|
}
|
|
950
|
-
const
|
|
968
|
+
const IconEl = expanded ? IconOpen_1.default : IconClosed_1.default;
|
|
951
969
|
const padding = this.state.viewType === TABLE ? item.level * this.levelPadding : 0;
|
|
952
970
|
const isUserData = item.name === USER_DATA;
|
|
953
971
|
const isSpecialData = isUserData || item.name === 'vis.0' || item.name === 'vis-2.0';
|
|
954
972
|
return react_1.default.createElement("div", { key: item.id, id: item.id, style: this.state.viewType === TABLE ? { marginLeft: padding, width: `calc(100% - ${padding}px` } : {}, onClick: e => (this.state.viewType === TABLE ? this.select(item.id, e) : this.changeFolder(e, item.id)), onDoubleClick: e => this.state.viewType === TABLE && this.toggleFolder(item, e), title: this.getText(item.title), className: Utils_1.default.clsx('browserItem', this.props.classes[`item${this.state.viewType}`], this.props.classes[`itemFolder${this.state.viewType}`], this.state.selected === item.id && this.props.classes.itemSelected, item.temp && this.props.classes.itemFolderTemp) },
|
|
955
|
-
react_1.default.createElement(
|
|
973
|
+
react_1.default.createElement(IconEl, { className: Utils_1.default.clsx(this.props.classes[`itemFolderIcon${this.state.viewType}`], isSpecialData && this.props.classes.specialFolder), onClick: this.state.viewType === TABLE ? e => this.toggleFolder(item, e) : undefined }),
|
|
956
974
|
react_1.default.createElement("div", { className: Utils_1.default.clsx(this.props.classes[`itemName${this.state.viewType}`], this.props.classes[`itemNameFolder${this.state.viewType}`]) }, isUserData ? this.props.t('ra_User files') : item.name),
|
|
957
975
|
react_1.default.createElement(material_1.Hidden, { smDown: true },
|
|
958
|
-
react_1.default.createElement("div", { className: this.props.classes[`itemSize${this.state.viewType}`] }, this.state.viewType === TABLE && this.state.folders[item.id]
|
|
976
|
+
react_1.default.createElement("div", { className: this.props.classes[`itemSize${this.state.viewType}`] }, this.state.viewType === TABLE && this.state.folders[item.id]
|
|
977
|
+
? this.state.folders[item.id].length
|
|
978
|
+
: '')),
|
|
959
979
|
react_1.default.createElement(material_1.Hidden, { smDown: true }, this.state.viewType === TABLE && this.props.expertMode ? this.formatAcl(item.acl) : null),
|
|
960
|
-
react_1.default.createElement(material_1.Hidden, { smDown: true }, this.state.viewType === TABLE && this.props.expertMode ?
|
|
961
|
-
|
|
962
|
-
this.state.viewType === TABLE && this.props.
|
|
963
|
-
react_1.default.createElement(
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
980
|
+
react_1.default.createElement(material_1.Hidden, { smDown: true }, this.state.viewType === TABLE && this.props.expertMode ?
|
|
981
|
+
react_1.default.createElement("div", { className: this.props.classes[`itemDeleteButton${this.state.viewType}`] }) : null),
|
|
982
|
+
this.state.viewType === TABLE && this.props.allowDownload ?
|
|
983
|
+
react_1.default.createElement("div", { className: this.props.classes[`itemDownloadEmpty${this.state.viewType}`] }) : null,
|
|
984
|
+
this.state.viewType === TABLE &&
|
|
985
|
+
this.props.allowDelete &&
|
|
986
|
+
this.state.folders[item.id] &&
|
|
987
|
+
this.state.folders[item.id].length ? react_1.default.createElement(material_1.IconButton, { "aria-label": "delete", onClick: e => {
|
|
988
|
+
e.stopPropagation();
|
|
989
|
+
if (this.suppressDeleteConfirm > Date.now()) {
|
|
990
|
+
this.deleteItem(item.id);
|
|
991
|
+
}
|
|
992
|
+
else {
|
|
993
|
+
this.setState({ deleteItem: item.id });
|
|
994
|
+
}
|
|
995
|
+
}, className: this.props.classes[`itemDeleteButton${this.state.viewType}`], size: "large" },
|
|
996
|
+
react_1.default.createElement(icons_material_1.Delete, { fontSize: "small" })) :
|
|
997
|
+
this.state.viewType === TABLE && this.props.allowDelete ?
|
|
998
|
+
react_1.default.createElement("div", { className: this.props.classes[`itemDeleteButton${this.state.viewType}`] }) : null);
|
|
975
999
|
}
|
|
976
1000
|
renderBackFolder() {
|
|
977
1001
|
return react_1.default.createElement("div", { key: this.state.currentDir, id: this.state.currentDir, onClick: e => this.changeFolder(e), title: this.props.t('ra_Back to %s', getParentDir(this.state.currentDir)), className: Utils_1.default.clsx('browserItem', this.props.classes[`item${this.state.viewType}`], this.props.classes[`itemFolder${this.state.viewType}`]) },
|
|
@@ -983,7 +1007,7 @@ class FileBrowser extends react_1.Component {
|
|
|
983
1007
|
return react_1.default.createElement("div", { className: this.props.classes[`itemSize${this.state.viewType}`] }, size || size === 0 ? Utils_1.default.formatBytes(size) : '');
|
|
984
1008
|
}
|
|
985
1009
|
formatAcl(acl) {
|
|
986
|
-
|
|
1010
|
+
const access = acl && (acl.permissions || acl.file);
|
|
987
1011
|
let accessStr;
|
|
988
1012
|
if (access) {
|
|
989
1013
|
accessStr = access.toString(16).padStart(3, '0');
|
|
@@ -1040,7 +1064,9 @@ class FileBrowser extends react_1.Component {
|
|
|
1040
1064
|
this.setState({ viewer: this.imagePrefix + item.id, formatEditFile: ext });
|
|
1041
1065
|
}
|
|
1042
1066
|
else if ((!this.props.filterFiles || (item.ext && this.props.filterFiles.includes(item.ext))) &&
|
|
1043
|
-
(!this.state.filterByType ||
|
|
1067
|
+
(!this.state.filterByType ||
|
|
1068
|
+
(item.ext &&
|
|
1069
|
+
FileViewer_1.EXTENSIONS[this.state.filterByType].includes(item.ext)))) {
|
|
1044
1070
|
this.props.onSelect(item.id, true, !!this.state.folders[item.id]);
|
|
1045
1071
|
}
|
|
1046
1072
|
}, onClick: e => this.select(item.id, e), style: this.state.viewType === TABLE ? { marginLeft: padding, width: `calc(100% - ${padding}px)` } : {}, className: Utils_1.default.clsx('browserItem', this.props.classes[`item${this.state.viewType}`], this.props.classes[`itemFile${this.state.viewType}`], this.state.selected === item.id && this.props.classes.itemSelected) },
|
|
@@ -1067,8 +1093,11 @@ class FileBrowser extends react_1.Component {
|
|
|
1067
1093
|
if (!this.props.onSelect) {
|
|
1068
1094
|
this.setState({ viewer: this.imagePrefix + item.id, formatEditFile: ext });
|
|
1069
1095
|
}
|
|
1070
|
-
else if ((!this.props.filterFiles ||
|
|
1071
|
-
(
|
|
1096
|
+
else if ((!this.props.filterFiles ||
|
|
1097
|
+
(item.ext && this.props.filterFiles.includes(item.ext))) &&
|
|
1098
|
+
(!this.state.filterByType ||
|
|
1099
|
+
(item.ext &&
|
|
1100
|
+
FileViewer_1.EXTENSIONS[this.state.filterByType].includes(item.ext)))) {
|
|
1072
1101
|
this.props.onSelect(item.id, true, !!this.state.folders[item.id]);
|
|
1073
1102
|
}
|
|
1074
1103
|
}, className: this.props.classes[`itemDeleteButton${this.state.viewType}`], size: "large" },
|
|
@@ -1083,23 +1112,19 @@ class FileBrowser extends react_1.Component {
|
|
|
1083
1112
|
this.props.allowDelete &&
|
|
1084
1113
|
item.id !== 'vis.0/' &&
|
|
1085
1114
|
item.id !== 'vis-2.0/' &&
|
|
1086
|
-
item.id !== USER_DATA
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
}, className: this.props.classes[`itemDeleteButton${this.state.viewType}`], size: "large" },
|
|
1097
|
-
react_1.default.createElement(icons_material_1.Delete, { fontSize: "small" }))
|
|
1115
|
+
item.id !== USER_DATA ? react_1.default.createElement(material_1.IconButton, { "aria-label": "delete", onClick: e => {
|
|
1116
|
+
e.stopPropagation();
|
|
1117
|
+
if (this.suppressDeleteConfirm > Date.now()) {
|
|
1118
|
+
this.deleteItem(item.id);
|
|
1119
|
+
}
|
|
1120
|
+
else {
|
|
1121
|
+
this.setState({ deleteItem: item.id });
|
|
1122
|
+
}
|
|
1123
|
+
}, className: this.props.classes[`itemDeleteButton${this.state.viewType}`], size: "large" },
|
|
1124
|
+
react_1.default.createElement(icons_material_1.Delete, { fontSize: "small" }))
|
|
1098
1125
|
:
|
|
1099
1126
|
(this.state.viewType === TABLE && this.props.allowDelete ?
|
|
1100
|
-
react_1.default.createElement("div", { className: this.props.classes[`itemDeleteButton${this.state.viewType}`] })
|
|
1101
|
-
:
|
|
1102
|
-
null));
|
|
1127
|
+
react_1.default.createElement("div", { className: this.props.classes[`itemDeleteButton${this.state.viewType}`] }) : null));
|
|
1103
1128
|
}
|
|
1104
1129
|
renderItems(folderId) {
|
|
1105
1130
|
if (this.state.folders && this.state.folders[folderId]) {
|
|
@@ -1114,7 +1139,9 @@ class FileBrowser extends react_1.Component {
|
|
|
1114
1139
|
res.push(this.renderFolder(item));
|
|
1115
1140
|
}
|
|
1116
1141
|
else if ((!this.props.filterFiles || (item.ext && this.props.filterFiles.includes(item.ext))) &&
|
|
1117
|
-
(!this.state.filterByType ||
|
|
1142
|
+
(!this.state.filterByType ||
|
|
1143
|
+
(item.ext &&
|
|
1144
|
+
FileViewer_1.EXTENSIONS[this.state.filterByType].includes(item.ext)))) {
|
|
1118
1145
|
res.push(this.renderFile(item));
|
|
1119
1146
|
}
|
|
1120
1147
|
});
|
|
@@ -1134,7 +1161,7 @@ class FileBrowser extends react_1.Component {
|
|
|
1134
1161
|
if (this.state.folders[item.id] && expanded) {
|
|
1135
1162
|
const items = this.renderItems(item.id);
|
|
1136
1163
|
if (Array.isArray(items)) {
|
|
1137
|
-
items.forEach(
|
|
1164
|
+
items.forEach(_item => totalResult.push(_item));
|
|
1138
1165
|
}
|
|
1139
1166
|
else {
|
|
1140
1167
|
totalResult.push(items);
|
|
@@ -1142,7 +1169,9 @@ class FileBrowser extends react_1.Component {
|
|
|
1142
1169
|
}
|
|
1143
1170
|
}
|
|
1144
1171
|
else if ((!this.props.filterFiles || (item.ext && this.props.filterFiles.includes(item.ext))) &&
|
|
1145
|
-
(!this.state.filterByType ||
|
|
1172
|
+
(!this.state.filterByType ||
|
|
1173
|
+
(item.ext &&
|
|
1174
|
+
FileViewer_1.EXTENSIONS[this.state.filterByType].includes(item.ext)))) {
|
|
1146
1175
|
totalResult.push(this.renderFile(item));
|
|
1147
1176
|
}
|
|
1148
1177
|
});
|
|
@@ -1151,16 +1180,23 @@ class FileBrowser extends react_1.Component {
|
|
|
1151
1180
|
return react_1.default.createElement("div", { style: { position: 'relative' } },
|
|
1152
1181
|
react_1.default.createElement(material_1.CircularProgress, { key: folderId, color: "secondary", size: 24 }),
|
|
1153
1182
|
react_1.default.createElement("div", { style: {
|
|
1154
|
-
position: 'absolute',
|
|
1183
|
+
position: 'absolute',
|
|
1184
|
+
zIndex: 2,
|
|
1185
|
+
top: 4,
|
|
1186
|
+
width: 24,
|
|
1187
|
+
textAlign: 'center',
|
|
1155
1188
|
} }, this.state.queueLength));
|
|
1156
1189
|
}
|
|
1157
1190
|
renderToolbar() {
|
|
1158
|
-
const IconType = this.props.showTypeSelector
|
|
1159
|
-
|
|
1160
|
-
|
|
1191
|
+
const IconType = this.props.showTypeSelector
|
|
1192
|
+
? FILE_TYPE_ICONS[this.state.filterByType || 'all'] ||
|
|
1193
|
+
FILE_TYPE_ICONS.all
|
|
1194
|
+
: null;
|
|
1161
1195
|
const isInFolder = this.findFirstFolder(this.state.selected);
|
|
1162
1196
|
return react_1.default.createElement(material_1.Toolbar, { key: "toolbar", variant: "dense" },
|
|
1163
|
-
this.props.allowNonRestricted && this.props.restrictToFolder ? react_1.default.createElement(material_1.IconButton, { edge: "start", title: this.state.restrictToFolder
|
|
1197
|
+
this.props.allowNonRestricted && this.props.restrictToFolder ? react_1.default.createElement(material_1.IconButton, { edge: "start", title: this.state.restrictToFolder
|
|
1198
|
+
? this.props.t('ra_Show all folders')
|
|
1199
|
+
: this.props.t('ra_Restrict to folder'), className: Utils_1.default.clsx(this.props.classes.menuButton, this.state.restrictToFolder && this.props.classes.menuButtonRestrictActive), "aria-label": "restricted to folder", onClick: () => this.setState({
|
|
1164
1200
|
restrictToFolder: (this.state.restrictToFolder ? '' : this.props.restrictToFolder) || '',
|
|
1165
1201
|
loadAllFolders: true,
|
|
1166
1202
|
}), size: "small" },
|
|
@@ -1257,10 +1293,12 @@ class FileBrowser extends react_1.Component {
|
|
|
1257
1293
|
window.alert(this.props.t('ra_Invalid parent folder!'));
|
|
1258
1294
|
return null;
|
|
1259
1295
|
}
|
|
1260
|
-
return react_1.default.createElement(TextInput_1.default, { key: "inputDialog", applyText: this.props.t('ra_Create'), cancelText: this.props.t('ra_Cancel'), titleText: this.props.t('ra_Create new folder in %s', this.state.selected), promptText: this.props.t('ra_If no file will be created in the folder, it will disappear after the browser closed'), labelText: this.props.t('ra_Folder name'), verify: (text) => (this.state.folders[parentFolder].find(item => item.name === text)
|
|
1296
|
+
return react_1.default.createElement(TextInput_1.default, { key: "inputDialog", applyText: this.props.t('ra_Create'), cancelText: this.props.t('ra_Cancel'), titleText: this.props.t('ra_Create new folder in %s', this.state.selected), promptText: this.props.t('ra_If no file will be created in the folder, it will disappear after the browser closed'), labelText: this.props.t('ra_Folder name'), verify: (text) => (this.state.folders[parentFolder].find(item => item.name === text)
|
|
1297
|
+
? ''
|
|
1298
|
+
: this.props.t('ra_Duplicate name')), onClose: (name) => {
|
|
1261
1299
|
if (name) {
|
|
1262
1300
|
const folders = {};
|
|
1263
|
-
Object.keys(this.state.folders).forEach(folder => folders[folder] = this.state.folders[folder]);
|
|
1301
|
+
Object.keys(this.state.folders).forEach(folder => (folders[folder] = this.state.folders[folder]));
|
|
1264
1302
|
const parent = this.findItem(parentFolder);
|
|
1265
1303
|
const id = `${parentFolder}/${name}`;
|
|
1266
1304
|
folders[parentFolder].push({
|
|
@@ -1283,7 +1321,7 @@ class FileBrowser extends react_1.Component {
|
|
|
1283
1321
|
else {
|
|
1284
1322
|
this.setState({ addFolder: false });
|
|
1285
1323
|
}
|
|
1286
|
-
}, replace: (text) => text.replace(/[^-_\w
|
|
1324
|
+
}, replace: (text) => text.replace(/[^-_\w]/, '_') });
|
|
1287
1325
|
}
|
|
1288
1326
|
return null;
|
|
1289
1327
|
}
|
|
@@ -1297,11 +1335,15 @@ class FileBrowser extends react_1.Component {
|
|
|
1297
1335
|
}
|
|
1298
1336
|
}, 100);
|
|
1299
1337
|
}
|
|
1300
|
-
uploadFile(fileName, data) {
|
|
1338
|
+
async uploadFile(fileName, data) {
|
|
1301
1339
|
const parts = fileName.split('/');
|
|
1302
1340
|
const adapter = parts.shift();
|
|
1303
|
-
|
|
1304
|
-
|
|
1341
|
+
try {
|
|
1342
|
+
return await this.props.socket.writeFile64(adapter || '', parts.join('/'), data);
|
|
1343
|
+
}
|
|
1344
|
+
catch (e) {
|
|
1345
|
+
return window.alert(`Cannot write file: ${e}`);
|
|
1346
|
+
}
|
|
1305
1347
|
}
|
|
1306
1348
|
findFirstFolder(id) {
|
|
1307
1349
|
let parentFolder = id;
|
|
@@ -1313,10 +1355,14 @@ class FileBrowser extends react_1.Component {
|
|
|
1313
1355
|
parentFolder = '';
|
|
1314
1356
|
while (parts.length) {
|
|
1315
1357
|
const _item = this.findItem(parts.join('/'));
|
|
1316
|
-
if (_item
|
|
1358
|
+
if (_item === null || _item === void 0 ? void 0 : _item.folder) {
|
|
1317
1359
|
parentFolder = parts.join('/');
|
|
1318
1360
|
break;
|
|
1319
1361
|
}
|
|
1362
|
+
parts.pop();
|
|
1363
|
+
}
|
|
1364
|
+
if (!parts.length) {
|
|
1365
|
+
return null;
|
|
1320
1366
|
}
|
|
1321
1367
|
}
|
|
1322
1368
|
return parentFolder;
|
|
@@ -1361,7 +1407,8 @@ class FileBrowser extends react_1.Component {
|
|
|
1361
1407
|
if (!expanded.includes(parentFolder)) {
|
|
1362
1408
|
expanded.push(parentFolder);
|
|
1363
1409
|
expanded.sort();
|
|
1364
|
-
(window._localStorage ||
|
|
1410
|
+
(window._localStorage ||
|
|
1411
|
+
window.localStorage).setItem('files.expanded', JSON.stringify(expanded));
|
|
1365
1412
|
}
|
|
1366
1413
|
this.setState({ folders, expanded }, () => this.select(id));
|
|
1367
1414
|
}), 500);
|
|
@@ -1373,13 +1420,14 @@ class FileBrowser extends react_1.Component {
|
|
|
1373
1420
|
};
|
|
1374
1421
|
reader.readAsArrayBuffer(file);
|
|
1375
1422
|
});
|
|
1376
|
-
} }, ({ getRootProps, getInputProps }) =>
|
|
1423
|
+
} }, ({ getRootProps, getInputProps }) => react_1.default.createElement("div", Object.assign({ className: Utils_1.default.clsx(this.props.classes.uploadDiv, this.state.uploadFile === 'dragging' && this.props.classes.uploadDivDragging) }, getRootProps()),
|
|
1377
1424
|
react_1.default.createElement("input", Object.assign({}, getInputProps())),
|
|
1378
1425
|
react_1.default.createElement("div", { className: this.props.classes.uploadCenterDiv },
|
|
1379
1426
|
react_1.default.createElement("div", { className: this.props.classes.uploadCenterTextAndIcon },
|
|
1380
1427
|
react_1.default.createElement(icons_material_1.Publish, { className: this.props.classes.uploadCenterIcon }),
|
|
1381
|
-
react_1.default.createElement("div", { className: this.props.classes.uploadCenterText }, this.state.uploadFile === 'dragging'
|
|
1382
|
-
this.props.t('
|
|
1428
|
+
react_1.default.createElement("div", { className: this.props.classes.uploadCenterText }, this.state.uploadFile === 'dragging'
|
|
1429
|
+
? this.props.t('ra_Drop file here')
|
|
1430
|
+
: this.props.t('ra_Place your files here or click here to open the browse dialog')))))),
|
|
1383
1431
|
];
|
|
1384
1432
|
}
|
|
1385
1433
|
return null;
|
|
@@ -1387,14 +1435,15 @@ class FileBrowser extends react_1.Component {
|
|
|
1387
1435
|
deleteRecursive(id) {
|
|
1388
1436
|
const item = this.findItem(id);
|
|
1389
1437
|
if (item === null || item === void 0 ? void 0 : item.folder) {
|
|
1390
|
-
return (this.state.folders[id]
|
|
1438
|
+
return (this.state.folders[id]
|
|
1439
|
+
? Promise.all(this.state.folders[id].map(_item => this.deleteRecursive(_item.id)))
|
|
1440
|
+
: Promise.resolve())
|
|
1391
1441
|
.then(() => {
|
|
1392
1442
|
// If it is a folder of second level
|
|
1393
1443
|
if (item.level >= 1) {
|
|
1394
1444
|
const parts = id.split('/');
|
|
1395
1445
|
const adapter = parts.shift();
|
|
1396
|
-
this.props.socket.deleteFolder(adapter || '', parts.join('/'))
|
|
1397
|
-
.then(() => {
|
|
1446
|
+
this.props.socket.deleteFolder(adapter || '', parts.join('/')).then(() => {
|
|
1398
1447
|
// remove this folder
|
|
1399
1448
|
const folders = JSON.parse(JSON.stringify(this.state.folders));
|
|
1400
1449
|
delete folders[item.id];
|
|
@@ -1415,7 +1464,8 @@ class FileBrowser extends react_1.Component {
|
|
|
1415
1464
|
const parts = id.split('/');
|
|
1416
1465
|
const adapter = parts.shift();
|
|
1417
1466
|
if (parts.length) {
|
|
1418
|
-
return this.props.socket
|
|
1467
|
+
return this.props.socket
|
|
1468
|
+
.deleteFile(adapter || '', parts.join('/'))
|
|
1419
1469
|
.catch(e => window.alert(`Cannot delete file: ${e}`));
|
|
1420
1470
|
}
|
|
1421
1471
|
return Promise.resolve();
|
|
@@ -1522,7 +1572,11 @@ class FileBrowser extends react_1.Component {
|
|
|
1522
1572
|
if (!this.state.folders[folder]) {
|
|
1523
1573
|
this.browseFolder(folder)
|
|
1524
1574
|
.then(folders => this.setState({ folders }, () => resolve(true)))
|
|
1525
|
-
.catch(err => this.setState({
|
|
1575
|
+
.catch(err => this.setState({
|
|
1576
|
+
errorText: err === NOT_FOUND
|
|
1577
|
+
? this.props.t('ra_Cannot find "%s"', folder)
|
|
1578
|
+
: this.props.t('ra_Cannot read "%s"', folder),
|
|
1579
|
+
}));
|
|
1526
1580
|
}
|
|
1527
1581
|
else {
|
|
1528
1582
|
resolve(true);
|
|
@@ -1536,7 +1590,9 @@ class FileBrowser extends react_1.Component {
|
|
|
1536
1590
|
}, 100);
|
|
1537
1591
|
}
|
|
1538
1592
|
renderBreadcrumb() {
|
|
1539
|
-
const parts = this.state.currentDir.startsWith('/')
|
|
1593
|
+
const parts = this.state.currentDir.startsWith('/')
|
|
1594
|
+
? this.state.currentDir.split('/')
|
|
1595
|
+
: `/${this.state.currentDir}`.split('/');
|
|
1540
1596
|
const p = [];
|
|
1541
1597
|
return react_1.default.createElement(material_1.Breadcrumbs, { style: { paddingLeft: 8 } }, parts.map((part, i) => {
|
|
1542
1598
|
part && p.push(part);
|
|
@@ -1550,10 +1606,10 @@ class FileBrowser extends react_1.Component {
|
|
|
1550
1606
|
renderPath() {
|
|
1551
1607
|
return react_1.default.createElement("div", { key: "path", className: this.props.classes.pathDiv }, this.state.pathFocus ?
|
|
1552
1608
|
react_1.default.createElement(material_1.Input, { value: this.state.path, onKeyDown: e => {
|
|
1553
|
-
if (e.
|
|
1609
|
+
if (e.key === 'Enter') {
|
|
1554
1610
|
this.changeToPath();
|
|
1555
1611
|
}
|
|
1556
|
-
else if (e.
|
|
1612
|
+
else if (e.key === 'Escape') {
|
|
1557
1613
|
this.setState({ pathFocus: false });
|
|
1558
1614
|
}
|
|
1559
1615
|
}, endAdornment: react_1.default.createElement(material_1.IconButton, { size: "small", onClick: () => this.changeToPath() },
|
|
@@ -1570,7 +1626,8 @@ class FileBrowser extends react_1.Component {
|
|
|
1570
1626
|
setTimeout(() => {
|
|
1571
1627
|
this.setState({ loadAllFolders: false, folders: {} }, () => {
|
|
1572
1628
|
this.foldersLoading = false;
|
|
1573
|
-
this.loadFolders()
|
|
1629
|
+
this.loadFolders()
|
|
1630
|
+
.catch(error => console.error(`Cannot load folders: ${error}`));
|
|
1574
1631
|
});
|
|
1575
1632
|
}, 300);
|
|
1576
1633
|
}
|
|
@@ -1587,13 +1644,17 @@ class FileBrowser extends react_1.Component {
|
|
|
1587
1644
|
}
|
|
1588
1645
|
}
|
|
1589
1646
|
} },
|
|
1590
|
-
this.state.viewType === TABLE
|
|
1591
|
-
|
|
1647
|
+
this.state.viewType === TABLE
|
|
1648
|
+
? this.renderItems('/')
|
|
1649
|
+
: this.renderItems(this.state.currentDir || '/'),
|
|
1650
|
+
this.state.viewType !== TABLE ? (react_1.default.createElement("div", { className: this.props.classes.filesDivHint }, this.props.t('ra_select_folder_hint'))) : null),
|
|
1592
1651
|
this.props.allowUpload ? this.renderInputDialog() : null,
|
|
1593
1652
|
this.props.allowUpload ? this.renderUpload() : null,
|
|
1594
1653
|
this.props.allowDelete ? this.renderDeleteDialog() : null,
|
|
1595
1654
|
this.props.allowView ? this.renderViewDialog() : null,
|
|
1596
|
-
this.state.modalEditOfAccess && this.props.modalEditOfAccessControl
|
|
1655
|
+
this.state.modalEditOfAccess && this.props.modalEditOfAccessControl
|
|
1656
|
+
? this.props.modalEditOfAccessControl(this)
|
|
1657
|
+
: null,
|
|
1597
1658
|
this.renderError());
|
|
1598
1659
|
}
|
|
1599
1660
|
}
|
package/README.md
CHANGED