@visin/frontend-core 1.12.0 → 1.14.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.
Files changed (43) hide show
  1. package/dist/auth/AuthProvider.d.ts +2 -0
  2. package/dist/auth/AuthProvider.d.ts.map +1 -1
  3. package/dist/auth/AuthProvider.js +7 -1
  4. package/dist/auth/AuthProvider.js.map +1 -1
  5. package/dist/auth/authService.d.ts +11 -1
  6. package/dist/auth/authService.d.ts.map +1 -1
  7. package/dist/auth/authService.js +4 -2
  8. package/dist/auth/authService.js.map +1 -1
  9. package/dist/components/AppLayout/AppLayout.d.ts +42 -5
  10. package/dist/components/AppLayout/AppLayout.d.ts.map +1 -1
  11. package/dist/components/AppLayout/AppLayout.js +89 -33
  12. package/dist/components/AppLayout/AppLayout.js.map +1 -1
  13. package/dist/components/AppLayout/index.d.ts +1 -1
  14. package/dist/components/AppLayout/index.d.ts.map +1 -1
  15. package/dist/components/Markdown/Markdown.d.ts +11 -0
  16. package/dist/components/Markdown/Markdown.d.ts.map +1 -0
  17. package/dist/components/Markdown/Markdown.js +63 -0
  18. package/dist/components/Markdown/Markdown.js.map +1 -0
  19. package/dist/components/Markdown/index.d.ts +2 -0
  20. package/dist/components/Markdown/index.d.ts.map +1 -0
  21. package/dist/components/Markdown/index.js +2 -0
  22. package/dist/components/Markdown/index.js.map +1 -0
  23. package/dist/components/Markdown/parse.d.ts +65 -0
  24. package/dist/components/Markdown/parse.d.ts.map +1 -0
  25. package/dist/components/Markdown/parse.js +247 -0
  26. package/dist/components/Markdown/parse.js.map +1 -0
  27. package/dist/components/ShareButton.d.ts +5 -0
  28. package/dist/components/ShareButton.d.ts.map +1 -0
  29. package/dist/components/ShareButton.js +23 -0
  30. package/dist/components/ShareButton.js.map +1 -0
  31. package/dist/index.d.ts +6 -2
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +3 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/navigation.d.ts +12 -2
  36. package/dist/navigation.d.ts.map +1 -1
  37. package/dist/navigation.js +43 -7
  38. package/dist/navigation.js.map +1 -1
  39. package/dist/recentVisits.d.ts +26 -0
  40. package/dist/recentVisits.d.ts.map +1 -0
  41. package/dist/recentVisits.js +97 -0
  42. package/dist/recentVisits.js.map +1 -0
  43. package/package.json +8 -8
@@ -1,11 +1,22 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Assignment, Folder, FolderCopy, Groups, Insights, Key, Label, Link as LinkIcon, ModelTraining, Person, PhotoLibrary, Storage } from '@mui/icons-material';
2
+ import { Assessment, Assignment, Checklist, EmojiEvents, Explore, Folder, FolderCopy, Groups, Home, Insights, Key, Label, Link as LinkIcon, Memory, ModelTraining, Person, PhotoLibrary, Scoreboard, Storage } from '@mui/icons-material';
3
3
  /**
4
4
  * The whole menu, grouped by what the user is doing. Every app renders the same
5
5
  * groups in the same places; crossing apps changes which entry is highlighted,
6
6
  * never what the menu contains.
7
7
  */
