core&ui: cache uicontext.domain

This commit is contained in:
undefined committed 2026-06-18 12:59:55 +00:00
1 parent 43fb00e3c7
commit e39a5fa87f
8 files changed
+71 -10

No files matched your search

@@ -17,7 +17,7 @@ const page = new NamedPage('domain_user', () => {
<p>${i18n('Users will have to manually join the domain first before selected roles can be applied.')}</p>
<p>${i18n('To join the domain, users can click the "Join Domain" button on "My Domain" page.')}</p>
<p>${i18n('Or use the following link:')}</p>
<p><a href="/domain/join?target=${UiContext.domain._id}">/domain/join?target=${UiContext.domain._id}</a></p>
<p><a href="/domain/join?target=${UiContext.domainId}">/domain/join?target=${UiContext.domainId}</a></p>
</div>`,
}).open();
});
@@ -37,7 +37,7 @@ const page = new NamedPage('domain_user', () => {
label: 'Role',
options: UiContext.roles.filter((i) => !['default', 'guest'].includes(i)),
},
...((UiContext.canForceJoin && UiContext.domain._id !== 'system') ? {
...((UiContext.canForceJoin && UiContext.domainId !== 'system') ? {
join: {
type: 'checkbox',
label: i18n('Mark user as joined using admin privilege'),
@@ -3,7 +3,9 @@ import ProblemSelectAutoComplete from 'vj/components/autocomplete/ProblemSelectA
import UserSelectAutoComplete from 'vj/components/autocomplete/UserSelectAutoComplete';
import Notification from 'vj/components/notification';
import { NamedPage } from 'vj/misc/Page';
import { getAvailableLangs, request, tpl } from 'vj/utils';
import {
getAvailableLangs, getDomainInfo, request, tpl,
} from 'vj/utils';
const page = new NamedPage('record_main', async () => {
const [{ default: WebSocket }, { DiffDOM }] = await Promise.all([
@@ -37,7 +39,8 @@ const page = new NamedPage('record_main', async () => {
ProblemSelectAutoComplete.getOrConstruct($('[name="pid"]'), {
clearDefaultValue: false,
});
const langs = UiContext.domain.langs?.split(',').map((i) => i.trim()).filter((i) => i);
const domain = await getDomainInfo();
const langs = domain.langs?.split(',').map((i) => i.trim()).filter((i) => i);
const availableLangs = getAvailableLangs(langs?.length ? langs : undefined);
Object.keys(availableLangs).map(
(i) => ($('select[name="lang"]').append(tpl`<option value="${i}" key="${i}">${availableLangs[i].display}</option>`)));
@@ -35,7 +35,7 @@
{% else %}
{% if model.system.get('ui-default.domainNavigation') %}
<li class="nav__list-item" data-dropdown-pos="bottom right" data-dropdown-custom-class="nav__dropdown" data-dropdown-target="#menu-nav-domain" data-dropdown-disabledconstrainToWindow data-dropdown-trigger-desktop-only>
<span class="nav__item"><span class="icon"><img class="small user-profile-avatar v-center" loading="lazy" src="{{ avatarUrl(UiContext.domain.avatar|default('')) }}" width="20" height="20"></span> {{ UiContext.domain.name }} <span class="icon icon-expand_more nojs--hide"></span></span>
<span class="nav__item"><span class="icon"><img class="small user-profile-avatar v-center" loading="lazy" src="{{ avatarUrl(handler.domain.avatar|default('')) }}" width="20" height="20"></span> {{ handler.domain.name }} <span class="icon icon-expand_more nojs--hide"></span></span>
<ol class="dropdown-target menu" id="menu-nav-domain">
{%- if handler.user.domains|length -%}
{%- for ddoc in handler.user.domains -%}
+2 -1
View File
@@ -1,7 +1,7 @@
import { openDB as _open } from 'idb';
import { alert } from 'vj/components/dialog';
export const openDB = _open('hydro', 1, {
export const openDB = _open('hydro', 2, {
upgrade(db, oldVersion) {
if (oldVersion < 1) {
const solutionStore = db.createObjectStore('solutions', { keyPath: 'id' });
@@ -17,6 +17,7 @@ export const openDB = _open('hydro', 1, {
if (/^0\.\d+$/.test(key)) localStorage.removeItem(key);
}
}
if (oldVersion < 2) db.createObjectStore('domain-info', { keyPath: 'id' });
},
blocked(currentVersion, blockedVersion) {
console.error('IDB Blocked by version', blockedVersion, 'want', currentVersion);
+40 -1
View File
@@ -1,13 +1,52 @@
import 'streamsaver/examples/zip-stream';
import { request } from './base';
import { openDB } from './db';
export async function api(method: string, args: Record<string, any>, projection: any) {
export async function api(method: string, args: Record<string, any>, projection?: any) {
const res = await request.post(`/d/${UiContext.domainId}/api/${encodeURIComponent(method)}`, { args, projection });
if (res.error) throw new Error(res.error);
return res;
}
interface DomainInfoCache {
id: string;
version: number;
domain: Record<string, any>;
}
const domainInfoCacheStore = 'domain-info';
let domainInfoPromise: Promise<Record<string, any>> | null = null;
async function readDomainInfoCache(domainId: string) {
return await (await openDB).get(domainInfoCacheStore, domainId) as DomainInfoCache | null;
}
async function writeDomainInfoCache(cache: DomainInfoCache) {
await (await openDB).put(domainInfoCacheStore, cache);
}
async function loadDomainInfo() {
let cached: DomainInfoCache | null = null;
try {
cached = await readDomainInfoCache(UiContext.domainId);
} catch (e) { }
if (cached && cached.version >= UiContext.domainVersion) return cached.domain;
const res = await api('domain.current', {});
const { domain } = res;
if (!domain) throw new Error('Failed to load domain info');
writeDomainInfoCache({ id: UiContext.domainId, version: UiContext.domainVersion, domain }).catch(() => { });
return domain;
}
export function getDomainInfo() {
domainInfoPromise ||= loadDomainInfo().catch((e) => {
domainInfoPromise = null;
throw e;
});
return domainInfoPromise;
}
export function getAvailableLangs(langsList?: string[]) {
const prefixes = new Set(Object.keys(window.LANGS).filter((i) => i.includes('.')).map((i) => i.split('.')[0]));
const Langs = {};