feat: Add rename calls and slug preview to the HQ client
This commit is contained in:
@@ -129,6 +129,7 @@ export interface Instance {
|
||||
status: InstanceStatus;
|
||||
current_license?: string;
|
||||
relink_count: number;
|
||||
renamed_at?: string;
|
||||
inject_failed_at?: string | null;
|
||||
notices_sent?: string[];
|
||||
created_at: string;
|
||||
@@ -288,6 +289,14 @@ export interface StaffInstanceResponse {
|
||||
injection: { applicable: boolean; state?: InjectionState; failed_at?: string | null };
|
||||
}
|
||||
|
||||
export interface RenameResult {
|
||||
instance_id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
/** Empty when APP_LOGIN_URL is unset on the server. */
|
||||
login_url?: string;
|
||||
}
|
||||
|
||||
// --- calls ---------------------------------------------------------------
|
||||
|
||||
export const api = {
|
||||
@@ -306,6 +315,8 @@ export const api = {
|
||||
post<Instance>("/api/instances/link", { instance_id, name }),
|
||||
createInstance: (name: string) => post<Instance>("/api/instances", { name }),
|
||||
renewInstance: (id: string) => post<License>(`/api/instances/${id}/renew`, {}),
|
||||
renameInstance: (id: string, name: string) =>
|
||||
put<RenameResult>(`/api/instances/${id}/name`, { name }),
|
||||
// Self-hosted Free: issue the licence on an already-linked instance.
|
||||
claimFree: (id: string) => post<License>(`/api/instances/${id}/claim-free`, {}),
|
||||
relink: (id: string, instance_id: string) =>
|
||||
@@ -367,6 +378,8 @@ export const api = {
|
||||
post<License>(`/api/staff/instances/${id}/issue`, payload),
|
||||
relink: (id: string, instance_id: string) =>
|
||||
post<License>(`/api/staff/instances/${id}/relink`, { instance_id }),
|
||||
renameInstance: (id: string, name: string) =>
|
||||
put<RenameResult>(`/api/staff/instances/${id}/name`, { name }),
|
||||
licenses: (params?: Record<string, string>) =>
|
||||
req<License[]>(`/api/staff/licenses${params ? `?${new URLSearchParams(params)}` : ""}`),
|
||||
plans: () => req<Plan[]>("/api/staff/plans"),
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* A TypeScript mirror of shared/provision's slug rules, used ONLY to preview the
|
||||
* host a rename would move an instance to while the customer types.
|
||||
*
|
||||
* It is a second implementation of Slugify, BaseSlug and ReservedSlugs, and it
|
||||
* must change in the same commit as the Go one — the same hazard as
|
||||
* web/lib/targets.ts. The preview is a courtesy; the server's 409 is the
|
||||
* boundary, and the two are allowed to disagree without anything breaking.
|
||||
*/
|
||||
|
||||
/** Mirrors provision.MinSlugLength / MaxSlugLength. */
|
||||
export const MIN_SLUG_LENGTH = 3;
|
||||
export const MAX_SLUG_LENGTH = 40;
|
||||
|
||||
/** Mirrors provision.ReservedSlugs. */
|
||||
const RESERVED = new Set([
|
||||
"www", "api", "app", "admin", "auth",
|
||||
"install", "static", "_next", "default",
|
||||
]);
|
||||
|
||||
/*
|
||||
* The tenant subdomain namespace. Also hardcoded in InstanceRecord.tsx and the
|
||||
* customer instance page; those predate this file and are left alone rather than
|
||||
* refactored under a rename change.
|
||||
*/
|
||||
export const INSTANCE_DOMAIN = "vantage.hostxtra.co.uk";
|
||||
|
||||
/** Mirrors provision.Slugify. */
|
||||
export function slugify(name: string): string {
|
||||
return name
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, "-")
|
||||
.replace(/^-+|-+$/g, "");
|
||||
}
|
||||
|
||||
/** Mirrors provision.BaseSlug's truncation. */
|
||||
export function baseSlug(name: string): string {
|
||||
return slugify(name).slice(0, MAX_SLUG_LENGTH);
|
||||
}
|
||||
|
||||
/** The reason a name cannot become a slug, or undefined when it can. */
|
||||
export function slugError(name: string): string | undefined {
|
||||
const base = slugify(name);
|
||||
if (base.length < MIN_SLUG_LENGTH) {
|
||||
return `Needs at least ${MIN_SLUG_LENGTH} letters or digits.`;
|
||||
}
|
||||
if (RESERVED.has(base.slice(0, MAX_SLUG_LENGTH))) {
|
||||
return "That name is reserved.";
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** The host an instance on this slug is reached at. */
|
||||
export function hostFor(slug: string): string {
|
||||
return `${slug}.${INSTANCE_DOMAIN}`;
|
||||
}
|
||||
Reference in New Issue
Block a user