@api-client/ui 0.0.10 → 0.0.12
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/.eslintrc +16 -1
- package/demo/elements/index.html +3 -0
- package/demo/elements/store/file-picker.html +15 -0
- package/demo/elements/store/file-picker.ts +134 -0
- package/demo/elements/store/index.html +19 -0
- package/demo/index.html +3 -0
- package/demo/layout/index.html +91 -0
- package/demo/layout/index.ts +182 -0
- package/demo/store/StorePlugin.js +1 -0
- package/dist/bindings/base/StoreBindings.d.ts +5 -0
- package/dist/bindings/base/StoreBindings.d.ts.map +1 -1
- package/dist/bindings/base/StoreBindings.js +15 -1
- package/dist/bindings/base/StoreBindings.js.map +1 -1
- package/dist/define/store/file-picker.d.ts +9 -0
- package/dist/define/store/file-picker.d.ts.map +1 -0
- package/dist/define/store/file-picker.js +10 -0
- package/dist/define/store/file-picker.js.map +1 -0
- package/dist/define/{files → store}/share-file.d.ts +1 -1
- package/dist/define/store/share-file.d.ts.map +1 -0
- package/dist/define/{files → store}/share-file.js +2 -2
- package/dist/define/store/share-file.js.map +1 -0
- package/dist/elements/layout/SplitItem.d.ts +1 -9
- package/dist/elements/layout/SplitItem.d.ts.map +1 -1
- package/dist/elements/layout/SplitItem.js +27 -20
- package/dist/elements/layout/SplitItem.js.map +1 -1
- package/dist/elements/layout/SplitLayout.d.ts +16 -14
- package/dist/elements/layout/SplitLayout.d.ts.map +1 -1
- package/dist/elements/layout/SplitLayout.js +47 -42
- package/dist/elements/layout/SplitLayout.js.map +1 -1
- package/dist/elements/layout/SplitPanel.d.ts +7 -2
- package/dist/elements/layout/SplitPanel.d.ts.map +1 -1
- package/dist/elements/layout/SplitPanel.js +130 -52
- package/dist/elements/layout/SplitPanel.js.map +1 -1
- package/dist/elements/layout/SplitView.d.ts.map +1 -1
- package/dist/elements/layout/SplitView.js +18 -14
- package/dist/elements/layout/SplitView.js.map +1 -1
- package/dist/elements/layout/type.d.ts +3 -3
- package/dist/elements/layout/type.d.ts.map +1 -1
- package/dist/elements/layout/type.js.map +1 -1
- package/dist/elements/store/FilePicker.element.d.ts +87 -0
- package/dist/elements/store/FilePicker.element.d.ts.map +1 -0
- package/dist/elements/store/FilePicker.element.js +263 -0
- package/dist/elements/store/FilePicker.element.js.map +1 -0
- package/dist/elements/store/FilePicker.styles.d.ts +3 -0
- package/dist/elements/store/FilePicker.styles.d.ts.map +1 -0
- package/dist/elements/store/FilePicker.styles.js +72 -0
- package/dist/elements/store/FilePicker.styles.js.map +1 -0
- package/dist/elements/store/FilesLib.d.ts +10 -0
- package/dist/elements/store/FilesLib.d.ts.map +1 -0
- package/dist/elements/store/FilesLib.js +38 -0
- package/dist/elements/store/FilesLib.js.map +1 -0
- package/dist/elements/{files/ShareFile.d.ts → store/ShareFile.element.d.ts} +1 -1
- package/dist/elements/store/ShareFile.element.d.ts.map +1 -0
- package/dist/elements/{files/ShareFile.js → store/ShareFile.element.js} +1 -1
- package/dist/elements/store/ShareFile.element.js.map +1 -0
- package/dist/elements/store/ShareFile.styles.d.ts.map +1 -0
- package/dist/elements/{files → store}/ShareFile.styles.js.map +1 -1
- package/dist/events/EventTypes.d.ts +1 -0
- package/dist/events/EventTypes.d.ts.map +1 -1
- package/dist/events/EventTypes.js +1 -0
- package/dist/events/EventTypes.js.map +1 -1
- package/dist/events/Events.d.ts +1 -0
- package/dist/events/Events.d.ts.map +1 -1
- package/dist/events/StoreEvents.d.ts +8 -1
- package/dist/events/StoreEvents.d.ts.map +1 -1
- package/dist/events/StoreEvents.js +19 -0
- package/dist/events/StoreEvents.js.map +1 -1
- package/dist/pages/ApplicationScreen.d.ts +1 -1
- package/dist/pages/ApplicationScreen.d.ts.map +1 -1
- package/dist/pages/ApplicationScreen.js +4 -2
- package/dist/pages/ApplicationScreen.js.map +1 -1
- package/dist/pages/api-client/ApiClient.screen.d.ts +0 -6
- package/dist/pages/api-client/ApiClient.screen.d.ts.map +1 -1
- package/dist/pages/api-client/ApiClient.screen.js +16 -29
- package/dist/pages/api-client/ApiClient.screen.js.map +1 -1
- package/dist/pages/api-client/Authenticate.screen.d.ts +1 -1
- package/dist/pages/api-client/Authenticate.screen.d.ts.map +1 -1
- package/dist/pages/api-client/Authenticate.screen.js +2 -2
- package/dist/pages/api-client/Authenticate.screen.js.map +1 -1
- package/dist/pages/api-client/pages/Files.page.d.ts +6 -35
- package/dist/pages/api-client/pages/Files.page.d.ts.map +1 -1
- package/dist/pages/api-client/pages/Files.page.js +32 -141
- package/dist/pages/api-client/pages/Files.page.js.map +1 -1
- package/dist/pages/api-client/pages/Shared.page.d.ts +1 -5
- package/dist/pages/api-client/pages/Shared.page.d.ts.map +1 -1
- package/dist/pages/api-client/pages/Shared.page.js +1 -40
- package/dist/pages/api-client/pages/Shared.page.js.map +1 -1
- package/dist/pages/demo/DemoPage.d.ts +7 -0
- package/dist/pages/demo/DemoPage.d.ts.map +1 -1
- package/dist/pages/demo/DemoPage.js +14 -0
- package/dist/pages/demo/DemoPage.js.map +1 -1
- package/dist/pages/http-project/HttpClientCommands.d.ts.map +1 -1
- package/dist/pages/http-project/HttpClientCommands.js +28 -12
- package/dist/pages/http-project/HttpClientCommands.js.map +1 -1
- package/dist/store/FileSystem.d.ts +90 -0
- package/dist/store/FileSystem.d.ts.map +1 -0
- package/dist/store/FileSystem.js +260 -0
- package/dist/store/FileSystem.js.map +1 -0
- package/dist/styles/global-styles.d.ts.map +1 -1
- package/dist/styles/global-styles.js +7 -0
- package/dist/styles/global-styles.js.map +1 -1
- package/dist/ui/icons/Icons.d.ts +2 -1
- package/dist/ui/icons/Icons.d.ts.map +1 -1
- package/dist/ui/icons/Icons.js +1 -0
- package/dist/ui/icons/Icons.js.map +1 -1
- package/dist/ui/list/UiDropdownList.d.ts +9 -1
- package/dist/ui/list/UiDropdownList.d.ts.map +1 -1
- package/dist/ui/list/UiDropdownList.js +39 -17
- package/dist/ui/list/UiDropdownList.js.map +1 -1
- package/dist/ui/list/UiList.d.ts +6 -1
- package/dist/ui/list/UiList.d.ts.map +1 -1
- package/dist/ui/list/UiList.js +24 -9
- package/dist/ui/list/UiList.js.map +1 -1
- package/dist/ui/table/DataTable.d.ts +4 -0
- package/dist/ui/table/DataTable.d.ts.map +1 -1
- package/dist/ui/table/DataTable.js +23 -1
- package/dist/ui/table/DataTable.js.map +1 -1
- package/package.json +2 -1
- package/src/bindings/base/StoreBindings.ts +16 -1
- package/src/define/store/file-picker.ts +12 -0
- package/src/define/{files → store}/share-file.ts +2 -2
- package/src/elements/layout/SplitItem.ts +29 -21
- package/src/elements/layout/SplitLayout.ts +53 -43
- package/src/elements/layout/SplitPanel.ts +140 -57
- package/src/elements/layout/SplitView.ts +18 -15
- package/src/elements/layout/type.ts +3 -4
- package/src/elements/store/FilePicker.element.ts +297 -0
- package/src/elements/store/FilePicker.styles.ts +72 -0
- package/src/elements/store/FilesLib.ts +32 -0
- package/src/events/EventTypes.ts +1 -0
- package/src/events/StoreEvents.ts +21 -1
- package/src/pages/ApplicationScreen.ts +5 -3
- package/src/pages/api-client/ApiClient.screen.ts +16 -31
- package/src/pages/api-client/Authenticate.screen.ts +2 -2
- package/src/pages/api-client/pages/Files.page.ts +37 -164
- package/src/pages/api-client/pages/Shared.page.ts +2 -40
- package/src/pages/demo/DemoPage.ts +17 -0
- package/src/pages/http-project/HttpClientCommands.ts +28 -12
- package/src/store/FileSystem.ts +325 -0
- package/src/styles/global-styles.ts +7 -0
- package/src/ui/icons/Icons.ts +2 -1
- package/src/ui/list/UiDropdownList.ts +44 -17
- package/src/ui/list/UiList.ts +26 -10
- package/src/ui/table/DataTable.ts +29 -3
- package/test/elements/layout/SplitItem.test.ts +76 -75
- package/test/elements/layout/SplitLayoutManager.test.ts +70 -69
- package/test/elements/layout/SplitPanel.test.ts +10 -7
- package/test/elements/store/FilePicker.test.ts +241 -0
- package/test/env.js +3 -0
- package/test/helpers/StoreHelper.ts +390 -0
- package/tsconfig.eslint.json +10 -0
- package/web-test-runner.config.mjs +51 -2
- package/dist/define/files/share-file.d.ts.map +0 -1
- package/dist/define/files/share-file.js.map +0 -1
- package/dist/define/layout/layout-panel.d.ts +0 -7
- package/dist/define/layout/layout-panel.d.ts.map +0 -1
- package/dist/define/layout/layout-panel.js +0 -3
- package/dist/define/layout/layout-panel.js.map +0 -1
- package/dist/elements/files/ShareFile.d.ts.map +0 -1
- package/dist/elements/files/ShareFile.js.map +0 -1
- package/dist/elements/files/ShareFile.styles.d.ts.map +0 -1
- package/dist/elements/layout/LayoutManager.d.ts +0 -327
- package/dist/elements/layout/LayoutManager.d.ts.map +0 -1
- package/dist/elements/layout/LayoutManager.js +0 -747
- package/dist/elements/layout/LayoutManager.js.map +0 -1
- package/dist/elements/layout/LayoutPanelElement.d.ts +0 -62
- package/dist/elements/layout/LayoutPanelElement.d.ts.map +0 -1
- package/dist/elements/layout/LayoutPanelElement.js +0 -628
- package/dist/elements/layout/LayoutPanelElement.js.map +0 -1
- package/src/define/layout/layout-panel.ts +0 -9
- package/src/elements/layout/LayoutManager.ts +0 -930
- package/src/elements/layout/LayoutPanelElement.ts +0 -651
- /package/dist/elements/{files → store}/ShareFile.styles.d.ts +0 -0
- /package/dist/elements/{files → store}/ShareFile.styles.js +0 -0
- /package/src/elements/{files/ShareFile.ts → store/ShareFile.element.ts} +0 -0
- /package/src/elements/{files → store}/ShareFile.styles.ts +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-param-reassign */
|
|
1
2
|
/* eslint-disable import/no-cycle */
|
|
2
3
|
import { html, TemplateResult } from "lit";
|
|
3
4
|
import { uuidV4 } from "@api-client/core/build/browser.js";
|
|
@@ -108,7 +109,7 @@ export class SplitPanel {
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
getParent(): SplitPanel | undefined {
|
|
111
|
-
return this.manager.
|
|
112
|
+
return this.manager.getParents(this.key)[0];
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
/**
|
|
@@ -226,6 +227,14 @@ export class SplitPanel {
|
|
|
226
227
|
return instance;
|
|
227
228
|
}
|
|
228
229
|
|
|
230
|
+
const panel = this.splitByRegion(region);
|
|
231
|
+
// we don't call request update here because
|
|
232
|
+
// the app has to redo the view rendering first as
|
|
233
|
+
// the panel purpose has changed.
|
|
234
|
+
return panel.addItem(item, { index });
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
protected splitByRegion(region: SplitRegion): SplitPanel {
|
|
229
238
|
let panel: SplitPanel;
|
|
230
239
|
if (region === 'east') {
|
|
231
240
|
[, panel] = this.split({
|
|
@@ -252,10 +261,7 @@ export class SplitPanel {
|
|
|
252
261
|
noSideEffects: true,
|
|
253
262
|
});
|
|
254
263
|
}
|
|
255
|
-
|
|
256
|
-
// the app has to redo the view rendering first as
|
|
257
|
-
// the panel purpose has changed.
|
|
258
|
-
return panel.addItem(item, { index });
|
|
264
|
+
return panel;
|
|
259
265
|
}
|
|
260
266
|
|
|
261
267
|
/**
|
|
@@ -273,11 +279,8 @@ export class SplitPanel {
|
|
|
273
279
|
this.items = [];
|
|
274
280
|
this.selected = undefined;
|
|
275
281
|
|
|
276
|
-
const p1 = this.addPanel()
|
|
277
|
-
const p2 = this.addPanel()
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
282
|
+
const p1 = this.addPanel();
|
|
283
|
+
const p2 = this.addPanel();
|
|
281
284
|
|
|
282
285
|
// const p1 = new SplitPanel(this.manager);
|
|
283
286
|
// const p2 = new SplitPanel(this.manager);
|
|
@@ -368,24 +371,19 @@ export class SplitPanel {
|
|
|
368
371
|
}
|
|
369
372
|
}
|
|
370
373
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
* @param key The `key` of the item.
|
|
374
|
-
* @returns The removed item, if any.
|
|
375
|
-
*/
|
|
376
|
-
removeItem(key: string, opts: SplitPanelRemoveItemOptions = {}): SplitItem | undefined {
|
|
377
|
-
const removed = this.manager.findItem(key);
|
|
378
|
-
if (!removed) {
|
|
379
|
-
return undefined;
|
|
380
|
-
}
|
|
381
|
-
const index = this.items.findIndex(i => i.key === key);
|
|
374
|
+
removeChildItem(item: SplitItem, opts: SplitPanelRemoveItemOptions = {}): SplitItem | undefined {
|
|
375
|
+
const index = this.items.findIndex(i => i.key === item.key);
|
|
382
376
|
if (index < 0) {
|
|
383
377
|
return undefined;
|
|
384
378
|
}
|
|
385
379
|
const itemInfo = this.items[index];
|
|
386
380
|
this.items.splice(index, 1);
|
|
387
|
-
this.
|
|
388
|
-
this.
|
|
381
|
+
this.decreaseIndex(item.index || 0);
|
|
382
|
+
const parents = this.manager.getParents(item.key);
|
|
383
|
+
if (!parents.length) {
|
|
384
|
+
// remove the definition since no other panel have this item.
|
|
385
|
+
this.manager.definitions.delete(itemInfo.key);
|
|
386
|
+
}
|
|
389
387
|
|
|
390
388
|
if (this.items.length === 0) {
|
|
391
389
|
// remove panel (self)
|
|
@@ -393,29 +391,82 @@ export class SplitPanel {
|
|
|
393
391
|
if (parent) {
|
|
394
392
|
parent.removePanel(this.key);
|
|
395
393
|
// Note, ignore `opts.noSideEffects` for tab close. It won't get dispatched elsewhere.
|
|
396
|
-
this.manager.notifyTabClose(key);
|
|
394
|
+
this.manager.notifyTabClose(item.key, this.key);
|
|
397
395
|
// no point doing the stuff below as the whole panel is removed.
|
|
398
|
-
return
|
|
396
|
+
return item;
|
|
399
397
|
}
|
|
400
398
|
}
|
|
401
|
-
|
|
399
|
+
|
|
400
|
+
if (this.selected === item.key) {
|
|
402
401
|
let nextKey: string | undefined;
|
|
403
402
|
if (this.items[index]) {
|
|
404
403
|
nextKey = this.items[index].key;
|
|
405
404
|
} else if (this.items[index - 1]) {
|
|
406
405
|
nextKey = this.items[index - 1].key;
|
|
407
406
|
} else if (this.items.length) {
|
|
408
|
-
const [
|
|
409
|
-
nextKey =
|
|
407
|
+
const [other] = this.items;
|
|
408
|
+
nextKey = other.key;
|
|
410
409
|
}
|
|
411
410
|
this.selected = nextKey;
|
|
412
411
|
}
|
|
412
|
+
|
|
413
413
|
if (!opts.noSideEffects) {
|
|
414
|
-
this.manager.notifyTabClose(key);
|
|
414
|
+
this.manager.notifyTabClose(item.key, this.key);
|
|
415
415
|
this.manager.notifyChange();
|
|
416
416
|
this.manager.updateView(this.key);
|
|
417
417
|
}
|
|
418
|
-
return
|
|
418
|
+
return item;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Removes an item from the layout
|
|
423
|
+
* @param key The `key` of the item.
|
|
424
|
+
* @returns The removed item, if any.
|
|
425
|
+
*/
|
|
426
|
+
removeItem(key: string, opts?: SplitPanelRemoveItemOptions): SplitItem | undefined {
|
|
427
|
+
const removed = this.manager.findItem(key);
|
|
428
|
+
if (!removed) {
|
|
429
|
+
return undefined;
|
|
430
|
+
}
|
|
431
|
+
return this.removeChildItem(removed, opts);
|
|
432
|
+
// const index = this.items.findIndex(i => i.key === key);
|
|
433
|
+
// if (index < 0) {
|
|
434
|
+
// return undefined;
|
|
435
|
+
// }
|
|
436
|
+
// const itemInfo = this.items[index];
|
|
437
|
+
// this.items.splice(index, 1);
|
|
438
|
+
// this.manager.definitions.delete(itemInfo.key);
|
|
439
|
+
// this.decreaseIndex(removed.index || 0);
|
|
440
|
+
|
|
441
|
+
// if (this.items.length === 0) {
|
|
442
|
+
// // remove panel (self)
|
|
443
|
+
// const parent = this.getParent();
|
|
444
|
+
// if (parent) {
|
|
445
|
+
// parent.removePanel(this.key);
|
|
446
|
+
// // Note, ignore `opts.noSideEffects` for tab close. It won't get dispatched elsewhere.
|
|
447
|
+
// this.manager.notifyTabClose(key);
|
|
448
|
+
// // no point doing the stuff below as the whole panel is removed.
|
|
449
|
+
// return removed;
|
|
450
|
+
// }
|
|
451
|
+
// }
|
|
452
|
+
// if (this.selected === key) {
|
|
453
|
+
// let nextKey: string | undefined;
|
|
454
|
+
// if (this.items[index]) {
|
|
455
|
+
// nextKey = this.items[index].key;
|
|
456
|
+
// } else if (this.items[index - 1]) {
|
|
457
|
+
// nextKey = this.items[index - 1].key;
|
|
458
|
+
// } else if (this.items.length) {
|
|
459
|
+
// const [item] = this.items;
|
|
460
|
+
// nextKey = item.key;
|
|
461
|
+
// }
|
|
462
|
+
// this.selected = nextKey;
|
|
463
|
+
// }
|
|
464
|
+
// if (!opts.noSideEffects) {
|
|
465
|
+
// this.manager.notifyTabClose(key);
|
|
466
|
+
// this.manager.notifyChange();
|
|
467
|
+
// this.manager.updateView(this.key);
|
|
468
|
+
// }
|
|
469
|
+
// return removed;
|
|
419
470
|
}
|
|
420
471
|
|
|
421
472
|
/**
|
|
@@ -423,30 +474,30 @@ export class SplitPanel {
|
|
|
423
474
|
* @param dir The direction to which close other items. Default to both directions leaving only the `key` item
|
|
424
475
|
*/
|
|
425
476
|
removeRelative(key: string, dir: SplitCloseDirection = SplitCloseDirection.both): void {
|
|
426
|
-
const
|
|
477
|
+
const items = this.sortedItems();
|
|
478
|
+
const index = items.findIndex(i => i.key === key);
|
|
427
479
|
if (index < 0) {
|
|
428
480
|
return;
|
|
429
481
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
let removed: IPanelObject[];
|
|
482
|
+
|
|
483
|
+
const item = items[index];
|
|
484
|
+
let removed: string[] = [];
|
|
434
485
|
if (dir === SplitCloseDirection.both) {
|
|
435
|
-
removed =
|
|
436
|
-
this.items = [item];
|
|
437
|
-
this.selected = item.key;
|
|
486
|
+
removed = items.filter(i => i !== item).map(i => i.key);
|
|
438
487
|
} else if (dir === SplitCloseDirection.left) {
|
|
439
|
-
removed =
|
|
440
|
-
this.items = this.items.splice(index);
|
|
441
|
-
this.selected = item.key;
|
|
488
|
+
removed = items.slice(0, index).map(i => i.key);
|
|
442
489
|
} else {
|
|
443
|
-
removed = this.items.slice(index + 1);
|
|
444
|
-
this.items = this.items.splice(0, index + 1);
|
|
445
|
-
this.selected = item.key;
|
|
490
|
+
removed = this.items.slice(index + 1).map(i => i.key);
|
|
446
491
|
}
|
|
492
|
+
this.items = this.items.filter(i => !removed.includes(i.key));
|
|
493
|
+
this.selected = item.key;
|
|
494
|
+
|
|
447
495
|
removed.forEach(i => {
|
|
448
|
-
this.manager.
|
|
449
|
-
|
|
496
|
+
const parents = this.manager.getParents(i);
|
|
497
|
+
if (!parents.length) {
|
|
498
|
+
this.manager.definitions.delete(i);
|
|
499
|
+
}
|
|
500
|
+
this.manager.notifyTabClose(i, this.key);
|
|
450
501
|
});
|
|
451
502
|
this.manager.notifyChange();
|
|
452
503
|
this.manager.updateView(this.key);
|
|
@@ -490,7 +541,7 @@ export class SplitPanel {
|
|
|
490
541
|
* @param key The item key
|
|
491
542
|
* @param toIndex The new index. When not set it moves the item to the end.
|
|
492
543
|
*/
|
|
493
|
-
moveItem(key: string,
|
|
544
|
+
moveItem(key: string, opts: SplitLayoutAddOptions = {}): void {
|
|
494
545
|
const info = this.items.find(i => i.key === key);
|
|
495
546
|
if (!info) {
|
|
496
547
|
return;
|
|
@@ -499,22 +550,54 @@ export class SplitPanel {
|
|
|
499
550
|
if (!item) {
|
|
500
551
|
return;
|
|
501
552
|
}
|
|
502
|
-
const
|
|
503
|
-
if (
|
|
553
|
+
const { index, region } = opts;
|
|
554
|
+
if (region) {
|
|
555
|
+
this.moveToRegion(item, region);
|
|
556
|
+
} else if (typeof index === 'number') {
|
|
557
|
+
this.moveToIndex(item, index);
|
|
558
|
+
} else {
|
|
559
|
+
this.moveToEnd(item);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
moveToRegion(item: SplitItem, region: SplitRegion): void {
|
|
564
|
+
if (this.items.length < 2) {
|
|
565
|
+
// nothing to split.
|
|
504
566
|
return;
|
|
505
567
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
568
|
+
if (region === SplitRegion.center) {
|
|
569
|
+
// the item is already there.
|
|
570
|
+
return;
|
|
509
571
|
}
|
|
510
|
-
|
|
511
|
-
|
|
572
|
+
const itemsIndex = this.items.findIndex(i => i.key === item.key);
|
|
573
|
+
if (itemsIndex < 0) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
this.items.splice(itemsIndex, 1);
|
|
577
|
+
const index = typeof item.index === 'number' ? item.index : this.nextIndex();
|
|
578
|
+
const panel = this.splitByRegion(region);
|
|
579
|
+
panel.addItem(item, { index });
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
moveToIndex(item: SplitItem, index: number): void {
|
|
583
|
+
if (item.index === index) {
|
|
584
|
+
return;
|
|
512
585
|
}
|
|
513
|
-
const
|
|
586
|
+
const hasTargetAtTarget = !!this.items[index as number];
|
|
587
|
+
this.decreaseIndex(item.index);
|
|
514
588
|
if (hasTargetAtTarget) {
|
|
515
|
-
this.increaseIndex(
|
|
589
|
+
this.increaseIndex(index);
|
|
590
|
+
}
|
|
591
|
+
item.index = index;
|
|
592
|
+
this.manager.notifyChange();
|
|
593
|
+
this.manager.updateView(this.key);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
moveToEnd(item: SplitItem): void {
|
|
597
|
+
if (item.index !== undefined) {
|
|
598
|
+
this.decreaseIndex(item.index);
|
|
516
599
|
}
|
|
517
|
-
item.index =
|
|
600
|
+
item.index = this.nextIndex();
|
|
518
601
|
this.manager.notifyChange();
|
|
519
602
|
this.manager.updateView(this.key);
|
|
520
603
|
}
|
|
@@ -70,7 +70,7 @@ export default class SplitView extends LitElement {
|
|
|
70
70
|
e.stopPropagation();
|
|
71
71
|
dataTransfer.dropEffect = 'copy';
|
|
72
72
|
}
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
protected handleDragOver(e: DragEvent): void {
|
|
75
75
|
const { dataTransfer } = e;
|
|
76
76
|
if (!dataTransfer || !this.panelCanDrop(e)) {
|
|
@@ -90,7 +90,8 @@ export default class SplitView extends LitElement {
|
|
|
90
90
|
|
|
91
91
|
protected handleDrop(e: DragEvent): void {
|
|
92
92
|
const { dataTransfer } = e;
|
|
93
|
-
|
|
93
|
+
const { panel } = this;
|
|
94
|
+
if (!dataTransfer || !panel || !this.panelCanDrop(e)) {
|
|
94
95
|
return;
|
|
95
96
|
}
|
|
96
97
|
e.preventDefault();
|
|
@@ -100,22 +101,23 @@ export default class SplitView extends LitElement {
|
|
|
100
101
|
if (!kind || !key) {
|
|
101
102
|
return;
|
|
102
103
|
}
|
|
104
|
+
const layoutKey = dataTransfer.getData('layout/key');
|
|
103
105
|
this.inDrag = false;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (
|
|
106
|
+
// TODO: When the drag originated in another panel then we
|
|
107
|
+
// move the panel between them. Otherwise we add the item to the panel.
|
|
108
|
+
if (layoutKey) {
|
|
109
|
+
// move operation not add.
|
|
110
|
+
panel.manager.moveItem(layoutKey, panel.key, key, { region: this.dragRegion });
|
|
111
|
+
} else {
|
|
107
112
|
panel.addItem({ key, kind, label: 'New tab' }, { region: this.dragRegion });
|
|
108
113
|
panel.manager.requestNameUpdate(key);
|
|
109
|
-
dispatch = true;
|
|
110
|
-
}
|
|
111
|
-
if (dispatch) {
|
|
112
|
-
this.dispatchEvent(new CustomEvent('datadrop', {
|
|
113
|
-
detail: { kind, key, region: this.dragRegion },
|
|
114
|
-
composed: true,
|
|
115
|
-
bubbles: true,
|
|
116
|
-
cancelable: true,
|
|
117
|
-
}));
|
|
118
114
|
}
|
|
115
|
+
this.dispatchEvent(new CustomEvent('datadrop', {
|
|
116
|
+
detail: { kind, key, region: this.dragRegion },
|
|
117
|
+
composed: true,
|
|
118
|
+
bubbles: true,
|
|
119
|
+
cancelable: true,
|
|
120
|
+
}));
|
|
119
121
|
this.requestUpdate();
|
|
120
122
|
}
|
|
121
123
|
|
|
@@ -282,7 +284,7 @@ export default class SplitView extends LitElement {
|
|
|
282
284
|
protected moveTab(fromLayout: string, toLayout: string, key: string, toIndex?: number): void {
|
|
283
285
|
const { panel } = this;
|
|
284
286
|
if (panel) {
|
|
285
|
-
panel.manager.moveItem(fromLayout, toLayout, key, toIndex);
|
|
287
|
+
panel.manager.moveItem(fromLayout, toLayout, key, { index: toIndex });
|
|
286
288
|
}
|
|
287
289
|
}
|
|
288
290
|
|
|
@@ -452,6 +454,7 @@ export default class SplitView extends LitElement {
|
|
|
452
454
|
data-index="${index}"
|
|
453
455
|
data-parent="${ifDefined(parent)}"
|
|
454
456
|
data-dirty="${isDirty}"
|
|
457
|
+
data-panel="${ifDefined(panel?.key)}"
|
|
455
458
|
role="tab"
|
|
456
459
|
class="${classMap(classes)}"
|
|
457
460
|
draggable="true"
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { ISplitLayout } from "./SplitLayout.js";
|
|
1
|
+
import type { TemplateResult } from "lit";
|
|
2
|
+
import type { SplitItem } from "./SplitItem.js";
|
|
3
|
+
import type { ISplitLayout } from "./SplitLayout.js";
|
|
5
4
|
|
|
6
5
|
export enum SplitDirection {
|
|
7
6
|
horizontal = 'horizontal',
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FolderKind, IFile,
|
|
3
|
+
ListFileKind
|
|
4
|
+
} from "@api-client/core/build/browser.js";
|
|
5
|
+
import { CSSResult, html, nothing, TemplateResult } from "lit";
|
|
6
|
+
import { eventOptions, property, query, state } from "lit/decorators.js";
|
|
7
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
8
|
+
import ApiElement from "../ApiElement.js";
|
|
9
|
+
import styles from './FilePicker.styles.js';
|
|
10
|
+
import { fileIcon } from "./FilesLib.js";
|
|
11
|
+
import type UiList from "../../ui/list/UiList.js";
|
|
12
|
+
import type { UiListSelection } from "../../ui/list/UiList.js";
|
|
13
|
+
import { FileSystem } from "../../store/FileSystem.js";
|
|
14
|
+
import '../../define/ui/ui-divider.js';
|
|
15
|
+
import '../../define/ui/ui-button.js';
|
|
16
|
+
import '../../define/ui/ui-icon-button.js';
|
|
17
|
+
import '../../define/ui/ui-icon.js';
|
|
18
|
+
import '../../define/ui/ui-list.js';
|
|
19
|
+
import '../../define/ui/ui-list-item.js';
|
|
20
|
+
import '../../define/ui/ui-progress.js';
|
|
21
|
+
|
|
22
|
+
export interface FilePickerClosingReason {
|
|
23
|
+
/**
|
|
24
|
+
* Whether the picker was canceled.
|
|
25
|
+
*/
|
|
26
|
+
canceled: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* The file selected by the user. This is always and only selected when the `canceled` is false.
|
|
29
|
+
*/
|
|
30
|
+
file?: IFile;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A portable element that allow to pick a file from the Store.
|
|
35
|
+
*
|
|
36
|
+
* @fires close - When a file is selected or the user cancelled the dialog. The detail object is the picked file object. Note, this event bubbles.
|
|
37
|
+
* @fires querycomplete - When the page of results was loaded.
|
|
38
|
+
*/
|
|
39
|
+
export default class FilePicker extends ApiElement {
|
|
40
|
+
static override get styles(): CSSResult[] {
|
|
41
|
+
return styles;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The key of the parent folder to query for files.
|
|
46
|
+
* @attribute
|
|
47
|
+
*/
|
|
48
|
+
@property({ type: String, hasChanged: () => false })
|
|
49
|
+
get folder(): string | undefined {
|
|
50
|
+
return this.fs.parent;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
set folder(value: string | undefined) {
|
|
54
|
+
this.fs.selectFolder(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The page limit. Defaults to the store defaults.
|
|
59
|
+
* @attribute
|
|
60
|
+
*/
|
|
61
|
+
@property({ type: Number, hasChanged: () => false })
|
|
62
|
+
set limit(value: number | undefined) {
|
|
63
|
+
this.fs.limit = value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get limit(): number | undefined {
|
|
67
|
+
return this.fs.limit;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The timeout for the page query debouncer.
|
|
72
|
+
* @attribute
|
|
73
|
+
*/
|
|
74
|
+
@property({ type: Number, hasChanged: () => false })
|
|
75
|
+
get debounceTimeout(): number {
|
|
76
|
+
return this.fs.debounceTimeout;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
set debounceTimeout(value: number) {
|
|
80
|
+
this.fs.debounceTimeout = value || 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* The list of file kinds to list.
|
|
85
|
+
* Folders are always included.
|
|
86
|
+
*/
|
|
87
|
+
@property({ type: Array, hasChanged: () => false })
|
|
88
|
+
get kinds(): ListFileKind[] | undefined {
|
|
89
|
+
return this.fs.kinds;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
set kinds(value: ListFileKind[] | undefined) {
|
|
93
|
+
this.fs.kinds = value;
|
|
94
|
+
this.fs.resetList();
|
|
95
|
+
this.fs.debounceQuery();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@query('ui-list') protected list?: UiList;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The currently selected in the picker file.
|
|
102
|
+
*/
|
|
103
|
+
@state() protected selectedFile?: IFile;
|
|
104
|
+
|
|
105
|
+
@state() errorMessage?: string;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* When set it does not query for files when attached to the DOM.
|
|
109
|
+
* It will still query for files when attributes change. This is primarily used in tests.
|
|
110
|
+
* @attribute
|
|
111
|
+
*/
|
|
112
|
+
@property({ type: Boolean }) manualQuery?: boolean;
|
|
113
|
+
|
|
114
|
+
get selectedKey(): string | undefined {
|
|
115
|
+
return this.selectedFile?.key;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
fs = new FileSystem();
|
|
119
|
+
|
|
120
|
+
constructor() {
|
|
121
|
+
super();
|
|
122
|
+
this.fs.eventsTarget = this;
|
|
123
|
+
this.fs.addEventListener('change', () => this.requestUpdate());
|
|
124
|
+
this.fs.addEventListener('error', (e: Event) => {
|
|
125
|
+
const event = e as CustomEvent<string>;
|
|
126
|
+
this.errorMessage = event.detail;
|
|
127
|
+
});
|
|
128
|
+
this.fs.addEventListener('querycomplete', () => {
|
|
129
|
+
this.dispatchEvent(new Event('querycomplete'));
|
|
130
|
+
});
|
|
131
|
+
this.fs.addEventListener('delete', (e: Event) => {
|
|
132
|
+
const event = e as CustomEvent<string>;
|
|
133
|
+
if (this.selectedFile && this.selectedFile.key === event.detail) {
|
|
134
|
+
this.selectedFile = undefined;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
override connectedCallback(): void {
|
|
140
|
+
super.connectedCallback();
|
|
141
|
+
this.fs.observe();
|
|
142
|
+
if (!this.manualQuery) {
|
|
143
|
+
this.fs.debounceQuery();
|
|
144
|
+
}
|
|
145
|
+
if (!this.hasAttribute('tabindex')) {
|
|
146
|
+
this.setAttribute('tabindex', '0');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
override disconnectedCallback(): void {
|
|
151
|
+
super.disconnectedCallback();
|
|
152
|
+
this.fs.unobserve();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
override focus(options?: FocusOptions | undefined): void {
|
|
156
|
+
const { list } = this;
|
|
157
|
+
if (list) {
|
|
158
|
+
list.focus(options);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
protected handleFileSelect(e: CustomEvent<UiListSelection>): void {
|
|
163
|
+
// this prevents the dropdown list to close the UI.
|
|
164
|
+
e.preventDefault();
|
|
165
|
+
const file = this.fs.files[e.detail.index];
|
|
166
|
+
if (!file) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (file.kind === FolderKind) {
|
|
170
|
+
this.fs.selectFolder(file.key);
|
|
171
|
+
this.selectedFile = undefined;
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
this.selectedFile = file;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
protected handleParentUp(): void {
|
|
178
|
+
this.fs.parentUp();
|
|
179
|
+
this.selectedFile = undefined;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
protected notifyClose(canceled: boolean): void {
|
|
183
|
+
if (!canceled && !this.selectedFile) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const detail: FilePickerClosingReason = {
|
|
187
|
+
canceled,
|
|
188
|
+
};
|
|
189
|
+
if (!canceled) {
|
|
190
|
+
detail.file = this.selectedFile;
|
|
191
|
+
}
|
|
192
|
+
// this event bubbles so any dropdown on the way can close itself.
|
|
193
|
+
const e = new CustomEvent<FilePickerClosingReason>('close', {
|
|
194
|
+
bubbles: true,
|
|
195
|
+
cancelable: true,
|
|
196
|
+
composed: true,
|
|
197
|
+
detail,
|
|
198
|
+
});
|
|
199
|
+
this.dispatchEvent(e);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
protected handleSelect(): void {
|
|
203
|
+
this.notifyClose(false);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
protected handleCancel(): void {
|
|
207
|
+
this.notifyClose(true);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@eventOptions({ passive: true })
|
|
211
|
+
protected handleListScroll(e: Event): void {
|
|
212
|
+
const list = e.target as UiList;
|
|
213
|
+
if (this.fs.isListEnd(list)) {
|
|
214
|
+
this.fs.debounceQuery();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
protected override render(): TemplateResult {
|
|
219
|
+
return html`
|
|
220
|
+
<div class="content">
|
|
221
|
+
${this.renderHeader()}
|
|
222
|
+
<ui-divider></ui-divider>
|
|
223
|
+
${this.renderFiles()}
|
|
224
|
+
${this.errorMessage ? html`<p class="error">${this.errorMessage}</p>` : nothing}
|
|
225
|
+
<ui-divider></ui-divider>
|
|
226
|
+
${this.renderActions()}
|
|
227
|
+
</div>
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
protected renderHeader(): TemplateResult {
|
|
232
|
+
const { breadcrumbs = [], reading } = this.fs;
|
|
233
|
+
let content: TemplateResult;
|
|
234
|
+
let withIcon = false;
|
|
235
|
+
if (!breadcrumbs.length) {
|
|
236
|
+
content = html`<span class="title-large label">My files</span>`;
|
|
237
|
+
} else {
|
|
238
|
+
withIcon = true;
|
|
239
|
+
const [parent] = breadcrumbs;
|
|
240
|
+
content = html`
|
|
241
|
+
<ui-icon-button aria-label="Open parent folder" @click="${this.handleParentUp}" class="back-button">
|
|
242
|
+
<ui-icon role="presentation" icon="arrowBack"></ui-icon>
|
|
243
|
+
</ui-icon-button>
|
|
244
|
+
<span class="title-large label">${parent.name}</span>
|
|
245
|
+
`;
|
|
246
|
+
}
|
|
247
|
+
const classes = {
|
|
248
|
+
header: true,
|
|
249
|
+
withIcon,
|
|
250
|
+
}
|
|
251
|
+
return html`
|
|
252
|
+
<div class="${classMap(classes)}">
|
|
253
|
+
${content}
|
|
254
|
+
${reading ? html`<ui-progress indeterminate class="progress"></ui-progress>` : nothing}
|
|
255
|
+
</div>
|
|
256
|
+
`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
protected renderFiles(): TemplateResult {
|
|
260
|
+
const { files } = this.fs;
|
|
261
|
+
if (!files || !files.length) {
|
|
262
|
+
return this.renderEmptyList();
|
|
263
|
+
}
|
|
264
|
+
return html`
|
|
265
|
+
<ui-list class="list" role="menu" @select="${this.handleFileSelect}" selectActive @scroll="${this.handleListScroll}">
|
|
266
|
+
${files.map(item => this.renderFileItem(item))}
|
|
267
|
+
</ui-list>
|
|
268
|
+
`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
protected renderEmptyList(): TemplateResult {
|
|
272
|
+
return html`
|
|
273
|
+
<p class="no-files body-large">No files in this view.</p>
|
|
274
|
+
`;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
protected renderFileItem(item: IFile): TemplateResult {
|
|
278
|
+
const icon = fileIcon(item);
|
|
279
|
+
return html`
|
|
280
|
+
<ui-list-item role="menuitem" data-key="${item.key}" data-kind="${item.kind}">
|
|
281
|
+
${icon ? html`<ui-icon icon="${icon}" class="file-icon"></ui-icon>` : nothing}
|
|
282
|
+
${item.info.name || 'Unnamed file'}
|
|
283
|
+
</ui-list-item>
|
|
284
|
+
`;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
protected renderActions(): TemplateResult {
|
|
288
|
+
const { selectedFile } = this;
|
|
289
|
+
const disableSelect = !selectedFile;
|
|
290
|
+
return html`
|
|
291
|
+
<div class="actions">
|
|
292
|
+
<ui-button type="text" @click="${this.handleCancel}" value="cancel">Cancel</ui-button>
|
|
293
|
+
<ui-button type="tonal" ?disabled="${disableSelect}" @click="${this.handleSelect}" value="select">Select</ui-button>
|
|
294
|
+
</div>
|
|
295
|
+
`;
|
|
296
|
+
}
|
|
297
|
+
}
|