@milaboratories/uikit 2.2.60 → 2.2.62

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@milaboratories/uikit",
3
- "version": "2.2.60",
3
+ "version": "2.2.62",
4
4
  "type": "module",
5
5
  "main": "dist/pl-uikit.umd.js",
6
6
  "module": "dist/pl-uikit.js",
@@ -26,7 +26,7 @@
26
26
  "@vueuse/core": "~12.4.0",
27
27
  "jsdom": "^25.0.1",
28
28
  "resize-observer-polyfill": "^1.5.1",
29
- "@vitejs/plugin-vue": "^5.2.1",
29
+ "@vitejs/plugin-vue": "^5.2.3",
30
30
  "tsc-alias": "^1.8.11",
31
31
  "vitest": "^2.1.8",
32
32
  "vite": "^5.4.11",
@@ -34,9 +34,9 @@
34
34
  "yarpm": "^1.2.0",
35
35
  "svgo": "^3.3.2",
36
36
  "@types/d3": "^7.4.3",
37
- "@milaboratories/eslint-config": "^1.0.1",
38
37
  "@milaboratories/helpers": "^1.6.11",
39
- "@platforma-sdk/model": "^1.24.0"
38
+ "@milaboratories/eslint-config": "^1.0.4",
39
+ "@platforma-sdk/model": "^1.27.10"
40
40
  },
