@morscherlab/mint-sdk 1.0.0-beta.7 → 1.0.0-rc.2
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/README.md +9 -1
- package/dist/__tests__/components/LcmsSequenceTable.test.d.ts +1 -0
- package/dist/__tests__/components/ProgressBar.test.d.ts +1 -0
- package/dist/__tests__/components/RackEditor.test.d.ts +1 -0
- package/dist/__tests__/components/SequenceProgressBar.test.d.ts +1 -0
- package/dist/__tests__/composables/useExperimentSamples.test.d.ts +1 -0
- package/dist/__tests__/composables/useProtocolTemplates.test.d.ts +1 -0
- package/dist/__tests__/stores/settings.test.d.ts +1 -0
- package/dist/__tests__/utils/instrument.test.d.ts +1 -0
- package/dist/__tests__/utils/lcms.test.d.ts +1 -0
- package/dist/__tests__/utils/permissions.test.d.ts +1 -0
- package/dist/__tests__/utils/rack.test.d.ts +1 -0
- package/dist/{auth-QQj2kkze.js → auth-B7g4J4ZF.js} +148 -24
- package/dist/auth-B7g4J4ZF.js.map +1 -0
- package/dist/components/AutoGroupModal.vue.d.ts +1 -1
- package/dist/components/BaseCheckbox.vue.d.ts +1 -1
- package/dist/components/BaseToggle.vue.d.ts +2 -2
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +1 -1
- package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +1 -1
- package/dist/components/BioTemplatePresetWorkspaceView.vue.d.ts +1 -1
- package/dist/components/DoseDesignWorkspaceView.vue.d.ts +1 -1
- package/dist/components/FormulaInput.vue.d.ts +1 -1
- package/dist/components/InstrumentAlertLog.vue.d.ts +22 -0
- package/dist/components/InstrumentStateBadge.vue.d.ts +11 -0
- package/dist/components/InstrumentStatusCard.vue.d.ts +13 -0
- package/dist/components/LcmsSequenceTable.vue.d.ts +26 -0
- package/dist/components/ProgressBar.vue.d.ts +1 -0
- package/dist/components/RackEditor.vue.d.ts +41 -3
- package/dist/components/ReagentList.vue.d.ts +1 -1
- package/dist/components/SampleSelector.vue.d.ts +5 -2
- package/dist/components/SegmentedControl.vue.d.ts +2 -0
- package/dist/components/SequenceInput.vue.d.ts +1 -1
- package/dist/components/SequenceProgressBar.vue.d.ts +15 -0
- package/dist/components/SettingsModal.vue.d.ts +8 -1
- package/dist/components/TagsInput.vue.d.ts +1 -1
- package/dist/components/WellPlate.vue.d.ts +42 -3
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.js +3 -3
- package/dist/{components-DihbSJjU.js → components-BhK-dW99.js} +2135 -1075
- package/dist/components-BhK-dW99.js.map +1 -0
- package/dist/composables/experimentDesignData.d.ts +17 -0
- package/dist/composables/index.d.ts +2 -0
- package/dist/composables/index.js +4 -4
- package/dist/composables/useControlSchema.d.ts +11 -0
- package/dist/composables/useExperimentData.d.ts +11 -3
- package/dist/composables/useExperimentSamples.d.ts +42 -0
- package/dist/composables/usePlatformContext.d.ts +54 -0
- package/dist/{composables-BcgZ6diz.js → composables-Bg7CFuNz.js} +5 -3
- package/dist/composables-Bg7CFuNz.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +168 -6
- package/dist/index.js.map +1 -0
- package/dist/install.js +2 -2
- package/dist/instrument.d.ts +7 -0
- package/dist/lcms.d.ts +27 -0
- package/dist/permissions.d.ts +46 -0
- package/dist/stores/auth.d.ts +74 -2
- package/dist/stores/index.js +1 -1
- package/dist/styles.css +3186 -1070
- package/dist/templates/builders.d.ts +7 -3
- package/dist/templates/index.d.ts +2 -2
- package/dist/templates/index.js +2 -2
- package/dist/templates/presets.d.ts +12 -0
- package/dist/templates/types.d.ts +16 -1
- package/dist/{templates-Cyt0Suwf.js → templates-BorLR_7p.js} +324 -10
- package/dist/templates-BorLR_7p.js.map +1 -0
- package/dist/types/auth.d.ts +2 -0
- package/dist/types/components.d.ts +32 -3
- package/dist/types/form-builder.d.ts +2 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/instrument.d.ts +56 -0
- package/dist/types/platform.d.ts +3 -0
- package/dist/{useExperimentData-CM6Y0u5L.js → useProtocolTemplates-n6AJqSqv.js} +627 -380
- package/dist/useProtocolTemplates-n6AJqSqv.js.map +1 -0
- package/dist/utils/rack.d.ts +47 -0
- package/package.json +1 -1
- package/src/__tests__/components/AppTopBar.test.ts +15 -0
- package/src/__tests__/components/BaseTabs.test.ts +15 -0
- package/src/__tests__/components/GroupAssigner.test.ts +18 -0
- package/src/__tests__/components/LcmsSequenceTable.test.ts +57 -0
- package/src/__tests__/components/ProgressBar.test.ts +18 -0
- package/src/__tests__/components/RackEditor.test.ts +125 -0
- package/src/__tests__/components/SampleSelector.test.ts +25 -0
- package/src/__tests__/components/SegmentedControl.test.ts +45 -0
- package/src/__tests__/components/SequenceProgressBar.test.ts +39 -0
- package/src/__tests__/components/SettingsModal.test.ts +83 -2
- package/src/__tests__/composables/useApi.test.ts +45 -0
- package/src/__tests__/composables/useAuth.test.ts +20 -0
- package/src/__tests__/composables/useControlSchema.test.ts +4 -0
- package/src/__tests__/composables/useExperimentData.test.ts +23 -0
- package/src/__tests__/composables/useExperimentSamples.test.ts +91 -0
- package/src/__tests__/composables/useProtocolTemplates.test.ts +64 -0
- package/src/__tests__/stores/settings.test.ts +78 -0
- package/src/__tests__/templates/templates.test.ts +86 -0
- package/src/__tests__/utils/instrument.test.ts +47 -0
- package/src/__tests__/utils/lcms.test.ts +73 -0
- package/src/__tests__/utils/permissions.test.ts +50 -0
- package/src/__tests__/utils/rack.test.ts +120 -0
- package/src/components/AppAvatarMenu.vue +6 -3
- package/src/components/AppTopBar.vue +16 -10
- package/src/components/AuditTrail.vue +1 -1
- package/src/components/BaseTabs.vue +22 -1
- package/src/components/Calendar.vue +6 -2
- package/src/components/ConcentrationInput.vue +3 -2
- package/src/components/GroupAssigner.vue +8 -3
- package/src/components/InstrumentAlertLog.vue +191 -0
- package/src/components/InstrumentStateBadge.vue +50 -0
- package/src/components/InstrumentStatusCard.vue +188 -0
- package/src/components/LcmsSequenceTable.vue +191 -0
- package/src/components/NumberInput.vue +5 -3
- package/src/components/ProgressBar.vue +3 -0
- package/src/components/RackEditor.vue +73 -2
- package/src/components/SampleHierarchyTree.vue +3 -2
- package/src/components/SampleSelector.vue +28 -9
- package/src/components/SegmentedControl.story.vue +17 -0
- package/src/components/SegmentedControl.vue +14 -3
- package/src/components/SequenceProgressBar.vue +71 -0
- package/src/components/SettingsModal.vue +49 -2
- package/src/components/UnitInput.vue +6 -2
- package/src/components/WellPlate.vue +145 -24
- package/src/components/index.ts +5 -0
- package/src/components/internal/WellEditPopupInternal.vue +1 -0
- package/src/composables/experimentDesignData.ts +182 -0
- package/src/composables/index.ts +14 -0
- package/src/composables/useApi.ts +113 -16
- package/src/composables/useAuth.ts +4 -0
- package/src/composables/useAutoGroup.ts +18 -9
- package/src/composables/useControlSchema.ts +21 -0
- package/src/composables/useExperimentData.ts +57 -16
- package/src/composables/useExperimentSamples.ts +142 -0
- package/src/composables/useProtocolTemplates.ts +13 -1
- package/src/composables/useRackEditor.ts +3 -2
- package/src/index.ts +27 -0
- package/src/instrument.ts +90 -0
- package/src/lcms.ts +108 -0
- package/src/permissions.ts +143 -0
- package/src/stores/auth.ts +79 -26
- package/src/stores/settings.ts +10 -0
- package/src/styles/components/instrument-monitor.css +478 -0
- package/src/styles/components/lcms-sequence-table.css +189 -0
- package/src/styles/components/sequence-progress-bar.css +63 -0
- package/src/styles/components/settings-modal.css +9 -0
- package/src/styles/components/tabs.css +9 -0
- package/src/styles/components/well-edit-popup.css +7 -1
- package/src/styles/components/well-plate.css +5 -0
- package/src/styles/index.css +3 -0
- package/src/templates/builders.ts +201 -0
- package/src/templates/controlSchemas.ts +68 -0
- package/src/templates/index.ts +2 -0
- package/src/templates/presets.ts +23 -0
- package/src/templates/types.ts +17 -0
- package/src/types/auth.ts +3 -0
- package/src/types/components.ts +45 -3
- package/src/types/form-builder.ts +2 -1
- package/src/types/index.ts +35 -0
- package/src/types/instrument.ts +61 -0
- package/src/types/platform.ts +4 -0
- package/src/utils/rack.ts +209 -0
- package/dist/auth-QQj2kkze.js.map +0 -1
- package/dist/components-DihbSJjU.js.map +0 -1
- package/dist/composables-BcgZ6diz.js.map +0 -1
- package/dist/templates-Cyt0Suwf.js.map +0 -1
- package/dist/useExperimentData-CM6Y0u5L.js.map +0 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
export const ADMIN_ROLE = 'admin'
|
|
2
|
+
|
|
3
|
+
export const ADMIN_PANEL_PERMISSIONS = [
|
|
4
|
+
'users.view',
|
|
5
|
+
'users.invite',
|
|
6
|
+
'users.manage',
|
|
7
|
+
'platform.configure',
|
|
8
|
+
'platform.view_logs',
|
|
9
|
+
'plugins.configure',
|
|
10
|
+
'plugins.install',
|
|
11
|
+
] as const
|
|
12
|
+
|
|
13
|
+
export type AccessAudience = 'all' | 'admin' | 'user'
|
|
14
|
+
export type AccessAudienceInput = AccessAudience | readonly AccessAudience[]
|
|
15
|
+
|
|
16
|
+
export interface RoleInfo {
|
|
17
|
+
id?: number
|
|
18
|
+
slug: string
|
|
19
|
+
name?: string
|
|
20
|
+
color?: string
|
|
21
|
+
permissions?: readonly string[] | null
|
|
22
|
+
project_scope?: 'all' | 'assigned' | string
|
|
23
|
+
plugin_access?: readonly string[] | 'all' | null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface PermissionUser {
|
|
27
|
+
role?: string | null
|
|
28
|
+
role_obj?: RoleInfo | null
|
|
29
|
+
roleObj?: RoleInfo | null
|
|
30
|
+
permissions?: readonly string[] | null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface AccessPolicy {
|
|
34
|
+
audience?: AccessAudienceInput
|
|
35
|
+
visibleFor?: AccessAudienceInput
|
|
36
|
+
requiresAuth?: boolean
|
|
37
|
+
requiresAdmin?: boolean
|
|
38
|
+
permissions?: readonly string[]
|
|
39
|
+
anyPermissions?: readonly string[]
|
|
40
|
+
plugin?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AccessControlled {
|
|
44
|
+
access?: AccessPolicy
|
|
45
|
+
visibleFor?: AccessAudienceInput
|
|
46
|
+
requiresAdmin?: boolean
|
|
47
|
+
permissions?: readonly string[]
|
|
48
|
+
anyPermissions?: readonly string[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getRoleInfo(user: PermissionUser | null | undefined): RoleInfo | null {
|
|
52
|
+
return user?.roleObj ?? user?.role_obj ?? null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isAdminRole(role: string | null | undefined): boolean {
|
|
56
|
+
return role === ADMIN_ROLE
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function isAdminUser(user: PermissionUser | null | undefined): boolean {
|
|
60
|
+
return isAdminRole(user?.role) || getRoleInfo(user)?.slug === ADMIN_ROLE
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function getAccessAudience(user: PermissionUser | null | undefined): Exclude<AccessAudience, 'all'> {
|
|
64
|
+
return isAdminUser(user) ? 'admin' : 'user'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getUserPermissions(user: PermissionUser | null | undefined): string[] {
|
|
68
|
+
const rolePermissions = getRoleInfo(user)?.permissions
|
|
69
|
+
if (rolePermissions?.length) return [...rolePermissions]
|
|
70
|
+
return [...(user?.permissions ?? [])]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function hasAllPermissions(
|
|
74
|
+
user: PermissionUser | null | undefined,
|
|
75
|
+
permissions: readonly string[] = [],
|
|
76
|
+
): boolean {
|
|
77
|
+
if (permissions.length === 0) return true
|
|
78
|
+
if (isAdminUser(user)) return true
|
|
79
|
+
const granted = new Set(getUserPermissions(user))
|
|
80
|
+
return permissions.every(permission => granted.has(permission))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function hasAnyPermission(
|
|
84
|
+
user: PermissionUser | null | undefined,
|
|
85
|
+
permissions: readonly string[] = [],
|
|
86
|
+
): boolean {
|
|
87
|
+
if (permissions.length === 0) return true
|
|
88
|
+
if (isAdminUser(user)) return true
|
|
89
|
+
const granted = new Set(getUserPermissions(user))
|
|
90
|
+
return permissions.some(permission => granted.has(permission))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function canAccessAdmin(user: PermissionUser | null | undefined): boolean {
|
|
94
|
+
return isAdminUser(user) || hasAnyPermission(user, ADMIN_PANEL_PERMISSIONS)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function canAccessPlugin(
|
|
98
|
+
user: PermissionUser | null | undefined,
|
|
99
|
+
pluginName: string | null | undefined,
|
|
100
|
+
): boolean {
|
|
101
|
+
if (!pluginName) return true
|
|
102
|
+
const access = getRoleInfo(user)?.plugin_access
|
|
103
|
+
if (!access || access === 'all') return true
|
|
104
|
+
return Array.isArray(access) && access.includes(pluginName)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function normalizeAccessPolicy(rule: AccessControlled | AccessPolicy | undefined): AccessPolicy {
|
|
108
|
+
if (!rule) return {}
|
|
109
|
+
const { access: nested, ...direct } = rule as AccessPolicy & { access?: AccessPolicy }
|
|
110
|
+
return {
|
|
111
|
+
...(nested ?? {}),
|
|
112
|
+
...direct,
|
|
113
|
+
...('visibleFor' in rule && rule.visibleFor !== undefined ? { visibleFor: rule.visibleFor } : {}),
|
|
114
|
+
...('requiresAdmin' in rule && rule.requiresAdmin !== undefined ? { requiresAdmin: rule.requiresAdmin } : {}),
|
|
115
|
+
...('permissions' in rule && rule.permissions !== undefined ? { permissions: rule.permissions } : {}),
|
|
116
|
+
...('anyPermissions' in rule && rule.anyPermissions !== undefined ? { anyPermissions: rule.anyPermissions } : {}),
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function canAccessByPolicy(
|
|
121
|
+
user: PermissionUser | null | undefined,
|
|
122
|
+
rule: AccessControlled | AccessPolicy | undefined,
|
|
123
|
+
isAuthenticated = user !== null && user !== undefined,
|
|
124
|
+
): boolean {
|
|
125
|
+
const policy = normalizeAccessPolicy(rule)
|
|
126
|
+
if (policy.requiresAuth && !isAuthenticated) return false
|
|
127
|
+
if (policy.requiresAdmin && !isAdminUser(user)) return false
|
|
128
|
+
if (!audienceAllowsUser(policy.visibleFor ?? policy.audience, user)) return false
|
|
129
|
+
if (!hasAllPermissions(user, policy.permissions)) return false
|
|
130
|
+
if (!hasAnyPermission(user, policy.anyPermissions)) return false
|
|
131
|
+
if (policy.plugin && !canAccessPlugin(user, policy.plugin)) return false
|
|
132
|
+
return true
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function audienceAllowsUser(
|
|
136
|
+
audience: AccessAudienceInput | undefined,
|
|
137
|
+
user: PermissionUser | null | undefined,
|
|
138
|
+
): boolean {
|
|
139
|
+
if (audience === undefined) return true
|
|
140
|
+
const allowed = Array.isArray(audience) ? audience : [audience]
|
|
141
|
+
if (allowed.includes('all')) return true
|
|
142
|
+
return allowed.includes(getAccessAudience(user))
|
|
143
|
+
}
|
package/src/stores/auth.ts
CHANGED
|
@@ -1,11 +1,51 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
2
|
import { ref, computed } from 'vue'
|
|
3
3
|
import type { AuthConfig, UserInfo } from '../types'
|
|
4
|
+
import {
|
|
5
|
+
canAccessAdmin as canUserAccessAdmin,
|
|
6
|
+
canAccessPlugin as canUserAccessPlugin,
|
|
7
|
+
getAccessAudience,
|
|
8
|
+
getUserPermissions,
|
|
9
|
+
hasAllPermissions,
|
|
10
|
+
hasAnyPermission,
|
|
11
|
+
isAdminUser,
|
|
12
|
+
} from '../permissions'
|
|
4
13
|
|
|
5
14
|
const AUTH_TOKEN_KEY = 'mint-auth-token'
|
|
6
15
|
const AUTH_EXPIRES_KEY = 'mint-auth-expires'
|
|
7
16
|
|
|
8
|
-
|
|
17
|
+
function getLocalStorage(): Storage | null {
|
|
18
|
+
try {
|
|
19
|
+
const storage = globalThis.localStorage
|
|
20
|
+
return typeof storage?.getItem === 'function' ? storage : null
|
|
21
|
+
} catch {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readStoredItem(key: string): string | null {
|
|
27
|
+
try {
|
|
28
|
+
return getLocalStorage()?.getItem(key) ?? null
|
|
29
|
+
} catch {
|
|
30
|
+
return null
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function writeStoredItem(key: string, value: string): void {
|
|
35
|
+
try {
|
|
36
|
+
getLocalStorage()?.setItem(key, value)
|
|
37
|
+
} catch {
|
|
38
|
+
// Keep auth usable in-memory when browser storage is blocked.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function removeStoredItem(key: string): void {
|
|
43
|
+
try {
|
|
44
|
+
getLocalStorage()?.removeItem(key)
|
|
45
|
+
} catch {
|
|
46
|
+
// Keep auth cleanup usable in-memory when browser storage is blocked.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
9
49
|
|
|
10
50
|
export const useAuthStore = defineStore('mint-auth', () => {
|
|
11
51
|
// State
|
|
@@ -42,9 +82,10 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
42
82
|
return authConfig.value.authRequired && !isAuthenticated.value
|
|
43
83
|
})
|
|
44
84
|
|
|
45
|
-
const isAdmin = computed(() =>
|
|
46
|
-
|
|
47
|
-
|
|
85
|
+
const isAdmin = computed(() => isAdminUser(userInfo.value))
|
|
86
|
+
const userType = computed(() => getAccessAudience(userInfo.value))
|
|
87
|
+
const permissions = computed(() => getUserPermissions(userInfo.value))
|
|
88
|
+
const canAccessAdmin = computed(() => canUserAccessAdmin(userInfo.value))
|
|
48
89
|
|
|
49
90
|
const canRegister = computed(() => {
|
|
50
91
|
return authConfig.value.registrationEnabled
|
|
@@ -52,20 +93,18 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
52
93
|
|
|
53
94
|
// Actions
|
|
54
95
|
function initialize() {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
clearToken()
|
|
68
|
-
}
|
|
96
|
+
const storedToken = readStoredItem(AUTH_TOKEN_KEY)
|
|
97
|
+
const storedExpires = readStoredItem(AUTH_EXPIRES_KEY)
|
|
98
|
+
|
|
99
|
+
if (storedToken) {
|
|
100
|
+
token.value = storedToken
|
|
101
|
+
|
|
102
|
+
if (storedExpires) {
|
|
103
|
+
const expires = new Date(storedExpires)
|
|
104
|
+
if (expires > new Date()) {
|
|
105
|
+
tokenExpires.value = expires
|
|
106
|
+
} else {
|
|
107
|
+
clearToken()
|
|
69
108
|
}
|
|
70
109
|
}
|
|
71
110
|
}
|
|
@@ -78,10 +117,8 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
78
117
|
const expires = new Date(Date.now() + expiresIn * 1000)
|
|
79
118
|
tokenExpires.value = expires
|
|
80
119
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
localStorage.setItem(AUTH_EXPIRES_KEY, expires.toISOString())
|
|
84
|
-
}
|
|
120
|
+
writeStoredItem(AUTH_TOKEN_KEY, accessToken)
|
|
121
|
+
writeStoredItem(AUTH_EXPIRES_KEY, expires.toISOString())
|
|
85
122
|
}
|
|
86
123
|
|
|
87
124
|
function clearToken() {
|
|
@@ -90,10 +127,8 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
90
127
|
username.value = null
|
|
91
128
|
userInfo.value = null
|
|
92
129
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
localStorage.removeItem(AUTH_EXPIRES_KEY)
|
|
96
|
-
}
|
|
130
|
+
removeStoredItem(AUTH_TOKEN_KEY)
|
|
131
|
+
removeStoredItem(AUTH_EXPIRES_KEY)
|
|
97
132
|
}
|
|
98
133
|
|
|
99
134
|
function setUserInfo(info: UserInfo) {
|
|
@@ -101,6 +136,18 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
101
136
|
username.value = info.username
|
|
102
137
|
}
|
|
103
138
|
|
|
139
|
+
function hasPermission(...perms: string[]): boolean {
|
|
140
|
+
return hasAllPermissions(userInfo.value, perms)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function hasAnyPermissionForUser(...perms: string[]): boolean {
|
|
144
|
+
return hasAnyPermission(userInfo.value, perms)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function canAccessPlugin(pluginName: string): boolean {
|
|
148
|
+
return canUserAccessPlugin(userInfo.value, pluginName)
|
|
149
|
+
}
|
|
150
|
+
|
|
104
151
|
function setAuthConfig(config: AuthConfig) {
|
|
105
152
|
authConfig.value = config
|
|
106
153
|
}
|
|
@@ -136,6 +183,9 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
136
183
|
isAuthenticated,
|
|
137
184
|
needsAuth,
|
|
138
185
|
isAdmin,
|
|
186
|
+
userType,
|
|
187
|
+
permissions,
|
|
188
|
+
canAccessAdmin,
|
|
139
189
|
canRegister,
|
|
140
190
|
|
|
141
191
|
// Actions
|
|
@@ -147,6 +197,9 @@ export const useAuthStore = defineStore('mint-auth', () => {
|
|
|
147
197
|
setUserInfo,
|
|
148
198
|
setError,
|
|
149
199
|
setLoading,
|
|
200
|
+
hasPermission,
|
|
201
|
+
hasAnyPermission: hasAnyPermissionForUser,
|
|
202
|
+
canAccessPlugin,
|
|
150
203
|
logout,
|
|
151
204
|
}
|
|
152
205
|
})
|
package/src/stores/settings.ts
CHANGED
|
@@ -24,6 +24,7 @@ export interface SettingsState {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const STORAGE_KEY = 'mint-settings'
|
|
27
|
+
const LEGACY_STORAGE_KEY = 'mld-settings'
|
|
27
28
|
|
|
28
29
|
function getDefaultServerHost(): string {
|
|
29
30
|
if (typeof window !== 'undefined' && window.location.hostname !== 'localhost') {
|
|
@@ -68,6 +69,15 @@ function loadSettings(): SettingsState {
|
|
|
68
69
|
const parsed = JSON.parse(stored)
|
|
69
70
|
return { ...defaultSettings, ...parsed }
|
|
70
71
|
}
|
|
72
|
+
|
|
73
|
+
const legacyStored = localStorage.getItem(LEGACY_STORAGE_KEY)
|
|
74
|
+
if (legacyStored) {
|
|
75
|
+
const parsed = JSON.parse(legacyStored)
|
|
76
|
+
const migrated = { ...defaultSettings, ...parsed }
|
|
77
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(migrated))
|
|
78
|
+
localStorage.removeItem(LEGACY_STORAGE_KEY)
|
|
79
|
+
return migrated
|
|
80
|
+
}
|
|
71
81
|
} catch (e) {
|
|
72
82
|
console.warn('Failed to load settings from localStorage:', e)
|
|
73
83
|
}
|