8
8
  const NAV_GROUPS = [
9
+ {
10
+ label: 'Home',
11
+ signedOutLabel: 'Explore',
12
+ icon: _jsx(Home, {}),
13
+ sections: [
14
+ // A visitor's front page is Explore itself; a signed-in session opens on its own
15
+ // dashboard and keeps Explore one tab over.
16
+ { app: 'shell', text: 'For you', icon: _jsx(Home, {}), path: '/', signedInOnly: true },
17
+ { app: 'shell', text: 'Explore', icon: _jsx(Explore, {}), path: '/explore', signedOutPath: '/' }
18
+ ]
19
+ },
9
20
  {
10
21
  label: 'Projects',
11
22
  icon: _jsx(Folder, {}),
@@ -25,9 +36,20 @@ const NAV_GROUPS = [
25
36
  icon: _jsx(Storage, {}),
26
37
  sections: [{ app: 'vision', text: 'Datasets', icon: _jsx(PhotoLibrary, {}), path: '/datasets' }]
27
38
  },
39
+ {
40
+ label: 'Leaderboards',
41
+ icon: _jsx(EmojiEvents, {}),
42
+ sections: [
43
+ { app: 'vision', text: 'Leaderboards', icon: _jsx(Scoreboard, {}), path: '/leaderboards' },
44
+ { app: 'vision', text: 'Models', icon: _jsx(Memory, {}), path: '/models' },
45
+ { app: 'vision', text: 'Suites', icon: _jsx(Checklist, {}), path: '/suites' },
46
+ { app: 'vision', text: 'Evaluations', icon: _jsx(Assessment, {}), path: '/evaluations' }
47
+ ]
48
+ },
28
49
  {
29
50
  label: 'Labels',
30
51
  icon: _jsx(Label, {}),
52
+ signedInOnly: true,
31
53
  // A labeling job is built on a dataset, which lives under Data; "New job"
32
54
  // is deliberately not here either, being an action on the Jobs list.
33
55
  sections: [{ app: 'label', text: 'Jobs', icon: _jsx(Assignment, {}), path: '/jobs' }]
@@ -52,22 +74,36 @@ const stripTrailingSlash = (url) => url.replace(/\/$/, '');
52
74
  * should hide Jobs, not leave entries that 404 inside Vision. A
53
75
  * group left with no sections is omitted with them.
54
76
  */
55
- export function createVisinNavigation(localApps, urls) {
77
+ export function createVisinNavigation(localApps, urls, { isAuthenticated = true } = {}) {
56
78
  const local = new Set(localApps === null ? [] : typeof localApps === 'string' ? [localApps] : localApps);
57
- const toItems = ({ app, text, icon, path }) => {
79
+ const toItems = ({ app, text, icon, path, signedInOnly, signedOutPath }) => {
80
+ if (signedInOnly && !isAuthenticated) {
81
+ return [];
82
+ }
83
+ const target = !isAuthenticated && signedOutPath ? signedOutPath : path;
58
84
  if (local.has(app)) {
59
- return [{ text, icon, path }];
85
+ return [{ text, icon, path: target }];
60
86
  }
61
87
  const baseUrl = urls[app];
62
- return baseUrl ? [{ text, icon, href: `${stripTrailingSlash(baseUrl)}${path}` }] : [];
88
+ return baseUrl ? [{ text, icon, href: `${stripTrailingSlash(baseUrl)}${target}` }] : [];
63
89
  };
64
- const groups = NAV_GROUPS.flatMap(({ label, icon, sections, pages }) => {
90
+ const groups = NAV_GROUPS.flatMap(({ label, signedOutLabel, icon, sections, pages, signedInOnly }) => {
91
+ if (signedInOnly && !isAuthenticated) {
92
+ return [];
93
+ }
65
94
  const items = sections.flatMap(toItems);
66
95
  if (items.length === 0) {
67
96
  return [];
68
97
  }
69
98
  // Another app's pages never render on this one, so only local ones can match.
70
- return [{ label, icon, items, match: pages && local.has(pages.app) ? pages.paths : [] }];
99
+ return [
100
+ {
101
+ label: !isAuthenticated && signedOutLabel ? signedOutLabel : label,
102
+ icon,
103
+ items,
104
+ match: pages && local.has(pages.app) ? pages.paths : []
105
+ }
106
+ ];
71
107
  });
72
108
  return { groups, accountItems: ACCOUNT_SECTIONS.flatMap(toItems) };
73
109
  }
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /** What can be visited again: the pages a person comes back to. */
2
+ export type VisitKind = 'project' | 'dataset' | 'training' | 'person' | 'group';
3
+ export interface Visit {
4
+ kind: VisitKind;
5
+ /** With `kind`, what identifies it: opening the same thing again moves it to the front rather than adding a second. */
6
+ id: string;
7
+ name: string;
8
+ /** Where it is, as a path within the app. */
9
+ path: string;
10
+ /** Milliseconds since the epoch. */
11
+ visitedAt: number;
12
+ }
13
+ /** The visits, newest first. */
14
+ export declare const readVisits: () => Visit[];
15
+ /** Opening something again moves it to the front; the oldest fall off past ten. */
16
+ export declare function recordVisit(visit: Omit<Visit, 'visitedAt'>, now?: number): void;
17
+ /** Forgets everything. Also what signing out does, so the next person at this browser does not read the last one's. */
18
+ export declare function clearVisits(): void;
19
+ /** What this browser has visited lately, newest first, kept up to date across tabs and across the apps on the page. */
20
+ export declare function useRecentVisits(): Visit[];
21
+ /**
22
+ * Notes that the page showing `visit` was opened. Call it once what is shown has loaded (pass `null` until then):
23
+ * the name is what the list will say, so a page that is still loading has none to give.
24
+ */
25
+ export declare function useTrackVisit(visit: Omit<Visit, 'visitedAt'> | null): void;
26
+ //# sourceMappingURL=recentVisits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recentVisits.d.ts","sourceRoot":"","sources":["../src/recentVisits.ts"],"names":[],"mappings":"AAEA,mEAAmE;AACnE,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEhF,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,uHAAuH;IACvH,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;CACnB;AA0CD,gCAAgC;AAChC,eAAO,MAAM,UAAU,QAAO,KAAK,EAAsB,CAAC;AAY1D,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,EAAE,GAAG,SAAa,GAAG,IAAI,CAGnF;AAED,uHAAuH;AACvH,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAmBD,uHAAuH;AACvH,wBAAgB,eAAe,IAAI,KAAK,EAAE,CAEzC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,GAAG,IAAI,GAAG,IAAI,CAQ1E"}
@@ -0,0 +1,97 @@
1
+ import { useEffect, useSyncExternalStore } from 'react';
2
+ const KEY = 'visin-recent';
3
+ /** The browser's own copy changed: the one event every copy of this module (the shell's, each remote's) listens for. */
4
+ const CHANGED = 'visin:recent-visits';
5
+ const MAX_VISITS = 10;
6
+ const KINDS = ['project', 'dataset', 'training', 'person', 'group'];
7
+ const isVisit = (value) => {
8
+ const visit = value;
9
+ return (typeof visit === 'object' &&
10
+ visit !== null &&
11
+ KINDS.includes(visit.kind) &&
12
+ typeof visit.id === 'string' &&
13
+ typeof visit.name === 'string' &&
14
+ typeof visit.path === 'string' &&
15
+ visit.path.startsWith('/') &&
16
+ typeof visit.visitedAt === 'number');
17
+ };
18
+ // Per-browser, never sent anywhere, and allowed to be unavailable (a private window, blocked storage): every read
19
+ // and write is guarded, and the list is simply empty then.
20
+ const readRaw = () => {
21
+ try {
22
+ return localStorage.getItem(KEY) ?? '';
23
+ }
24
+ catch {
25
+ return '';
26
+ }
27
+ };
28
+ const parse = (raw) => {
29
+ if (!raw)
30
+ return [];
31
+ try {
32
+ const value = JSON.parse(raw);
33
+ return Array.isArray(value) ? value.filter(isVisit).sort((a, b) => b.visitedAt - a.visitedAt).slice(0, MAX_VISITS) : [];
34
+ }
35
+ catch {
36
+ return [];
37
+ }
38
+ };
39
+ /** The visits, newest first. */
40
+ export const readVisits = () => parse(readRaw());
41
+ const write = (visits) => {
42
+ try {
43
+ if (visits.length === 0)
44
+ localStorage.removeItem(KEY);
45
+ else
46
+ localStorage.setItem(KEY, JSON.stringify(visits));
47
+ }
48
+ catch {
49
+ // Nowhere to keep it: the list stays empty, and nothing else depends on it.
50
+ }
51
+ window.dispatchEvent(new Event(CHANGED));
52
+ };
53
+ /** Opening something again moves it to the front; the oldest fall off past ten. */
54
+ export function recordVisit(visit, now = Date.now()) {
55
+ const others = readVisits().filter((held) => !(held.kind === visit.kind && held.id === visit.id));
56
+ write([{ ...visit, visitedAt: now }, ...others].slice(0, MAX_VISITS));
57
+ }
58
+ /** Forgets everything. Also what signing out does, so the next person at this browser does not read the last one's. */
59
+ export function clearVisits() {
60
+ write([]);
61
+ }
62
+ let snapshot = { raw: '', visits: [] };
63
+ const getSnapshot = () => {
64
+ const raw = readRaw();
65
+ if (raw !== snapshot.raw)
66
+ snapshot = { raw, visits: parse(raw) };
67
+ return snapshot.visits;
68
+ };
69
+ const subscribe = (listener) => {
70
+ window.addEventListener(CHANGED, listener);
71
+ // Another tab's change.
72
+ window.addEventListener('storage', listener);
73
+ return () => {
74
+ window.removeEventListener(CHANGED, listener);
75
+ window.removeEventListener('storage', listener);
76
+ };
77
+ };
78
+ const empty = [];
79
+ /** What this browser has visited lately, newest first, kept up to date across tabs and across the apps on the page. */
80
+ export function useRecentVisits() {
81
+ return useSyncExternalStore(subscribe, getSnapshot, () => empty);
82
+ }
83
+ /**
84
+ * Notes that the page showing `visit` was opened. Call it once what is shown has loaded (pass `null` until then):
85
+ * the name is what the list will say, so a page that is still loading has none to give.
86
+ */
87
+ export function useTrackVisit(visit) {
88
+ const kind = visit?.kind;
89
+ const id = visit?.id;
90
+ const name = visit?.name;
91
+ const path = visit?.path;
92
+ useEffect(() => {
93
+ if (kind && id && name && path)
94
+ recordVisit({ kind, id, name, path });
95
+ }, [kind, id, name, path]);
96
+ }
97
+ //# sourceMappingURL=recentVisits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recentVisits.js","sourceRoot":"","sources":["../src/recentVisits.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visin/frontend-core",
3
- "version": "1.12.0",
3
+ "version": "1.14.0",
4
4
  "description": "Shared frontend auth/API-client logic for Visin frontends",
5
5
  "author": "Toomas Tahves",
6
6
  "license": "MIT",
@@ -58,17 +58,17 @@
58
58
  "@mui/material": "^9.4.0",
59
59
  "@testing-library/jest-dom": "^7.0.1",
60
60
  "@testing-library/react": "^16.3.3",
61
- "@types/node": "^26.5.1",
61
+ "@types/node": "^26.6.3",
62
62
  "@types/react": "^19.3.0",
63
- "@vitest/coverage-v8": "^4.1.11",
64
- "eslint": "^10.10.0",
65
- "jsdom": "^30.0.1",
63
+ "@vitest/coverage-v8": "^5.0.2",
64
+ "eslint": "^10.11.0",
65
+ "jsdom": "^30.1.1",
66
66
  "react": "^19.3.0",
67
67
  "react-dom": "^19.3.0",
68
- "react-router-dom": "^7.18.3",
68
+ "react-router-dom": "^7.18.4",
69
69
  "standard-version": "^9.5.0",
70
70
  "typescript": "^6.0.3",
71
- "typescript-eslint": "^8.70.0",
72
- "vitest": "^4.1.11"
71
+ "typescript-eslint": "^8.71.0",
72
+ "vitest": "^5.0.2"
73
73
  }
74
74
  }