41
41
  "scripts": {
42
42
  "dev": "vite",
@@ -3,7 +3,7 @@ import style from './pl-file-dialog.module.scss';
3
3
  import type { ImportedFiles } from '@/types';
4
4
  import { PlIcon24 } from '../PlIcon24';
5
5
  import { computed, reactive } from 'vue';
6
- import type { OpenDialogFilter } from '@platforma-sdk/model';
6
+ import { getRawPlatformaInstance, type OpenDialogFilter } from '@platforma-sdk/model';
7
7
  import { normalizeExtensions } from './utils';
8
8
 
9
9
  const props = defineProps<{
@@ -19,10 +19,10 @@ const data = reactive({
19
19
  const label = computed(() => (props.multi ? 'Drag & Drop files here or click to add' : 'Drag & Drop file here or click to add'));
20
20
 
21
21
  const onDrop = async (ev: DragEvent) => {
22
- const fileToImportHandle = window.platforma?.lsDriver?.fileToImportHandle;
22
+ const fileToImportHandle = getRawPlatformaInstance()?.lsDriver?.fileToImportHandle;
23
23
 
24
24
  if (!fileToImportHandle) {
25
- return console.error('API platforma.lsDriver.fileToImportHandle is not available');
25
+ return console.error('API getPlatformaRawInstance().lsDriver.fileToImportHandle is not available');
26
26
  }
27
27
 
28
28
  const extensions = normalizeExtensions(props.extensions);
@@ -54,7 +54,7 @@ const openNativeDialog = async () => {
54
54
  : [];
55
55
 
56
56
  if (props.multi) {
57
- window.platforma?.lsDriver
57
+ getRawPlatformaInstance()?.lsDriver
58
58
  .showOpenMultipleFilesDialog({
59
59
  title: 'Select files to import',
60
60
  filters,
@@ -68,7 +68,7 @@ const openNativeDialog = async () => {
68
68
  })
69
69
  .catch((err) => (data.error = err));
70
70
  } else {
71
- window.platforma?.lsDriver
71
+ getRawPlatformaInstance()?.lsDriver
72
72
  .showOpenSingleFileDialog({
73
73
  title: 'Select file to import',
74
74
  filters,
@@ -2,7 +2,7 @@
2
2
  import { useEventListener } from '@/composition/useEventListener';
3
3
  import type { ImportedFiles } from '@/types';
4
4
  import { between, notEmpty, tapIf } from '@milaboratories/helpers';
5
- import type { StorageHandle } from '@platforma-sdk/model';
5
+ import { getRawPlatformaInstance, type StorageHandle } from '@platforma-sdk/model';
6
6
  import { computed, onMounted, reactive, toRef, watch } from 'vue';
7
7
  import { PlDropdown } from '../PlDropdown';
8
8
  import { PlIcon16 } from '../PlIcon16';
@@ -58,7 +58,7 @@ const lookup = computed(() => {
58
58
  });
59
59
 
60
60
  const query = (storageHandle: StorageHandle, dirPath: string) => {
61
- if (!window.platforma) {
61
+ if (!getRawPlatformaInstance()) {
62
62
  return;
63
63
  }
64
64
 
@@ -68,7 +68,7 @@ const query = (storageHandle: StorageHandle, dirPath: string) => {
68
68
 
69
69
  data.currentLoadingPath = dirPath;
70
70
 
71
- window.platforma.lsDriver
71
+ getRawPlatformaInstance().lsDriver
72
72
  .listFiles(storageHandle, dirPath)
73
73
  .then((res) => {
74
74
  if (dirPath !== data.dirPath) {
@@ -186,11 +186,11 @@ const deselectAll = () => changeAll(false);
186
186
  const loadAvailableStorages = () => {
187
187
  resetData();
188
188
  deselectAll();
189
- if (!window.platforma) {
189
+ if (!getRawPlatformaInstance()) {
190
190
  console.warn('platforma API is not found');
191
191
  return;
192
192
  }
193
- window.platforma.lsDriver
193
+ getRawPlatformaInstance().lsDriver
194
194
  .getStorageList()
195
195
  .then((storageEntries) => {
196
196
  // local storage is always returned by the ML, so we need to remove it from remote dialog manually
@@ -0,0 +1,51 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { getFilePathBreadcrumbs } from './utils';
3
+
4
+ describe('getFilePathBreadcrumbs', () => {
5
+ test.each([
6
+ {
7
+ name: 'root path "/"',
8
+ path: '/',
9
+ expected: [
10
+ { index: 0, name: 'Root', path: '' },
11
+ ],
12
+ },
13
+ {
14
+ name: 'empty path ""',
15
+ path: '',
16
+ expected: [
17
+ { index: 0, name: 'Root', path: '' },
18
+ ],
19
+ },
20
+ {
21
+ name: 'single-level path "/folder"',
22
+ path: '/folder',
23
+ expected: [
24
+ { index: 0, name: 'Root', path: '' },
25
+ { index: 1, name: 'folder', path: '/folder' },
26
+ ],
27
+ },
28
+ {
29
+ name: 'multi-level path "/folder/subfolder/file.txt"',
30
+ path: '/folder/subfolder/file.txt',
31
+ expected: [
32
+ { index: 0, name: 'Root', path: '' },
33
+ { index: 1, name: 'folder', path: '/folder' },
34
+ { index: 2, name: 'subfolder', path: '/folder/subfolder' },
35
+ { index: 3, name: 'file.txt', path: '/folder/subfolder/file.txt' },
36
+ ],
37
+ },
38
+ {
39
+ name: 'path without leading slash "folder/file.txt"',
40
+ path: 'folder/file.txt',
41
+ expected: [
42
+ { index: 0, name: 'Root', path: '' },
43
+ { index: 1, name: 'folder', path: 'folder' },
44
+ { index: 2, name: 'file.txt', path: 'folder/file.txt' },
45
+ ],
46
+ },
47
+ ])('should handle $name', ({ path, expected }) => {
48
+ const result = getFilePathBreadcrumbs(path);
49
+ expect(result).toEqual(expected);
50
+ });
51
+ });
@@ -1,27 +1,42 @@
1
- import { trimCharsLeft } from '@milaboratories/helpers';
1
+ import { trimChars, trimCharsLeft } from '@milaboratories/helpers';
2
2
  import type { ImportFileHandle } from '@platforma-sdk/model';
3
3
 
4
4
  export function normalizeExtensions(extensions: string[] | undefined) {
5
5
  return extensions ? extensions.map((it) => '.' + trimCharsLeft(it, ['.'])) : undefined;
6
6
  }
7
7
 
8
+ // NOTE: works only with '/' separator on *nix systems.
8
9
  export function getFilePathBreadcrumbs(filePath: string) {
9
- const chunks = filePath.split('/');
10
+ // FIXME: separator probably should be got from ls driver from backend.
11
+ // or else this component won't work with remote storages on Windows.
12
+ const sep = '/';
10
13
 
11
- if (chunks[0] !== '') {
12
- chunks.unshift('');
13
- }
14
+ // If file path starts with '/',
15
+ // the storage was set up with absolute paths,
16
+ // and we need to add the separator to the results.
17
+ const isAbsolute = filePath.startsWith(sep);
18
+ const chunks = trimChars(filePath, [sep]).split(sep);
19
+
20
+ const stack: { index: number; path: string; name: string }[] = [
21
+ {
22
+ index: 0,
23
+ name: 'Root',
24
+ path: '',
25
+ },
26
+ ];
14
27
 
15
- const stack: { index: number; path: string; name: string }[] = [];
28
+ if (chunks.length === 1 && chunks[0] === '') {
29
+ return stack;
30
+ }
16
31
 
17
32
  for (let i = 0; i < chunks.length; i++) {
33
+ const pathPrefix = isAbsolute ? sep : '';
34
+ const p = pathPrefix + chunks.slice(0, i + 1).join(sep);
35
+
18
36
  stack.push({
19
- index: i,
20
- name: i === 0 ? 'Root' : chunks[i],
21
- path: chunks
22
- .slice(0, i + 1)
23
- .filter((c) => c !== '')
24
- .join('/'),
37
+ index: i + 1,
38
+ name: chunks[i],
39
+ path: p,
25
40
  });
26
41
  }
27
42
 
@@ -31,6 +31,10 @@ const props = defineProps<{
31
31
  * String contents
32
32
  */
33
33
  value?: string;
34
+ /**
35
+ * The content to copy (Note: it takes precedence over value property)
36
+ */
37
+ valueToCopy?: string;
34
38
  /**
35
39
  * AnyLogHandle
36
40
  */
@@ -85,8 +89,15 @@ const onClickCopy = () => {
85
89
  copyActive.value = false;
86
90
  }, 1200);
87
91
 
88
- if (computedValue.value && typeof computedValue.value === 'string') {
89
- navigator.clipboard.writeText(computedValue.value);
92
+ let toCopy: string | undefined = undefined;
93
+ if (props.valueToCopy) {
94
+ toCopy = props.valueToCopy;
95
+ } else if (computedValue.value && typeof computedValue.value === 'string') {
96
+ toCopy = computedValue.value;
97
+ }
98
+
99
+ if (toCopy !== undefined) {
100
+ navigator.clipboard.writeText(toCopy);
90
101
  }
91
102
  };
92
103
 
@@ -1,6 +1,6 @@
1
1
  import { reactive, type Reactive, ref, watch } from 'vue';
2
2
  import { useTimeoutPoll, whenever } from '@vueuse/core';
3
- import type { AnyLogHandle, Platforma } from '@platforma-sdk/model';
3
+ import { getRawPlatformaInstance, type AnyLogHandle, type Platforma } from '@platforma-sdk/model';
4
4
 
5
5
  type LogState = {
6
6
  logHandle: AnyLogHandle;
@@ -32,7 +32,7 @@ export function useLogHandle(
32
32
 
33
33
  if (currentLogState === undefined) return;
34
34
 
35
- const platforma = props.mockPlatforma ?? window.platforma;
35
+ const platforma = props.mockPlatforma ?? getRawPlatformaInstance();
36
36
 
37
37
  if (!platforma) {
38
38
  console.warn('Platforma API is not available');