feat(app-switcher): централизовать ссылки приложений в portal settings
Build and Push Auth Portal Docker Image / build-and-push (push) Successful in 1m49s
Build and Push Auth Portal Docker Image / create-release (push) Skipped

Публичный GET и admin PUT/UI /admin/apps; каталог и chrome читают URL из store.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-07-18 20:59:01 +07:00
co-authored by Cursor
parent 83bfc0355d
commit 0fa4b7adea
18 changed files with 662 additions and 46 deletions
+7
View File
@@ -60,6 +60,12 @@ export function migrateSchema(sqlite: Sqlite): void {
created_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS portal_settings (
id TEXT PRIMARY KEY NOT NULL,
app_switcher_json TEXT,
updated_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_user_apps_user ON user_apps(user_id);
CREATE INDEX IF NOT EXISTS idx_user_permissions_user ON user_permissions(user_id);
CREATE INDEX IF NOT EXISTS idx_refresh_sessions_user ON refresh_sessions(user_id);
@@ -72,3 +78,4 @@ export function healthCheck(sqlite: Sqlite): void {
export * from './schema/index.js'
export * from './users.js'
export * from './settings.js'
+7
View File
@@ -35,3 +35,10 @@ export const refreshSessions = sqliteTable('refresh_sessions', {
revokedAt: text('revoked_at'),
createdAt: text('created_at').notNull(),
})
/** Singleton row id = 'main' */
export const portalSettings = sqliteTable('portal_settings', {
id: text('id').primaryKey(),
appSwitcherJson: text('app_switcher_json'),
updatedAt: text('updated_at').notNull(),
})
+54
View File
@@ -0,0 +1,54 @@
import { eq } from 'drizzle-orm'
import {
defaultAppSwitcherConfig,
normalizeAppSwitcherConfig,
parseAppSwitcherConfig,
type AppSwitcherConfig,
} from '@authportal/shared'
import type { AppDb } from './index.js'
import { portalSettings } from './schema/index.js'
const SETTINGS_ID = 'main'
export function getAppSwitcherConfig(db: AppDb): AppSwitcherConfig {
const row = db
.select()
.from(portalSettings)
.where(eq(portalSettings.id, SETTINGS_ID))
.get()
if (!row?.appSwitcherJson) return defaultAppSwitcherConfig()
try {
return parseAppSwitcherConfig(JSON.parse(row.appSwitcherJson))
} catch {
return defaultAppSwitcherConfig()
}
}
export function setAppSwitcherConfig(
db: AppDb,
config: AppSwitcherConfig,
): AppSwitcherConfig {
const normalized = normalizeAppSwitcherConfig(config)
const now = new Date().toISOString()
const json = JSON.stringify(normalized)
const existing = db
.select()
.from(portalSettings)
.where(eq(portalSettings.id, SETTINGS_ID))
.get()
if (existing) {
db.update(portalSettings)
.set({ appSwitcherJson: json, updatedAt: now })
.where(eq(portalSettings.id, SETTINGS_ID))
.run()
} else {
db.insert(portalSettings)
.values({
id: SETTINGS_ID,
appSwitcherJson: json,
updatedAt: now,
})
.run()
}
return normalized
}