557 lines
16 KiB
TypeScript
557 lines
16 KiB
TypeScript
import { apiRequest } from '../../lib/api';
|
|
|
|
export type PageParams = {
|
|
page?: number;
|
|
limit?: number;
|
|
keyword?: string;
|
|
[key: string]: string | number | undefined;
|
|
};
|
|
|
|
export type PagedResponse<T> = {
|
|
items: T[];
|
|
total: number;
|
|
page: number;
|
|
limit: number;
|
|
};
|
|
|
|
function pageQuery(params?: PageParams) {
|
|
const searchParams = new URLSearchParams();
|
|
Object.entries(params ?? {}).forEach(([key, value]) => {
|
|
if (value !== undefined && value !== '') searchParams.set(key, String(value));
|
|
});
|
|
const query = searchParams.toString();
|
|
return query ? `?${query}` : '';
|
|
}
|
|
|
|
export type AdminSession = {
|
|
id?: string;
|
|
revokedAt?: string | null;
|
|
};
|
|
|
|
export type AdminSshKey = {
|
|
id: string;
|
|
label?: string | null;
|
|
fingerprint?: string | null;
|
|
};
|
|
|
|
export type AdminAccount = {
|
|
id: string;
|
|
no?: number;
|
|
email: string;
|
|
name: string;
|
|
avatarUrl?: string | null;
|
|
role: 'OWNER' | 'ADMIN' | 'OPERATOR' | 'VIEWER' | string;
|
|
isActive: boolean;
|
|
lastLoginAt?: string | null;
|
|
sessions?: AdminSession[];
|
|
sshKeys?: AdminSshKey[];
|
|
appPermissions?: string[];
|
|
};
|
|
|
|
export type AdminRoleOption = {
|
|
id: string;
|
|
code: string;
|
|
name: string;
|
|
description?: string | null;
|
|
sortOrder: number;
|
|
isActive: boolean;
|
|
};
|
|
|
|
export type UserSession = {
|
|
id: string;
|
|
no?: number;
|
|
userId: string;
|
|
sessionId?: string | null;
|
|
user: string;
|
|
email?: string;
|
|
avatarUrl?: string | null;
|
|
role: string;
|
|
session: string;
|
|
expiresAt?: string | null;
|
|
lastSeen?: string | null;
|
|
state: string;
|
|
primaryAffiliation?: {
|
|
id: string;
|
|
organizationId: string;
|
|
organizationName: string;
|
|
organizationType: string;
|
|
department?: string | null;
|
|
position?: string | null;
|
|
} | null;
|
|
};
|
|
|
|
export type OrganizationType = 'COMPANY' | 'SCHOOL' | 'GOVERNMENT' | 'LAB' | 'OTHER' | string;
|
|
|
|
export type Organization = {
|
|
id: string;
|
|
no?: number;
|
|
name: string;
|
|
type: OrganizationType;
|
|
domain?: string | null;
|
|
defaultLicenseCode?: string | null;
|
|
defaultLicenseName?: string | null;
|
|
createdAt: string;
|
|
};
|
|
|
|
export type LauncherNotice = {
|
|
id: string;
|
|
no?: number;
|
|
appKey: string;
|
|
title: string;
|
|
body: string;
|
|
linkUrl?: string | null;
|
|
isActive: boolean;
|
|
startsAt?: string | null;
|
|
endsAt?: string | null;
|
|
priority: number;
|
|
status?: string;
|
|
createdByName?: string | null;
|
|
createdByEmail?: string | null;
|
|
createdByAvatarUrl?: string | null;
|
|
createdAt: string;
|
|
updatedAt?: string;
|
|
};
|
|
|
|
export type LauncherTerm = {
|
|
id: string;
|
|
no?: number;
|
|
key: string;
|
|
body: string;
|
|
isRequired: boolean;
|
|
createdById?: string | null;
|
|
createdByName?: string | null;
|
|
createdByEmail?: string | null;
|
|
createdByAvatarUrl?: string | null;
|
|
createdAt: string;
|
|
updatedAt?: string;
|
|
};
|
|
|
|
export async function loadAdminsPage(params?: PageParams & { role?: string; state?: string }): Promise<PagedResponse<AdminAccount>> {
|
|
type RawAdminAccount = Omit<AdminAccount, 'appPermissions'> & {
|
|
appPermissions?: Array<string | { appId: string }>;
|
|
};
|
|
const response = await apiRequest<RawAdminAccount[] | { admins?: RawAdminAccount[]; total?: number; page?: number; limit?: number }>(`/admins${pageQuery(params)}`);
|
|
const admins = Array.isArray(response) ? response : response.admins ?? [];
|
|
const items = admins.map((admin) => ({
|
|
...admin,
|
|
appPermissions: (admin.appPermissions ?? []).map((permission) => (
|
|
typeof permission === 'string' ? permission : permission.appId
|
|
))
|
|
}));
|
|
if (Array.isArray(response)) return { items, total: items.length, page: params?.page ?? 1, limit: params?.limit ?? items.length };
|
|
return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length };
|
|
}
|
|
|
|
export async function loadAdmins() {
|
|
return (await loadAdminsPage({ limit: 1000 })).items;
|
|
}
|
|
|
|
export function loadAdminRoles() {
|
|
return apiRequest<AdminRoleOption[]>('/admins/roles');
|
|
}
|
|
|
|
export function createAdmin(payload: {
|
|
email: string;
|
|
name: string;
|
|
role: string;
|
|
temporaryPassword?: string;
|
|
}) {
|
|
return apiRequest('/admins', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function updateAdminStatus(adminId: string, isActive: boolean) {
|
|
return apiRequest(`/admins/${adminId}/status`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify({ isActive })
|
|
});
|
|
}
|
|
|
|
export function updateAdminRole(adminId: string, role: string) {
|
|
return apiRequest(`/admins/${adminId}/role`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify({ role })
|
|
});
|
|
}
|
|
|
|
export function resetAdminPassword(adminId: string, temporaryPassword: string) {
|
|
return apiRequest(`/admins/${adminId}/password`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify({ temporaryPassword })
|
|
});
|
|
}
|
|
|
|
export function createAdminSshKey(
|
|
adminId: string,
|
|
payload: { label?: string; publicKey: string }
|
|
) {
|
|
return apiRequest(`/admins/${adminId}/ssh-keys`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function deleteAdminSshKey(adminId: string, keyId: string) {
|
|
return apiRequest(`/admins/${adminId}/ssh-keys/${keyId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
}
|
|
|
|
export async function loadAdminAppPermissions(adminId: string) {
|
|
const response = await apiRequest<{ appIds?: string[] }>(`/admins/${adminId}/app-permissions`);
|
|
return response.appIds ?? [];
|
|
}
|
|
|
|
export function updateAdminAppPermissions(adminId: string, appIds: string[]) {
|
|
return apiRequest<{ appIds?: string[] }>(`/admins/${adminId}/app-permissions`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify({ appIds })
|
|
});
|
|
}
|
|
|
|
export async function loadUserSessionsPage(params?: PageParams & { state?: string }): Promise<PagedResponse<UserSession>> {
|
|
const response = await apiRequest<{ sessions?: UserSession[]; total?: number; page?: number; limit?: number }>(`/users/sessions${pageQuery(params)}`);
|
|
const items = (response.sessions ?? []).map((session) => ({
|
|
...session,
|
|
session: session.sessionId ? session.session : '-',
|
|
state: session.state
|
|
}));
|
|
return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length };
|
|
}
|
|
|
|
export async function loadUserSessions() {
|
|
return (await loadUserSessionsPage({ limit: 1000 })).items;
|
|
}
|
|
|
|
export function lockUser(userId: string) {
|
|
return apiRequest(`/users/${userId}/lock`, {
|
|
method: 'PATCH'
|
|
});
|
|
}
|
|
|
|
export function unlockUser(userId: string) {
|
|
return apiRequest(`/users/${userId}/unlock`, {
|
|
method: 'PATCH'
|
|
});
|
|
}
|
|
|
|
export function terminateUserSession(sessionId: string) {
|
|
return apiRequest(`/users/sessions/${sessionId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
}
|
|
|
|
export function createManagedUser(payload: {
|
|
email: string;
|
|
password: string;
|
|
name: string;
|
|
organizationId?: string | null;
|
|
department?: string | null;
|
|
position?: string | null;
|
|
licenseCode?: 'FREE' | 'EDU' | 'PRO';
|
|
}) {
|
|
return apiRequest<{ user: { id: string; email: string; name?: string | null } }>('/users', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function loadOrganizationsPage(params?: PageParams & { type?: string }): Promise<PagedResponse<Organization>> {
|
|
const response = await apiRequest<{ organizations?: Organization[]; total?: number; page?: number; limit?: number }>(`/organizations${pageQuery(params)}`);
|
|
const items = response.organizations ?? [];
|
|
return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length };
|
|
}
|
|
|
|
export async function loadOrganizations() {
|
|
return (await loadOrganizationsPage({ limit: 1000 })).items;
|
|
}
|
|
|
|
export function createOrganization(payload: { name: string; type: OrganizationType; domain?: string | null }) {
|
|
return apiRequest<{ organization: Organization }>('/organizations', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function updateOrganization(organizationId: string, payload: { name?: string; type?: OrganizationType; domain?: string | null }) {
|
|
return apiRequest<{ organization: Organization }>(`/organizations/${organizationId}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function deleteOrganization(organizationId: string) {
|
|
return apiRequest<{ ok: boolean }>(`/organizations/${organizationId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
}
|
|
|
|
export function updateOrganizationLicense(organizationId: string, licenseCode: string | null) {
|
|
return apiRequest<{ organization: Organization; updatedUserCount: number }>(`/organizations/${organizationId}/license`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify({ licenseCode })
|
|
});
|
|
}
|
|
|
|
export async function loadLauncherNoticesPage(params?: PageParams & { appKey?: string }): Promise<PagedResponse<LauncherNotice>> {
|
|
const response = await apiRequest<{ notices?: LauncherNotice[]; total?: number; page?: number; limit?: number }>(`/notices${pageQuery(params)}`);
|
|
const items = response.notices ?? [];
|
|
return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length };
|
|
}
|
|
|
|
export async function loadLauncherNotices() {
|
|
return (await loadLauncherNoticesPage({ limit: 1000 })).items;
|
|
}
|
|
|
|
export function createLauncherNotice(payload: {
|
|
appKey: string;
|
|
title: string;
|
|
body: string;
|
|
linkUrl?: string;
|
|
isActive?: boolean;
|
|
startsAt?: string;
|
|
endsAt?: string;
|
|
priority?: number;
|
|
}) {
|
|
return apiRequest<{ notice: LauncherNotice }>('/notices', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function updateLauncherNotice(
|
|
noticeId: string,
|
|
payload: Partial<{
|
|
appKey: string;
|
|
title: string;
|
|
body: string;
|
|
linkUrl: string;
|
|
isActive: boolean;
|
|
startsAt: string;
|
|
endsAt: string;
|
|
priority: number;
|
|
}>
|
|
) {
|
|
return apiRequest<{ notice: LauncherNotice }>(`/notices/${noticeId}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function deleteLauncherNotice(noticeId: string) {
|
|
return apiRequest<{ ok: boolean }>(`/notices/${noticeId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
}
|
|
|
|
export async function loadTermsPage(params?: PageParams & { key?: string }): Promise<PagedResponse<LauncherTerm>> {
|
|
const response = await apiRequest<{ terms?: LauncherTerm[]; total?: number; page?: number; limit?: number }>(`/terms${pageQuery(params)}`);
|
|
const items = response.terms ?? [];
|
|
return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length };
|
|
}
|
|
|
|
export function createTerm(payload: {
|
|
key: string;
|
|
body: string;
|
|
isRequired?: boolean;
|
|
}) {
|
|
return apiRequest<{ term: LauncherTerm }>('/terms', {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function updateTerm(
|
|
termId: string,
|
|
payload: Partial<{
|
|
key: string;
|
|
body: string;
|
|
isRequired: boolean;
|
|
}>
|
|
) {
|
|
return apiRequest<{ term: LauncherTerm }>(`/terms/${termId}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function deleteTerm(termId: string) {
|
|
return apiRequest<{ ok: boolean }>(`/terms/${termId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
}
|
|
|
|
export type LicensePlan = {
|
|
id: string;
|
|
code: string;
|
|
name: string;
|
|
description?: string | null;
|
|
defaultDurationDays?: number | null;
|
|
isActive: boolean;
|
|
assignedCount: number;
|
|
activeUserCount: number;
|
|
expiringSoonCount: number;
|
|
createdAt?: string;
|
|
updatedAt?: string;
|
|
};
|
|
|
|
export type AuthUserLicense = {
|
|
id: string;
|
|
userId: string;
|
|
licenseId: string;
|
|
startsAt: string;
|
|
expiresAt?: string | null;
|
|
assignedById?: string | null;
|
|
license: {
|
|
id: string;
|
|
code: string;
|
|
name: string;
|
|
description?: string | null;
|
|
};
|
|
status: string;
|
|
};
|
|
|
|
export type AuthLicenseUser = {
|
|
id: string;
|
|
email: string;
|
|
name: string;
|
|
role: string;
|
|
isActive: boolean;
|
|
currentLicense?: AuthUserLicense | null;
|
|
licenses: AuthUserLicense[];
|
|
};
|
|
|
|
export async function loadLicensePlans() {
|
|
const response = await apiRequest<{ plans?: LicensePlan[] }>('/licenses/plans');
|
|
return response.plans ?? [];
|
|
}
|
|
|
|
export function updateLicensePlan(licenseCode: string, payload: {
|
|
name?: string;
|
|
description?: string | null;
|
|
defaultDurationDays?: number | null;
|
|
isActive?: boolean;
|
|
permissions?: Array<{ appKey: string; canLaunch: boolean }>;
|
|
}) {
|
|
return apiRequest<{ plan: LicensePlan; updatedUserCount?: number }>(`/licenses/plans/${encodeURIComponent(licenseCode)}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export async function loadLicenseUsers(params?: { keyword?: string; licenseCode?: string }) {
|
|
const searchParams = new URLSearchParams();
|
|
if (params?.keyword) searchParams.set('keyword', params.keyword);
|
|
if (params?.licenseCode) searchParams.set('licenseCode', params.licenseCode);
|
|
const suffix = searchParams.toString() ? `?${searchParams.toString()}` : '';
|
|
const response = await apiRequest<{ users?: AuthLicenseUser[] }>(`/licenses/users${suffix}`);
|
|
return response.users ?? [];
|
|
}
|
|
|
|
export async function loadLicenseAssignments(params?: PageParams & { licenseCode?: string; status?: string }): Promise<PagedResponse<LicenseAssignment>> {
|
|
const response = await apiRequest<{ assignments?: LicenseAssignment[]; total?: number; page?: number; limit?: number }>(`/licenses/assignments${pageQuery(params)}`);
|
|
const items = response.assignments ?? [];
|
|
return { items, total: response.total ?? items.length, page: response.page ?? params?.page ?? 1, limit: response.limit ?? params?.limit ?? items.length };
|
|
}
|
|
|
|
export type LicenseAssignment = {
|
|
id: string;
|
|
no?: number;
|
|
userId: string;
|
|
user: string;
|
|
name: string;
|
|
role: string;
|
|
code: string;
|
|
licenseName: string;
|
|
startsAt: string;
|
|
expiresAt?: string | null;
|
|
assignedBy?: string | null;
|
|
status: string;
|
|
};
|
|
|
|
export function assignUserLicense(userId: string, payload: {
|
|
licenseCode: string;
|
|
startsAt?: string;
|
|
expiresAt?: string;
|
|
}) {
|
|
return apiRequest<{ userLicense: AuthUserLicense }>(`/licenses/users/${userId}`, {
|
|
method: 'POST',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function updateUserLicense(userLicenseId: string, payload: {
|
|
licenseCode: string;
|
|
startsAt?: string;
|
|
expiresAt?: string;
|
|
}) {
|
|
return apiRequest<{ userLicense: AuthUserLicense }>(`/licenses/user-licenses/${userLicenseId}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify(payload)
|
|
});
|
|
}
|
|
|
|
export function revokeUserLicense(userLicenseId: string) {
|
|
return apiRequest<{ ok: boolean }>(`/licenses/user-licenses/${userLicenseId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
}
|
|
|
|
export type LauncherUserAppPermission = {
|
|
appId: string;
|
|
appKey: string;
|
|
displayName: string;
|
|
description?: string | null;
|
|
sortOrder: number;
|
|
isEnabled: boolean;
|
|
permissionId?: string | null;
|
|
canView: boolean;
|
|
canLaunch: boolean;
|
|
assignedAt?: string | null;
|
|
};
|
|
|
|
export type LicenseAppPermission = {
|
|
appId: string;
|
|
appKey: string;
|
|
displayName: string;
|
|
description?: string | null;
|
|
sortOrder: number;
|
|
isEnabled: boolean;
|
|
policyId?: string | null;
|
|
canView: boolean;
|
|
canLaunch: boolean;
|
|
};
|
|
|
|
export async function loadLicenseAppPermissions(licenseCode: string) {
|
|
const response = await apiRequest<{ permissions?: LicenseAppPermission[] }>(`/licenses/plans/${encodeURIComponent(licenseCode)}/app-permissions`);
|
|
return response.permissions ?? [];
|
|
}
|
|
|
|
export function updateLicenseAppPermissions(licenseCode: string, permissions: Array<{
|
|
appKey: string;
|
|
canLaunch: boolean;
|
|
}>) {
|
|
return apiRequest<{ permissions?: LicenseAppPermission[]; updatedUserCount?: number }>(`/licenses/plans/${encodeURIComponent(licenseCode)}/app-permissions`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify({ permissions })
|
|
});
|
|
}
|
|
|
|
export async function loadLauncherUserAppPermissions(userId: string) {
|
|
const response = await apiRequest<{ permissions?: LauncherUserAppPermission[] }>(`/launcher/users/${userId}/app-permissions`);
|
|
return response.permissions ?? [];
|
|
}
|
|
|
|
export function updateLauncherUserAppPermissions(userId: string, permissions: Array<{
|
|
appKey: string;
|
|
canView: boolean;
|
|
canLaunch: boolean;
|
|
}>) {
|
|
return apiRequest<{ permissions?: LauncherUserAppPermission[] }>(`/launcher/users/${userId}/app-permissions`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify({ permissions })
|
|
});
|
|
}
|