ankka-console 0.12.0 → 0.14.0
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/dist/ankka-mark.png +0 -0
- package/dist/client/schemas.d.ts +205 -1
- package/dist/client/schemas.js +63 -1
- package/dist/routes/front.d.ts +29 -1
- package/dist/routes/front.js +14 -2
- package/dist/routes/logs.d.ts +10 -0
- package/dist/routes/project.d.ts +10 -0
- package/dist/routes/service-history.js +1 -1
- package/dist/routes/service-topology.d.ts +10 -0
- package/dist/routes/service.d.ts +10 -0
- package/dist/routes/service.js +2 -1
- package/dist/styles.css +1 -1
- package/dist/testing/fake-control-plane.d.ts +14 -0
- package/dist/testing/fake-control-plane.js +25 -0
- package/dist/ui/buckets.d.ts +14 -0
- package/dist/ui/buckets.js +9 -0
- package/dist/ui/shell.js +5 -1
- package/dist/ui/topology/Graph.js +2 -2
- package/dist/ui/topology/Table.d.ts +8 -0
- package/dist/ui/topology/Table.js +8 -1
- package/dist/ui/use-stream.d.ts +20 -0
- package/package.json +10 -10
|
Binary file
|
package/dist/client/schemas.d.ts
CHANGED
|
@@ -68,9 +68,69 @@ export declare const installationSecretsSchema: z.ZodObject<{
|
|
|
68
68
|
auditLog: z.ZodDefault<z.ZodString>;
|
|
69
69
|
}, z.core.$strip>;
|
|
70
70
|
export type InstallationSecrets = z.infer<typeof installationSecretsSchema>;
|
|
71
|
+
/** One model the installation's model server declares: its state, and its digest once served (feature 053). */
|
|
72
|
+
export declare const modelLineSchema: z.ZodObject<{
|
|
73
|
+
name: z.ZodString;
|
|
74
|
+
state: z.ZodString;
|
|
75
|
+
digest: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
76
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
77
|
+
}, z.core.$strip>;
|
|
78
|
+
export type ModelLine = z.infer<typeof modelLineSchema>;
|
|
79
|
+
/** One cluster's model server, read live through its door. */
|
|
80
|
+
export declare const clusterModelsSchema: z.ZodObject<{
|
|
81
|
+
cluster: z.ZodString;
|
|
82
|
+
server: z.ZodString;
|
|
83
|
+
ready: z.ZodBoolean;
|
|
84
|
+
models: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
85
|
+
name: z.ZodString;
|
|
86
|
+
state: z.ZodString;
|
|
87
|
+
digest: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
88
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
89
|
+
}, z.core.$strip>>>;
|
|
90
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
91
|
+
}, z.core.$strip>;
|
|
92
|
+
export type ClusterModels = z.infer<typeof clusterModelsSchema>;
|
|
93
|
+
export declare const installationModelsSchema: z.ZodObject<{
|
|
94
|
+
clusters: z.ZodArray<z.ZodObject<{
|
|
95
|
+
cluster: z.ZodString;
|
|
96
|
+
server: z.ZodString;
|
|
97
|
+
ready: z.ZodBoolean;
|
|
98
|
+
models: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
99
|
+
name: z.ZodString;
|
|
100
|
+
state: z.ZodString;
|
|
101
|
+
digest: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
102
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
103
|
+
}, z.core.$strip>>>;
|
|
104
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
105
|
+
}, z.core.$strip>>;
|
|
106
|
+
}, z.core.$strip>;
|
|
107
|
+
export type InstallationModels = z.infer<typeof installationModelsSchema>;
|
|
108
|
+
/**
|
|
109
|
+
* The installation's broker (spec 057): how many nodes, absent when the control plane was not told,
|
|
110
|
+
* and the copies a topic is given by default, with how many must hold a message.
|
|
111
|
+
*/
|
|
112
|
+
export declare const installationBrokerSchema: z.ZodObject<{
|
|
113
|
+
nodes: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodNumber>>, z.ZodTransform<number | undefined, number | null | undefined>>;
|
|
114
|
+
defaultCopies: z.ZodNumber;
|
|
115
|
+
minInSync: z.ZodNumber;
|
|
116
|
+
}, z.core.$strip>;
|
|
117
|
+
export type InstallationBroker = z.infer<typeof installationBrokerSchema>;
|
|
118
|
+
/** The longest retention a topic may be given (spec 057): a duration, or unbounded. */
|
|
119
|
+
export declare const installationRetentionSchema: z.ZodObject<{
|
|
120
|
+
longest: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
121
|
+
unbounded: z.ZodDefault<z.ZodBoolean>;
|
|
122
|
+
}, z.core.$strip>;
|
|
123
|
+
export type InstallationRetention = z.infer<typeof installationRetentionSchema>;
|
|
124
|
+
/** Erasure and its keyring (spec 057, built by spec 042); absent until the platform has erasure. */
|
|
125
|
+
export declare const installationErasureSchema: z.ZodObject<{
|
|
126
|
+
enabled: z.ZodBoolean;
|
|
127
|
+
keyringInstances: z.ZodNumber;
|
|
128
|
+
}, z.core.$strip>;
|
|
129
|
+
export type InstallationErasure = z.infer<typeof installationErasureSchema>;
|
|
71
130
|
/**
|
|
72
131
|
* `GET /installation`: the platform's version, and its cloud when it names a provider; and its
|
|
73
|
-
* backups (feature 041);
|
|
132
|
+
* backups (feature 041); where it keeps its secrets (feature 038); its model server (feature 053);
|
|
133
|
+
* and its broker, longest retention and erasure (spec 057), each absent when not stated.
|
|
74
134
|
*/
|
|
75
135
|
export declare const installationSchema: z.ZodObject<{
|
|
76
136
|
platformVersion: z.ZodString;
|
|
@@ -211,6 +271,79 @@ export declare const installationSchema: z.ZodObject<{
|
|
|
211
271
|
recordRetention: string;
|
|
212
272
|
auditLog: string;
|
|
213
273
|
} | null | undefined>>;
|
|
274
|
+
models: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
275
|
+
clusters: z.ZodArray<z.ZodObject<{
|
|
276
|
+
cluster: z.ZodString;
|
|
277
|
+
server: z.ZodString;
|
|
278
|
+
ready: z.ZodBoolean;
|
|
279
|
+
models: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
280
|
+
name: z.ZodString;
|
|
281
|
+
state: z.ZodString;
|
|
282
|
+
digest: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
283
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
284
|
+
}, z.core.$strip>>>;
|
|
285
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
286
|
+
}, z.core.$strip>>;
|
|
287
|
+
}, z.core.$strip>>>, z.ZodTransform<{
|
|
288
|
+
clusters: {
|
|
289
|
+
cluster: string;
|
|
290
|
+
server: string;
|
|
291
|
+
ready: boolean;
|
|
292
|
+
models: {
|
|
293
|
+
name: string;
|
|
294
|
+
state: string;
|
|
295
|
+
digest: string | undefined;
|
|
296
|
+
detail: string | undefined;
|
|
297
|
+
}[];
|
|
298
|
+
detail: string | undefined;
|
|
299
|
+
}[];
|
|
300
|
+
} | undefined, {
|
|
301
|
+
clusters: {
|
|
302
|
+
cluster: string;
|
|
303
|
+
server: string;
|
|
304
|
+
ready: boolean;
|
|
305
|
+
models: {
|
|
306
|
+
name: string;
|
|
307
|
+
state: string;
|
|
308
|
+
digest: string | undefined;
|
|
309
|
+
detail: string | undefined;
|
|
310
|
+
}[];
|
|
311
|
+
detail: string | undefined;
|
|
312
|
+
}[];
|
|
313
|
+
} | null | undefined>>;
|
|
314
|
+
broker: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
315
|
+
nodes: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodNumber>>, z.ZodTransform<number | undefined, number | null | undefined>>;
|
|
316
|
+
defaultCopies: z.ZodNumber;
|
|
317
|
+
minInSync: z.ZodNumber;
|
|
318
|
+
}, z.core.$strip>>>, z.ZodTransform<{
|
|
319
|
+
nodes: number | undefined;
|
|
320
|
+
defaultCopies: number;
|
|
321
|
+
minInSync: number;
|
|
322
|
+
} | undefined, {
|
|
323
|
+
nodes: number | undefined;
|
|
324
|
+
defaultCopies: number;
|
|
325
|
+
minInSync: number;
|
|
326
|
+
} | null | undefined>>;
|
|
327
|
+
retention: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
328
|
+
longest: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
329
|
+
unbounded: z.ZodDefault<z.ZodBoolean>;
|
|
330
|
+
}, z.core.$strip>>>, z.ZodTransform<{
|
|
331
|
+
longest: string | undefined;
|
|
332
|
+
unbounded: boolean;
|
|
333
|
+
} | undefined, {
|
|
334
|
+
longest: string | undefined;
|
|
335
|
+
unbounded: boolean;
|
|
336
|
+
} | null | undefined>>;
|
|
337
|
+
erasure: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
338
|
+
enabled: z.ZodBoolean;
|
|
339
|
+
keyringInstances: z.ZodNumber;
|
|
340
|
+
}, z.core.$strip>>>, z.ZodTransform<{
|
|
341
|
+
enabled: boolean;
|
|
342
|
+
keyringInstances: number;
|
|
343
|
+
} | undefined, {
|
|
344
|
+
enabled: boolean;
|
|
345
|
+
keyringInstances: number;
|
|
346
|
+
} | null | undefined>>;
|
|
214
347
|
}, z.core.$strip>;
|
|
215
348
|
export type Installation = z.infer<typeof installationSchema>;
|
|
216
349
|
export declare const quotaSchema: z.ZodObject<{
|
|
@@ -389,6 +522,21 @@ export declare const dnsRecordSchema: z.ZodObject<{
|
|
|
389
522
|
value: z.ZodString;
|
|
390
523
|
}, z.core.$strip>;
|
|
391
524
|
export type DnsRecord = z.infer<typeof dnsRecordSchema>;
|
|
525
|
+
/**
|
|
526
|
+
* One named bucket of a service, as the operator reported it (feature 055): kept ones are those the
|
|
527
|
+
* descriptor no longer names, which the platform never deletes.
|
|
528
|
+
*/
|
|
529
|
+
export declare const bucketReportSchema: z.ZodObject<{
|
|
530
|
+
name: z.ZodString;
|
|
531
|
+
phase: z.ZodString;
|
|
532
|
+
store: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
533
|
+
bucket: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
534
|
+
exposure: z.ZodDefault<z.ZodString>;
|
|
535
|
+
publicAddress: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
536
|
+
kept: z.ZodDefault<z.ZodBoolean>;
|
|
537
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
538
|
+
}, z.core.$strip>;
|
|
539
|
+
export type BucketReport = z.infer<typeof bucketReportSchema>;
|
|
392
540
|
/** One custom hostname of a service: where it stands, and the record that points it at the installation. */
|
|
393
541
|
export declare const customHostnameSchema: z.ZodObject<{
|
|
394
542
|
hostname: z.ZodString;
|
|
@@ -622,6 +770,34 @@ export declare const serviceStatusSchema: z.ZodObject<{
|
|
|
622
770
|
bucketLocation: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
623
771
|
softDeleteDays: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodNumber>>, z.ZodTransform<number | undefined, number | null | undefined>>;
|
|
624
772
|
storageMove: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
773
|
+
buckets: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
774
|
+
name: z.ZodString;
|
|
775
|
+
phase: z.ZodString;
|
|
776
|
+
store: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
777
|
+
bucket: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
778
|
+
exposure: z.ZodDefault<z.ZodString>;
|
|
779
|
+
publicAddress: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
780
|
+
kept: z.ZodDefault<z.ZodBoolean>;
|
|
781
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
782
|
+
}, z.core.$strip>>>>, z.ZodTransform<{
|
|
783
|
+
name: string;
|
|
784
|
+
phase: string;
|
|
785
|
+
store: string | undefined;
|
|
786
|
+
bucket: string | undefined;
|
|
787
|
+
exposure: string;
|
|
788
|
+
publicAddress: string | undefined;
|
|
789
|
+
kept: boolean;
|
|
790
|
+
detail: string | undefined;
|
|
791
|
+
}[] | undefined, {
|
|
792
|
+
name: string;
|
|
793
|
+
phase: string;
|
|
794
|
+
store: string | undefined;
|
|
795
|
+
bucket: string | undefined;
|
|
796
|
+
exposure: string;
|
|
797
|
+
publicAddress: string | undefined;
|
|
798
|
+
kept: boolean;
|
|
799
|
+
detail: string | undefined;
|
|
800
|
+
}[] | null | undefined>>;
|
|
625
801
|
databaseCluster: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
626
802
|
grants: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
627
803
|
crossProjectTopics: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodLazy<z.ZodObject<{
|
|
@@ -939,6 +1115,34 @@ export declare const rolledBackSchema: z.ZodObject<{
|
|
|
939
1115
|
bucketLocation: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
940
1116
|
softDeleteDays: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodNumber>>, z.ZodTransform<number | undefined, number | null | undefined>>;
|
|
941
1117
|
storageMove: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
1118
|
+
buckets: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
1119
|
+
name: z.ZodString;
|
|
1120
|
+
phase: z.ZodString;
|
|
1121
|
+
store: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
1122
|
+
bucket: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
1123
|
+
exposure: z.ZodDefault<z.ZodString>;
|
|
1124
|
+
publicAddress: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
1125
|
+
kept: z.ZodDefault<z.ZodBoolean>;
|
|
1126
|
+
detail: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
1127
|
+
}, z.core.$strip>>>>, z.ZodTransform<{
|
|
1128
|
+
name: string;
|
|
1129
|
+
phase: string;
|
|
1130
|
+
store: string | undefined;
|
|
1131
|
+
bucket: string | undefined;
|
|
1132
|
+
exposure: string;
|
|
1133
|
+
publicAddress: string | undefined;
|
|
1134
|
+
kept: boolean;
|
|
1135
|
+
detail: string | undefined;
|
|
1136
|
+
}[] | undefined, {
|
|
1137
|
+
name: string;
|
|
1138
|
+
phase: string;
|
|
1139
|
+
store: string | undefined;
|
|
1140
|
+
bucket: string | undefined;
|
|
1141
|
+
exposure: string;
|
|
1142
|
+
publicAddress: string | undefined;
|
|
1143
|
+
kept: boolean;
|
|
1144
|
+
detail: string | undefined;
|
|
1145
|
+
}[] | null | undefined>>;
|
|
942
1146
|
databaseCluster: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
943
1147
|
grants: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | undefined, string | null | undefined>>;
|
|
944
1148
|
crossProjectTopics: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodLazy<z.ZodObject<{
|
package/dist/client/schemas.js
CHANGED
|
@@ -57,9 +57,47 @@ export const installationSecretsSchema = z.object({
|
|
|
57
57
|
recordRetention: z.string(),
|
|
58
58
|
auditLog: z.string().default("unknown"),
|
|
59
59
|
});
|
|
60
|
+
/** One model the installation's model server declares: its state, and its digest once served (feature 053). */
|
|
61
|
+
export const modelLineSchema = z.object({
|
|
62
|
+
name: z.string(),
|
|
63
|
+
state: z.string(),
|
|
64
|
+
digest: optional(z.string()),
|
|
65
|
+
detail: optional(z.string()),
|
|
66
|
+
});
|
|
67
|
+
/** One cluster's model server, read live through its door. */
|
|
68
|
+
export const clusterModelsSchema = z.object({
|
|
69
|
+
cluster: z.string(),
|
|
70
|
+
server: z.string(),
|
|
71
|
+
ready: z.boolean(),
|
|
72
|
+
models: z.array(modelLineSchema).default([]),
|
|
73
|
+
detail: optional(z.string()),
|
|
74
|
+
});
|
|
75
|
+
export const installationModelsSchema = z.object({
|
|
76
|
+
clusters: z.array(clusterModelsSchema),
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* The installation's broker (spec 057): how many nodes, absent when the control plane was not told,
|
|
80
|
+
* and the copies a topic is given by default, with how many must hold a message.
|
|
81
|
+
*/
|
|
82
|
+
export const installationBrokerSchema = z.object({
|
|
83
|
+
nodes: optional(z.number().int()),
|
|
84
|
+
defaultCopies: z.number().int(),
|
|
85
|
+
minInSync: z.number().int(),
|
|
86
|
+
});
|
|
87
|
+
/** The longest retention a topic may be given (spec 057): a duration, or unbounded. */
|
|
88
|
+
export const installationRetentionSchema = z.object({
|
|
89
|
+
longest: optional(z.string()),
|
|
90
|
+
unbounded: z.boolean().default(false),
|
|
91
|
+
});
|
|
92
|
+
/** Erasure and its keyring (spec 057, built by spec 042); absent until the platform has erasure. */
|
|
93
|
+
export const installationErasureSchema = z.object({
|
|
94
|
+
enabled: z.boolean(),
|
|
95
|
+
keyringInstances: z.number().int(),
|
|
96
|
+
});
|
|
60
97
|
/**
|
|
61
98
|
* `GET /installation`: the platform's version, and its cloud when it names a provider; and its
|
|
62
|
-
* backups (feature 041);
|
|
99
|
+
* backups (feature 041); where it keeps its secrets (feature 038); its model server (feature 053);
|
|
100
|
+
* and its broker, longest retention and erasure (spec 057), each absent when not stated.
|
|
63
101
|
*/
|
|
64
102
|
export const installationSchema = z.object({
|
|
65
103
|
platformVersion: z.string(),
|
|
@@ -67,6 +105,10 @@ export const installationSchema = z.object({
|
|
|
67
105
|
// Lazily: its schema is with the other backup schemas, below.
|
|
68
106
|
backups: optional(z.lazy(() => installationStatusSchema)),
|
|
69
107
|
secrets: optional(installationSecretsSchema),
|
|
108
|
+
models: optional(installationModelsSchema),
|
|
109
|
+
broker: optional(installationBrokerSchema),
|
|
110
|
+
retention: optional(installationRetentionSchema),
|
|
111
|
+
erasure: optional(installationErasureSchema),
|
|
70
112
|
});
|
|
71
113
|
export const quotaSchema = z.object({
|
|
72
114
|
projects: optional(z.number().int()),
|
|
@@ -140,6 +182,24 @@ export const dnsRecordSchema = z.object({
|
|
|
140
182
|
kind: z.string(),
|
|
141
183
|
value: z.string(),
|
|
142
184
|
});
|
|
185
|
+
/**
|
|
186
|
+
* One named bucket of a service, as the operator reported it (feature 055): kept ones are those the
|
|
187
|
+
* descriptor no longer names, which the platform never deletes.
|
|
188
|
+
*/
|
|
189
|
+
export const bucketReportSchema = z.object({
|
|
190
|
+
name: z.string(),
|
|
191
|
+
phase: z.string(),
|
|
192
|
+
/** `garage` or `gcs`; absent for a supplied bucket. */
|
|
193
|
+
store: optional(z.string()),
|
|
194
|
+
/** Its name in the store. */
|
|
195
|
+
bucket: optional(z.string()),
|
|
196
|
+
/** `private`, `signed`, `public` or `supplied`. */
|
|
197
|
+
exposure: z.string().default("private"),
|
|
198
|
+
/** Where a public or signed bucket is on the internet. */
|
|
199
|
+
publicAddress: optional(z.string()),
|
|
200
|
+
kept: z.boolean().default(false),
|
|
201
|
+
detail: optional(z.string()),
|
|
202
|
+
});
|
|
143
203
|
/** One custom hostname of a service: where it stands, and the record that points it at the installation. */
|
|
144
204
|
export const customHostnameSchema = z.object({
|
|
145
205
|
hostname: z.string(),
|
|
@@ -190,6 +250,8 @@ export const serviceStatusSchema = z.object({
|
|
|
190
250
|
softDeleteDays: optional(z.number().int()),
|
|
191
251
|
/** Where a move of the bucket from Garage is, as a phrase; its detail is in `detail`. */
|
|
192
252
|
storageMove: optional(z.string()),
|
|
253
|
+
/** Each named bucket, in the descriptor's order, then the kept ones (feature 055); absent when none. */
|
|
254
|
+
buckets: optional(z.array(bucketReportSchema)),
|
|
193
255
|
/** The project database cluster the service is on, when a member switched it to a restore. */
|
|
194
256
|
databaseCluster: optional(z.string()),
|
|
195
257
|
/** `mounted` when the service's instances read their project's grants (feature 040). */
|
package/dist/routes/front.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The front page: who you are, as the control plane sees you, and the organizations you can see —
|
|
3
3
|
* yours with your role in each, or every one of them for a platform administrator — and what the
|
|
4
|
-
* installation is: its version, and its cloud when it names one (feature 044)
|
|
4
|
+
* installation is: its version, and its cloud when it names one (feature 044), and its broker and
|
|
5
|
+
* longest topic retention (spec 057).
|
|
5
6
|
*/
|
|
6
7
|
import { type ActionFunctionArgs, type LoaderFunctionArgs, type MetaFunction } from "react-router";
|
|
7
8
|
import { ConsoleErrorBoundary } from "../ui/errors.tsx";
|
|
@@ -76,6 +77,33 @@ export declare function loader({ context }: LoaderFunctionArgs): Promise<{
|
|
|
76
77
|
recordRetention: string;
|
|
77
78
|
auditLog: string;
|
|
78
79
|
} | undefined;
|
|
80
|
+
models: {
|
|
81
|
+
clusters: {
|
|
82
|
+
cluster: string;
|
|
83
|
+
server: string;
|
|
84
|
+
ready: boolean;
|
|
85
|
+
models: {
|
|
86
|
+
name: string;
|
|
87
|
+
state: string;
|
|
88
|
+
digest: string | undefined;
|
|
89
|
+
detail: string | undefined;
|
|
90
|
+
}[];
|
|
91
|
+
detail: string | undefined;
|
|
92
|
+
}[];
|
|
93
|
+
} | undefined;
|
|
94
|
+
broker: {
|
|
95
|
+
nodes: number | undefined;
|
|
96
|
+
defaultCopies: number;
|
|
97
|
+
minInSync: number;
|
|
98
|
+
} | undefined;
|
|
99
|
+
retention: {
|
|
100
|
+
longest: string | undefined;
|
|
101
|
+
unbounded: boolean;
|
|
102
|
+
} | undefined;
|
|
103
|
+
erasure: {
|
|
104
|
+
enabled: boolean;
|
|
105
|
+
keyringInstances: number;
|
|
106
|
+
} | undefined;
|
|
79
107
|
};
|
|
80
108
|
hold: {
|
|
81
109
|
held: boolean;
|
package/dist/routes/front.js
CHANGED
|
@@ -2,7 +2,8 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
/**
|
|
3
3
|
* The front page: who you are, as the control plane sees you, and the organizations you can see —
|
|
4
4
|
* yours with your role in each, or every one of them for a platform administrator — and what the
|
|
5
|
-
* installation is: its version, and its cloud when it names one (feature 044)
|
|
5
|
+
* installation is: its version, and its cloud when it names one (feature 044), and its broker and
|
|
6
|
+
* longest topic retention (spec 057).
|
|
6
7
|
*/
|
|
7
8
|
import { redirect, useLoaderData } from "react-router";
|
|
8
9
|
import { act, guard, pageData, text, useConsoleContext, withShell } from "../context.js";
|
|
@@ -50,7 +51,18 @@ export default function Front() {
|
|
|
50
51
|
const hostActions = useHostActions("organization.create");
|
|
51
52
|
const { shows } = useConsole();
|
|
52
53
|
return (_jsxs(Page, { inspector: hostActions ? (_jsx("div", { className: "ac-ops", children: _jsx(HostActions, { operation: "organization.create" }) })) : null, children: [_jsx("h1", { children: "Organizations" }), _jsxs("p", { className: "ac-lede", children: ["Signed in as ", _jsx("strong", { children: whoami.name ?? whoami.email ?? whoami.subject }), whoami.email && whoami.name ? ` (${whoami.email})` : null, whoami.platformAdmin ? ", a platform administrator: you see every organization in this installation." : "."] }), hold?.held ? (_jsxs("section", { className: "ac-card", "aria-labelledby": "hold-title", "data-held": "yes", children: [_jsx("h2", { id: "hold-title", children: "The control plane is held" }), _jsxs("p", { children: ["Its database was restored to ", hold.targetTime ? when(hold.targetTime) : "an earlier moment", ", and it changes nothing in the cluster until a platform administrator releases it."] }), hold.services.length > 0 ? (_jsx("ul", { className: "ac-topics", "aria-label": "Services that differ", children: hold.services.map((d) => (_jsxs("li", { "data-differs": `${d.project}/${d.service}`, children: [d.project, "/", d.service, ": recorded ", d.recordedImage ?? "nothing", ", the cluster runs ", d.clusterImage ?? "nothing"] }, `${d.project}/${d.service}`))) })) : null, hold.unknownProjects.length > 0 ? _jsxs("p", { children: ["Projects the database does not know: ", hold.unknownProjects.join(", "), "."] }) : null, whoami.platformAdmin && shows("installation.release") ? (_jsx(ConsoleForm, { intent: "release", children: _jsx(Submit, { intent: "release", children: "Release the control plane" }) })) : null, _jsx(Refused, { intent: "release" })] })) : hold?.releasedAt ? (_jsxs("p", { "data-held": "released", children: ["The control plane was released after its database's restore, ", when(hold.releasedAt), hold.releasedBy ? ` by ${hold.releasedBy}` : "", "."] })) : null, backups ? (_jsx("p", { className: "ac-hint", "data-backups": backups.backupTarget, children: backups.notBackedUp ??
|
|
53
|
-
`Backups are kept at least ${backups.retentionDays} days${backups.sharesFailureDomain ? ", in the cluster they back up" : ", with a copy outside the cluster"}.` })) : null, organizations.length === 0 ? (_jsxs("p", { className: "ac-empty", children: ["You are not a member of any organization yet. Create one, or ask an owner to invite ", whoami.email ?? "you", "."] })) : (_jsx("div", { className: "ac-card ac-table-wrap", children: _jsxs("table", { className: "ac-table", children: [_jsx("caption", { className: "ac-visually-hidden", children: "Organizations you can see" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Name" }), _jsx("th", { scope: "col", children: "Id" }), _jsx("th", { scope: "col", children: "Your role" }), _jsx("th", { scope: "col", className: "ac-num", children: "Projects" }), _jsx("th", { scope: "col", children: "State" })] }) }), _jsx("tbody", { children: organizations.map((o) => (_jsxs("tr", { children: [_jsx("td", { children: _jsx(ConsoleLink, { to: `organizations/${encodeURIComponent(o.id)}`, children: o.name }) }), _jsx("td", { children: o.id }), _jsx("td", { children: o.role ? roleWords[o.role] : "Administrator (not a member)" }), _jsx("td", { className: "ac-num", children: o.projects }), _jsx("td", { children: o.disabled ? "Disabled" : "Active" })] }, o.id))) })] }) })), _jsxs("section", { className: "ac-card", "aria-labelledby": "installation", children: [_jsx("h2", { id: "installation", children: "This installation" }), _jsxs("dl", { className: "ac-facts", children: [_jsx("dt", { children: "Platform version" }), _jsx("dd", { children: installation.platformVersion }), _jsx("dt", { children: "Cloud" }), _jsx("dd", { children: cloud ? `${cloud.provider}, account ${cloud.account}` : "None: everything is served by the installation itself" }), cloud ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Location" }), _jsx("dd", { children: cloud.location })] })) : null, cloud?.kmsKey ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Wrapping key" }), _jsx("dd", { children: cloud.kmsKey })] })) : null, installation.secrets ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Secrets kept in" }), _jsx("dd", { children: secretBackendWords[installation.secrets.backend] ?? installation.secrets.backend }), _jsx("dt", { children: "Record of reads kept for" }), _jsx("dd", { children: installation.secrets.recordRetention }), _jsx("dt", { children: "Access log" }), _jsx("dd", { children: installation.secrets.auditLog })] })) : null] })] })] }));
|
|
54
|
+
`Backups are kept at least ${backups.retentionDays} days${backups.sharesFailureDomain ? ", in the cluster they back up" : ", with a copy outside the cluster"}.` })) : null, organizations.length === 0 ? (_jsxs("p", { className: "ac-empty", children: ["You are not a member of any organization yet. Create one, or ask an owner to invite ", whoami.email ?? "you", "."] })) : (_jsx("div", { className: "ac-card ac-table-wrap", children: _jsxs("table", { className: "ac-table", children: [_jsx("caption", { className: "ac-visually-hidden", children: "Organizations you can see" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Name" }), _jsx("th", { scope: "col", children: "Id" }), _jsx("th", { scope: "col", children: "Your role" }), _jsx("th", { scope: "col", className: "ac-num", children: "Projects" }), _jsx("th", { scope: "col", children: "State" })] }) }), _jsx("tbody", { children: organizations.map((o) => (_jsxs("tr", { children: [_jsx("td", { children: _jsx(ConsoleLink, { to: `organizations/${encodeURIComponent(o.id)}`, children: o.name }) }), _jsx("td", { children: o.id }), _jsx("td", { children: o.role ? roleWords[o.role] : "Administrator (not a member)" }), _jsx("td", { className: "ac-num", children: o.projects }), _jsx("td", { children: o.disabled ? "Disabled" : "Active" })] }, o.id))) })] }) })), _jsxs("section", { className: "ac-card", "aria-labelledby": "installation", children: [_jsx("h2", { id: "installation", children: "This installation" }), _jsxs("dl", { className: "ac-facts", children: [_jsx("dt", { children: "Platform version" }), _jsx("dd", { children: installation.platformVersion }), _jsx("dt", { children: "Cloud" }), _jsx("dd", { children: cloud ? `${cloud.provider}, account ${cloud.account}` : "None: everything is served by the installation itself" }), cloud ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Location" }), _jsx("dd", { children: cloud.location })] })) : null, cloud?.kmsKey ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Wrapping key" }), _jsx("dd", { children: cloud.kmsKey })] })) : null, installation.secrets ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Secrets kept in" }), _jsx("dd", { children: secretBackendWords[installation.secrets.backend] ?? installation.secrets.backend }), _jsx("dt", { children: "Record of reads kept for" }), _jsx("dd", { children: installation.secrets.recordRetention }), _jsx("dt", { children: "Access log" }), _jsx("dd", { children: installation.secrets.auditLog })] })) : null, installation.broker ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Broker" }), _jsx("dd", { children: brokerWords(installation.broker) })] })) : null, installation.retention ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Longest topic retention" }), _jsx("dd", { children: retentionWords(installation.retention) })] })) : null] })] })] }));
|
|
55
|
+
}
|
|
56
|
+
/** The installation's broker (spec 057), in words; a node count the control plane was not told is said so. */
|
|
57
|
+
function brokerWords(broker) {
|
|
58
|
+
const nodes = broker.nodes === undefined ? "nodes not stated" : `${broker.nodes} ${broker.nodes === 1 ? "node" : "nodes"}`;
|
|
59
|
+
return `${nodes}; a topic gets ${broker.defaultCopies} ${broker.defaultCopies === 1 ? "copy" : "copies"}, ${broker.minInSync} in sync, by default`;
|
|
60
|
+
}
|
|
61
|
+
/** The longest retention a topic may be given (spec 057), in words. */
|
|
62
|
+
function retentionWords(retention) {
|
|
63
|
+
if (retention.longest !== undefined)
|
|
64
|
+
return retention.longest;
|
|
65
|
+
return retention.unbounded ? "Unbounded" : "Not stated";
|
|
54
66
|
}
|
|
55
67
|
/** The installation's secret store (feature 038), in words; an unknown backend is shown as it is named. */
|
|
56
68
|
const secretBackendWords = {
|
package/dist/routes/logs.d.ts
CHANGED
|
@@ -87,6 +87,16 @@ export declare function loader({ request, params, context }: LoaderFunctionArgs)
|
|
|
87
87
|
bucketLocation: string | undefined;
|
|
88
88
|
softDeleteDays: number | undefined;
|
|
89
89
|
storageMove: string | undefined;
|
|
90
|
+
buckets: {
|
|
91
|
+
name: string;
|
|
92
|
+
phase: string;
|
|
93
|
+
store: string | undefined;
|
|
94
|
+
bucket: string | undefined;
|
|
95
|
+
exposure: string;
|
|
96
|
+
publicAddress: string | undefined;
|
|
97
|
+
kept: boolean;
|
|
98
|
+
detail: string | undefined;
|
|
99
|
+
}[] | undefined;
|
|
90
100
|
databaseCluster: string | undefined;
|
|
91
101
|
grants: string | undefined;
|
|
92
102
|
crossProjectTopics: {
|
package/dist/routes/project.d.ts
CHANGED
|
@@ -120,6 +120,16 @@ export declare function loader({ params, context }: LoaderFunctionArgs): Promise
|
|
|
120
120
|
bucketLocation: string | undefined;
|
|
121
121
|
softDeleteDays: number | undefined;
|
|
122
122
|
storageMove: string | undefined;
|
|
123
|
+
buckets: {
|
|
124
|
+
name: string;
|
|
125
|
+
phase: string;
|
|
126
|
+
store: string | undefined;
|
|
127
|
+
bucket: string | undefined;
|
|
128
|
+
exposure: string;
|
|
129
|
+
publicAddress: string | undefined;
|
|
130
|
+
kept: boolean;
|
|
131
|
+
detail: string | undefined;
|
|
132
|
+
}[] | undefined;
|
|
123
133
|
databaseCluster: string | undefined;
|
|
124
134
|
grants: string | undefined;
|
|
125
135
|
crossProjectTopics: {
|
|
@@ -77,6 +77,6 @@ const words = {
|
|
|
77
77
|
export default function ServiceHistory() {
|
|
78
78
|
const { name, projectId, history } = useLoaderData();
|
|
79
79
|
const offered = rollbackTargets(history);
|
|
80
|
-
return (_jsxs(Page, { children: [_jsxs("div", { className: "ac-head", children: [_jsxs("h1", { children: ["History of ", name] }), _jsx(ServiceSections, { projectId: projectId, name: name, current: "history" })] }), _jsxs("section", { className: "ac-card", "aria-labelledby": "history", children: [_jsx("h2", { id: "history", children: "History" }), history.length === 0 ? (_jsx("p", { className: "ac-empty", children: "Nothing recorded yet." })) : (_jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "What" }), _jsx("th", { scope: "col", className: "ac-num", children: "Generation" }), _jsx("th", { scope: "col", children: "Image" }), _jsx("th", { scope: "col", children: "Digest" }), _jsx("th", { scope: "col", children: "Who" }), _jsx("th", { scope: "col", children: "When" }), _jsx("th", { scope: "col", "aria-label": "Roll back" })] }) }), _jsx("tbody", { children: history.map((h, i) => (_jsxs("tr", { children: [_jsx("td", { children: h.rolledBackTo !== undefined ? `Rolled back to generation ${h.rolledBackTo}` : (words[h.kind] ?? h.kind) }), _jsx("td", { className: "ac-num", children: h.generation }), _jsx("td", { children: h.image ?? "—" }), _jsx("td", { children: h.digest ? (_jsx(ConsoleLink, { to: `projects/${encodeURIComponent(projectId)}/services/apply?name=${encodeURIComponent(name)}&generation=${h.generation}`, "aria-label":
|
|
80
|
+
return (_jsxs(Page, { children: [_jsxs("div", { className: "ac-head", children: [_jsxs("h1", { children: ["History of ", name] }), _jsx(ServiceSections, { projectId: projectId, name: name, current: "history" })] }), _jsxs("section", { className: "ac-card", "aria-labelledby": "history", children: [_jsx("h2", { id: "history", children: "History" }), history.length === 0 ? (_jsx("p", { className: "ac-empty", children: "Nothing recorded yet." })) : (_jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "What" }), _jsx("th", { scope: "col", className: "ac-num", children: "Generation" }), _jsx("th", { scope: "col", children: "Image" }), _jsx("th", { scope: "col", children: "Digest" }), _jsx("th", { scope: "col", children: "Who" }), _jsx("th", { scope: "col", children: "When" }), _jsx("th", { scope: "col", "aria-label": "Roll back" })] }) }), _jsx("tbody", { children: history.map((h, i) => (_jsxs("tr", { children: [_jsx("td", { children: h.rolledBackTo !== undefined ? `Rolled back to generation ${h.rolledBackTo}` : (words[h.kind] ?? h.kind) }), _jsx("td", { className: "ac-num", children: h.generation }), _jsx("td", { children: h.image ?? "—" }), _jsx("td", { children: h.digest ? (_jsx(ConsoleLink, { to: `projects/${encodeURIComponent(projectId)}/services/apply?name=${encodeURIComponent(name)}&generation=${h.generation}`, "aria-label": `${h.digest.slice(0, 12)}, generation ${h.generation}'s descriptor`, children: _jsx("code", { title: h.digest, children: h.digest.slice(0, 12) }) })) : ("—") }), _jsxs("td", { children: [h.actor ? (h.actor.display ?? h.actor.subject) : "—", h.actor?.administrative ? " (as administrator)" : ""] }), _jsx("td", { children: when(h.at) }), _jsx("td", { children: offered.has(h.generation) ? _jsx(RollBack, { generation: h.generation, image: h.image, entity: { name, projectId, entry: h } }) : null })] }, i))) })] }) })), _jsx(Refused, { intent: "rollback" })] })] }));
|
|
81
81
|
}
|
|
82
82
|
export const ErrorBoundary = ConsoleErrorBoundary;
|
|
@@ -87,6 +87,16 @@ export declare function loader({ params, context }: LoaderFunctionArgs): Promise
|
|
|
87
87
|
bucketLocation: string | undefined;
|
|
88
88
|
softDeleteDays: number | undefined;
|
|
89
89
|
storageMove: string | undefined;
|
|
90
|
+
buckets: {
|
|
91
|
+
name: string;
|
|
92
|
+
phase: string;
|
|
93
|
+
store: string | undefined;
|
|
94
|
+
bucket: string | undefined;
|
|
95
|
+
exposure: string;
|
|
96
|
+
publicAddress: string | undefined;
|
|
97
|
+
kept: boolean;
|
|
98
|
+
detail: string | undefined;
|
|
99
|
+
}[] | undefined;
|
|
90
100
|
databaseCluster: string | undefined;
|
|
91
101
|
grants: string | undefined;
|
|
92
102
|
crossProjectTopics: {
|
package/dist/routes/service.d.ts
CHANGED
|
@@ -92,6 +92,16 @@ export declare function loader({ params, context }: LoaderFunctionArgs): Promise
|
|
|
92
92
|
bucketLocation: string | undefined;
|
|
93
93
|
softDeleteDays: number | undefined;
|
|
94
94
|
storageMove: string | undefined;
|
|
95
|
+
buckets: {
|
|
96
|
+
name: string;
|
|
97
|
+
phase: string;
|
|
98
|
+
store: string | undefined;
|
|
99
|
+
bucket: string | undefined;
|
|
100
|
+
exposure: string;
|
|
101
|
+
publicAddress: string | undefined;
|
|
102
|
+
kept: boolean;
|
|
103
|
+
detail: string | undefined;
|
|
104
|
+
}[] | undefined;
|
|
95
105
|
databaseCluster: string | undefined;
|
|
96
106
|
grants: string | undefined;
|
|
97
107
|
crossProjectTopics: {
|
package/dist/routes/service.js
CHANGED
|
@@ -12,6 +12,7 @@ import { Select } from "../ui/primitives/select.js";
|
|
|
12
12
|
import { Page, SectionTitle, ServiceSections } from "../ui/shell.js";
|
|
13
13
|
import { Shape } from "../ui/shape.js";
|
|
14
14
|
import { runsAs } from "../ui/hosting.js";
|
|
15
|
+
import { bucketRows } from "../ui/buckets.js";
|
|
15
16
|
import { Refused, useRefusal } from "../ui/refused.js";
|
|
16
17
|
import { Lifecycle } from "../ui/status.js";
|
|
17
18
|
import { useServiceStream } from "../ui/use-stream.js";
|
|
@@ -132,6 +133,6 @@ export default function Service() {
|
|
|
132
133
|
const { status: s, state } = useServiceStream(p.id, data.service.name, data.service);
|
|
133
134
|
const deleteRefused = useRefusal("delete") !== undefined;
|
|
134
135
|
const inspector = (_jsxs(_Fragment, { children: [_jsxs("section", { className: "ac-ops", "aria-labelledby": "operations-title", children: [_jsx(SectionTitle, { children: _jsx("span", { id: "operations-title", children: "Operations" }) }), s.paused ? _jsx(Operation, { intent: "resume", label: "Resume", operation: "service.resume", entity: s }) : _jsx(Operation, { intent: "pause", label: "Pause", operation: "service.pause", entity: s }), _jsx(Operation, { intent: "restart", label: "Restart", operation: "service.restart", entity: s }), s.exposed ? _jsx(Operation, { intent: "unexpose", label: "Unexpose", operation: "service.unexpose", entity: s }) : _jsx(Operation, { intent: "expose", label: "Expose", operation: "service.expose", entity: s })] }), _jsx(HostnameOperations, { service: s }), serviceOperations.map((op) => (_jsx(Refused, { intent: op }, op))), _jsx(Storage, { s: s }), _jsxs("details", { className: "ac-more", open: deleteRefused || undefined, children: [_jsx("summary", { children: "Delete" }), _jsxs("div", { className: "ac-danger-zone", children: [_jsxs("p", { children: ["Deleting ", s.name, " stops it and removes it from the project. Its database is kept, and so is its bucket if it has one: applying a descriptor with this name again brings the service back with its data."] }), _jsx(Operation, { intent: "delete", label: "Delete service", operation: "service.delete", danger: true, entity: s }), _jsx(Refused, { intent: "delete" })] })] })] }));
|
|
135
|
-
return (_jsxs(Page, { inspector: inspector, children: [_jsxs("div", { className: "ac-head", children: [_jsx("h1", { children: s.name }), _jsxs("p", { "aria-live": "polite", className: "ac-actions ac-state-line", children: [_jsx("span", { className: "ac-pill", children: _jsx(Lifecycle, { lifecycle: s.lifecycle, confirmed: s.confirmed }) }), state === "live" ? _jsx("span", { className: "ac-live", children: " Updating as the platform reports" }) : null] }), _jsx(ServiceSections, { projectId: p.id, name: s.name, current: "overview" })] }), s.detail ? _jsx("p", { className: "ac-notice", children: s.detail }) : null, _jsx(Shape, { service: s }), _jsx(Hostnames, { service: s }), _jsxs("section", { className: "ac-card", "aria-labelledby": "reported", children: [_jsx("h2", { id: "reported", children: "Reported by the cluster" }), _jsxs("dl", { className: "ac-facts", children: [_jsx("dt", { children: "Instances" }), _jsxs("dd", { children: [s.readyInstances, " ready of ", s.desiredInstances] }), _jsx("dt", { children: "Image" }), _jsx("dd", { children: s.image }), _jsx("dt", { children: "Generation" }), _jsx("dd", { children: s.generation }), _jsx("dt", { children: "Database" }), _jsx("dd", { children: s.hosting === "web" ? "None" : (s.database ?? "Nothing reported yet") }), _jsx("dt", { children: "Object storage" }), _jsxs("dd", { children: [objectStorage(s), s.bucketAddress ? _jsxs("span", { className: "ac-hint", "data-bucket-address": true, children: [" ", s.bucketAddress] }) : null] }), s.objectStore ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Object store" }), _jsx("dd", { "data-object-store": s.objectStore, children: stores[s.objectStore] ?? s.objectStore })] })) : null, s.bucketLocation ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Bucket location" }), _jsx("dd", { children: s.bucketLocation })] })) : null, s.softDeleteDays !== undefined && s.softDeleteDays !== null ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Deleted objects" }), _jsxs("dd", { children: ["Recoverable for ", s.softDeleteDays, " days"] })] })) : null, s.storageMove ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Bucket move" }), _jsx("dd", { "data-storage-move": true, children: s.storageMove })] })) : null, s.broker ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Broker" }), _jsx("dd", { children: s.broker })] })) : null, s.grants ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Grants" }), _jsx("dd", { "data-grants": true, children: s.grants })] })) : null, s.crossProjectTopics && s.crossProjectTopics.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Cross-project topics" }), _jsx("dd", { children: _jsx("ul", { className: "ac-topics", children: s.crossProjectTopics.map((t) => (_jsxs("li", { "data-cross-project-topic": `${t.project}/${t.topic}`, "data-granted": t.status === "granted" ? "yes" : "no", children: [_jsx("code", { children: `${t.project}/${t.topic}` }), " ", t.right, " ", t.status === "granted" ? t.status : _jsx("span", { className: "ac-notice", children: t.status })] }, `${t.project}/${t.topic}/${t.right}`))) }) })] })) : null, s.undeclaredTopics && s.undeclaredTopics.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Undeclared topics" }), _jsx("dd", { children: _jsx("ul", { className: "ac-topics", children: s.undeclaredTopics.map((t) => (_jsx("li", { "data-topic": t, children: _jsx("code", { children: t }) }, t))) }) })] })) : null, s.warnings && s.warnings.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Warnings" }), _jsx("dd", { children: _jsx("ul", { className: "ac-topics", children: s.warnings.map((w) => (_jsx("li", { "data-warning": w.kind, children: _jsx("span", { className: "ac-notice", children: w.message }) }, `${w.kind}/${w.component}/${w.topic}`))) }) })] })) : null, s.topicSources && s.topicSources.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Topic sources" }), _jsx("dd", { children: _jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", "data-topic-sources": true, children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Component" }), _jsx("th", { scope: "col", children: "Topic" }), _jsx("th", { scope: "col", children: "Group" }), _jsx("th", { scope: "col", className: "ac-num", children: "Version" }), _jsx("th", { scope: "col", className: "ac-num", children: "Lag" }), _jsx("th", { scope: "col", children: "Failing" }), _jsx("th", { scope: "col", children: "Retained" })] }) }), _jsx("tbody", { children: s.topicSources.map((t) => (_jsxs("tr", { "data-topic-source": t.component, "data-failing": t.failing ? "yes" : "no", children: [_jsx("td", { children: t.component }), _jsxs("td", { children: [_jsx("code", { children: t.broker ? `${t.topic}@${t.broker}` : t.topic }), t.contract ? ` as ${t.contract}` : ""] }), _jsx("td", { children: _jsx("code", { children: t.group }) }), _jsx("td", { className: "ac-num", children: t.version }), _jsx("td", { className: "ac-num", children: t.lag ?? "—" }), _jsx("td", { children: t.failing ? _jsx("span", { className: "ac-notice", children: t.failing }) : "—" }), _jsx("td", { "data-gap": t.gap ? (t.gap.compacted ? "compacted" : t.gap.gone ? "gone" : "everything") : "unknown", children: t.gap === undefined || t.gap === null ? ("—") : t.gap.compacted ? ("compacted") : !t.gap.gone ? ("everything") : (_jsxs("details", { children: [_jsx("summary", { children: "earlier messages gone" }), _jsx("ul", { className: "ac-topics", children: t.gap.partitions.map((p) => (_jsxs("li", { "data-partition": p.partition, children: ["p", p.partition, " from ", p.beginning, " (", p.earliestRetained ?? "holds nothing", ")"] }, p.partition))) })] })) })] }, t.component))) })] }) }) })] })) : null, s.topicChecks && s.topicChecks.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Topic checks" }), _jsx("dd", { children: _jsx("ul", { className: "ac-topics", children: s.topicChecks.map((c) => (_jsxs("li", { "data-check": c.state, children: [c.component, " ", c.direction, ": ", c.state, c.state === "mismatch" ? ` (${c.stated ?? "none"})` : ""] }, `${c.component}/${c.direction}`))) }) })] })) : null, _jsx("dt", { children: "Runs as" }), _jsx("dd", { children: runsAs(s) }), s.hosting === "web" ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Admits" }), _jsx("dd", { children: ["The internet", ...s.callers.map((c) => (c === "*" ? `Every service in ${p.name}` : c))].join(", ") }), _jsx("dt", { children: "Mounts" }), _jsx("dd", { children: s.mounts.length === 0 ? ("None") : (_jsx("ul", { className: "ac-mounts", children: s.mounts.map((m) => (_jsxs("li", { "data-mount": m.path, children: [_jsx("code", { children: m.path }), " \u2192 ", m.service, m.state && m.state !== "ok" ? ` (${m.state})` : ""] }, m.path))) })) })] })) : null, _jsx("dt", { children: "Stopped by" }), _jsx("dd", { children: s.suspended ? "Its organization is disabled" : s.paused ? "Its members paused it" : "Nobody" }), _jsx("dt", { children: "Report" }), _jsx("dd", { children: s.confirmed ? "Confirmed by the cluster" : "The last known state; the cluster has not confirmed it" })] })] }), _jsx(Panels, { kind: "service", entity: s, loaded: panels })] }));
|
|
136
|
+
return (_jsxs(Page, { inspector: inspector, children: [_jsxs("div", { className: "ac-head", children: [_jsx("h1", { children: s.name }), _jsxs("p", { "aria-live": "polite", className: "ac-actions ac-state-line", children: [_jsx("span", { className: "ac-pill", children: _jsx(Lifecycle, { lifecycle: s.lifecycle, confirmed: s.confirmed }) }), state === "live" ? _jsx("span", { className: "ac-live", children: " Updating as the platform reports" }) : null] }), _jsx(ServiceSections, { projectId: p.id, name: s.name, current: "overview" })] }), s.detail ? _jsx("p", { className: "ac-notice", children: s.detail }) : null, _jsx(Shape, { service: s }), _jsx(Hostnames, { service: s }), _jsxs("section", { className: "ac-card", "aria-labelledby": "reported", children: [_jsx("h2", { id: "reported", children: "Reported by the cluster" }), _jsxs("dl", { className: "ac-facts", children: [_jsx("dt", { children: "Instances" }), _jsxs("dd", { children: [s.readyInstances, " ready of ", s.desiredInstances] }), _jsx("dt", { children: "Image" }), _jsx("dd", { children: s.image }), _jsx("dt", { children: "Generation" }), _jsx("dd", { children: s.generation }), _jsx("dt", { children: "Database" }), _jsx("dd", { children: s.hosting === "web" ? "None" : (s.database ?? "Nothing reported yet") }), _jsx("dt", { children: "Object storage" }), _jsxs("dd", { children: [objectStorage(s), s.bucketAddress ? _jsxs("span", { className: "ac-hint", "data-bucket-address": true, children: [" ", s.bucketAddress] }) : null] }), s.objectStore ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Object store" }), _jsx("dd", { "data-object-store": s.objectStore, children: stores[s.objectStore] ?? s.objectStore })] })) : null, s.bucketLocation ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Bucket location" }), _jsx("dd", { children: s.bucketLocation })] })) : null, s.softDeleteDays !== undefined && s.softDeleteDays !== null ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Deleted objects" }), _jsxs("dd", { children: ["Recoverable for ", s.softDeleteDays, " days"] })] })) : null, s.storageMove ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Bucket move" }), _jsx("dd", { "data-storage-move": true, children: s.storageMove })] })) : null, s.buckets && s.buckets.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Named buckets" }), _jsx("dd", { children: _jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", "data-buckets": true, children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Name" }), _jsx("th", { scope: "col", children: "Exposure" }), _jsx("th", { scope: "col", children: "Bucket" }), _jsx("th", { scope: "col", children: "Address" })] }) }), _jsx("tbody", { children: bucketRows(s.buckets).map((b) => (_jsxs("tr", { "data-bucket": b.name, children: [_jsx("th", { scope: "row", children: b.name }), _jsx("td", { "data-bucket-exposure": true, children: b.exposure }), _jsx("td", { children: b.bucket ?? "" }), _jsxs("td", { children: [b.address ? _jsx("a", { href: b.address, children: b.address }) : null, b.note ? _jsx("span", { className: "ac-hint", "data-bucket-note": true, children: b.note }) : null] })] }, b.name))) })] }) }) })] })) : null, s.broker ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Broker" }), _jsx("dd", { children: s.broker })] })) : null, s.grants ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Grants" }), _jsx("dd", { "data-grants": true, children: s.grants })] })) : null, s.crossProjectTopics && s.crossProjectTopics.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Cross-project topics" }), _jsx("dd", { children: _jsx("ul", { className: "ac-topics", children: s.crossProjectTopics.map((t) => (_jsxs("li", { "data-cross-project-topic": `${t.project}/${t.topic}`, "data-granted": t.status === "granted" ? "yes" : "no", children: [_jsx("code", { children: `${t.project}/${t.topic}` }), " ", t.right, " ", t.status === "granted" ? t.status : _jsx("span", { className: "ac-notice", children: t.status })] }, `${t.project}/${t.topic}/${t.right}`))) }) })] })) : null, s.undeclaredTopics && s.undeclaredTopics.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Undeclared topics" }), _jsx("dd", { children: _jsx("ul", { className: "ac-topics", children: s.undeclaredTopics.map((t) => (_jsx("li", { "data-topic": t, children: _jsx("code", { children: t }) }, t))) }) })] })) : null, s.warnings && s.warnings.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Warnings" }), _jsx("dd", { children: _jsx("ul", { className: "ac-topics", children: s.warnings.map((w) => (_jsx("li", { "data-warning": w.kind, children: _jsx("span", { className: "ac-notice", children: w.message }) }, `${w.kind}/${w.component}/${w.topic}`))) }) })] })) : null, s.topicSources && s.topicSources.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Topic sources" }), _jsx("dd", { children: _jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", "data-topic-sources": true, children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Component" }), _jsx("th", { scope: "col", children: "Topic" }), _jsx("th", { scope: "col", children: "Group" }), _jsx("th", { scope: "col", className: "ac-num", children: "Version" }), _jsx("th", { scope: "col", className: "ac-num", children: "Lag" }), _jsx("th", { scope: "col", children: "Failing" }), _jsx("th", { scope: "col", children: "Retained" })] }) }), _jsx("tbody", { children: s.topicSources.map((t) => (_jsxs("tr", { "data-topic-source": t.component, "data-failing": t.failing ? "yes" : "no", children: [_jsx("td", { children: t.component }), _jsxs("td", { children: [_jsx("code", { children: t.broker ? `${t.topic}@${t.broker}` : t.topic }), t.contract ? ` as ${t.contract}` : ""] }), _jsx("td", { children: _jsx("code", { children: t.group }) }), _jsx("td", { className: "ac-num", children: t.version }), _jsx("td", { className: "ac-num", children: t.lag ?? "—" }), _jsx("td", { children: t.failing ? _jsx("span", { className: "ac-notice", children: t.failing }) : "—" }), _jsx("td", { "data-gap": t.gap ? (t.gap.compacted ? "compacted" : t.gap.gone ? "gone" : "everything") : "unknown", children: t.gap === undefined || t.gap === null ? ("—") : t.gap.compacted ? ("compacted") : !t.gap.gone ? ("everything") : (_jsxs("details", { children: [_jsx("summary", { children: "earlier messages gone" }), _jsx("ul", { className: "ac-topics", children: t.gap.partitions.map((p) => (_jsxs("li", { "data-partition": p.partition, children: ["p", p.partition, " from ", p.beginning, " (", p.earliestRetained ?? "holds nothing", ")"] }, p.partition))) })] })) })] }, t.component))) })] }) }) })] })) : null, s.topicChecks && s.topicChecks.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Topic checks" }), _jsx("dd", { children: _jsx("ul", { className: "ac-topics", children: s.topicChecks.map((c) => (_jsxs("li", { "data-check": c.state, children: [c.component, " ", c.direction, ": ", c.state, c.state === "mismatch" ? ` (${c.stated ?? "none"})` : ""] }, `${c.component}/${c.direction}`))) }) })] })) : null, _jsx("dt", { children: "Runs as" }), _jsx("dd", { children: runsAs(s) }), s.hosting === "web" ? (_jsxs(_Fragment, { children: [_jsx("dt", { children: "Admits" }), _jsx("dd", { children: ["The internet", ...s.callers.map((c) => (c === "*" ? `Every service in ${p.name}` : c))].join(", ") }), _jsx("dt", { children: "Mounts" }), _jsx("dd", { children: s.mounts.length === 0 ? ("None") : (_jsx("ul", { className: "ac-mounts", children: s.mounts.map((m) => (_jsxs("li", { "data-mount": m.path, children: [_jsx("code", { children: m.path }), " \u2192 ", m.service, m.state && m.state !== "ok" ? ` (${m.state})` : ""] }, m.path))) })) })] })) : null, _jsx("dt", { children: "Stopped by" }), _jsx("dd", { children: s.suspended ? "Its organization is disabled" : s.paused ? "Its members paused it" : "Nobody" }), _jsx("dt", { children: "Report" }), _jsx("dd", { children: s.confirmed ? "Confirmed by the cluster" : "The last known state; the cluster has not confirmed it" })] })] }), _jsx(Panels, { kind: "service", entity: s, loaded: panels })] }));
|
|
136
137
|
}
|
|
137
138
|
export const ErrorBoundary = ConsoleErrorBoundary;
|
package/dist/styles.css
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer theme{:root,:host{--ac-spacing:.25rem;--ac-color-mesh-base:#111f26;--ac-color-mesh-slate:#1e2e3a;--ac-color-glow:#d4805857;--ac-color-peach:#deaa8429;--ac-color-dot:#ffffff14;--ac-color-glass:#ffffff0d;--ac-color-glass-strong:#ffffff17;--ac-color-glass-line:#fff3;--ac-color-tile:#ffffff0f;--ac-color-tile-line:#ffffff24;--ac-color-node:#ffffff1a;--ac-color-node-line:#ffffff61;--ac-color-inset:#0003;--ac-color-edge:#ffffffb3;--ac-color-ink:#f5f8f7;--ac-color-ink-2:#dfe8e6;--ac-color-ink-3:#ccd9d6;--ac-color-amber:#f0b83c;--ac-color-amber-ink:#13343b;--ac-color-green:#8fe0ad;--ac-color-red:#ffc4bc;--ac-color-red-wash:#ff8a8029;--ac-shadow-part:0 18px 50px #050f1247;--ac-radius-panel:20px;--ac-radius-card:14px;--ac-radius-control:10px;--ac-radius-node:18px;--ac-font-sans:"Inter Variable", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--ac-font-mono:ui-monospace, "SF Mono", Menlo, Consolas, monospace;--ac-size-rail:56px;--ac-size-panel:232px;--ac-size-inspector:300px;--ac-size-bar:64px}:root:has(.ac-light){--ac-color-mesh-base:#e6eeee;--ac-color-mesh-slate:#cfe0dc;--ac-color-glow:#e0a5264d;--ac-color-peach:#f1d5c2cc;--ac-color-dot:#13343b1a;--ac-color-glass:#ffffff80;--ac-color-glass-strong:#ffffffd9;--ac-color-glass-line:#13343b24;--ac-color-tile:#ffffff80;--ac-color-tile-line:#13343b1a;--ac-color-node:#ffffff9e;--ac-color-node-line:#13343b38;--ac-color-inset:#13343b0f;--ac-color-edge:#13343b8c;--ac-color-ink:#13343b;--ac-color-ink-2:#33504f;--ac-color-ink-3:#4a6465;--ac-color-amber:#e0a526;--ac-color-amber-ink:#13343b;--ac-color-green:#1f6b3a;--ac-color-red:#a8231b;--ac-color-red-wash:#fbe9e7;--ac-shadow-part:0 18px 50px #13343b1a}}@layer base{.ac-root{color-scheme:dark;isolation:isolate;min-height:100vh;color:var(--ac-color-ink);font-family:var(--ac-font-sans);font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased;font-size:.875rem;line-height:1.5;position:relative}.ac-root.ac-light{color-scheme:light}.ac-root *,.ac-root :before,.ac-root :after{box-sizing:border-box}.ac-root h1,.ac-root h2,.ac-root h3,.ac-root p,.ac-root dl,.ac-root dd,.ac-root figure{margin:0}.ac-root h1{letter-spacing:-.01em;text-wrap:balance;font-size:1.5rem;font-weight:600;line-height:1.2}.ac-root h2{font-size:.9375rem;font-weight:600}.ac-root h3{font-size:.875rem;font-weight:600}.ac-root p{max-width:72ch}.ac-root a{color:inherit;-webkit-text-decoration-color:var(--ac-color-ink-3);-webkit-text-decoration-color:var(--ac-color-ink-3);text-decoration-color:var(--ac-color-ink-3);text-underline-offset:.2em}.ac-root a:hover{-webkit-text-decoration-color:var(--ac-color-amber);-webkit-text-decoration-color:var(--ac-color-amber);text-decoration-color:var(--ac-color-amber);text-decoration-thickness:2px}.ac-root :focus-visible{outline:3px solid var(--ac-color-amber);outline-offset:2px;border-radius:4px}.ac-root code,.ac-root pre{font-family:var(--ac-font-mono)}.ac-root input,.ac-root select,.ac-root textarea{font:inherit;color:var(--ac-color-ink);background:var(--ac-color-inset);border:1px solid var(--ac-color-glass-line);border-radius:var(--ac-radius-control);width:100%;padding:.5rem .75rem}.ac-root input::placeholder,.ac-root textarea::placeholder{color:var(--ac-color-ink-3)}.ac-root textarea{font-family:var(--ac-font-mono);min-height:16rem;font-size:.8125rem}.ac-root input[type=checkbox],.ac-root input[type=radio]{width:auto;accent-color:var(--ac-color-amber)}.ac-root input[type=file]{padding:.4rem}.ac-root [aria-invalid=true]{border-color:var(--ac-color-red)}}@layer components{.ac-backdrop{z-index:-1;pointer-events:none;background:radial-gradient(var(--ac-color-dot) 1px, transparent 1.3px) 0 0 / 16px 16px, radial-gradient(42% 46% at 56% 52%, var(--ac-color-glow) 0%, transparent 72%), radial-gradient(40% 50% at 90% 88%, var(--ac-color-peach) 0%, transparent 65%), radial-gradient(55% 60% at 8% 10%, var(--ac-color-mesh-slate) 0%, transparent 70%), linear-gradient(160deg, var(--ac-color-mesh-base), var(--ac-color-mesh-slate));position:fixed;inset:0}.ac-rail,.ac-bar,.ac-listing,.ac-inspector{background:var(--ac-color-glass);-webkit-backdrop-filter:blur(20px)saturate(150%);backdrop-filter:blur(20px)saturate(150%);border:1px solid var(--ac-color-glass-line);border-radius:var(--ac-radius-panel)}@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.ac-rail,.ac-bar,.ac-listing,.ac-inspector,.ac-card,.ac-panel,.ac-part{background:linear-gradient(var(--ac-color-glass), var(--ac-color-glass)), var(--ac-color-mesh-base)}}.ac-shell{--ac-shell-gap:12px;--ac-shell-rail:0px;--ac-shell-listing:0px;--ac-shell-inspector:0px;grid-template-columns:var(--ac-shell-rail) var(--ac-shell-listing) minmax(0, 1fr) var(--ac-shell-inspector);column-gap:0;row-gap:var(--ac-shell-gap);padding:var(--ac-shell-gap);grid-template-rows:auto 1fr;align-items:start;display:grid}.ac-shell:has(>.ac-rail){--ac-shell-rail:calc(var(--ac-size-rail) + var(--ac-shell-gap))}.ac-shell:has(>.ac-listing){--ac-shell-listing:calc(var(--ac-size-panel) + var(--ac-shell-gap))}.ac-shell:has(.ac-inspector){--ac-shell-inspector:calc(var(--ac-size-inspector) + var(--ac-shell-gap))}.ac-rail{top:var(--ac-shell-gap);max-height:calc(100vh - 2 * var(--ac-shell-gap));grid-area:1/1/3;margin-inline-end:var(--ac-shell-gap);position:sticky}.ac-bar{grid-area:1/2/auto/-1}.ac-listing{top:calc(var(--ac-size-bar) + 2 * var(--ac-shell-gap));max-height:calc(100vh - var(--ac-size-bar) - 3 * var(--ac-shell-gap));grid-area:2/2;margin-inline-end:var(--ac-shell-gap);position:sticky}.ac-page{display:contents}.ac-body{flex-direction:column;grid-area:2/3;gap:16px;min-width:0;padding-block-end:24px;display:flex}.ac-inspector{top:calc(var(--ac-size-bar) + 2 * var(--ac-shell-gap));max-height:calc(100vh - var(--ac-size-bar) - 3 * var(--ac-shell-gap));flex-direction:column;grid-area:2/4;gap:14px;margin-inline-start:var(--ac-shell-gap);padding:14px;display:flex;position:sticky;overflow:auto}.ac-rail{flex-direction:column;align-items:center;gap:6px;padding:10px 0;display:flex}.ac-rail-areas{flex-direction:column;align-items:center;gap:6px;margin:0;padding:0;list-style:none;display:flex}.ac-rail-foot{margin-top:auto}.ac-mark{width:40px;height:40px;color:var(--ac-color-ink);place-items:center;margin-bottom:8px;display:grid}.ac-rail-item{width:40px;height:40px;color:var(--ac-color-ink-2);cursor:pointer;background:0 0;border:0;border-radius:12px;place-items:center;padding:0;display:grid}.ac-rail-item svg{width:20px;height:20px}a.ac-rail-item:hover,button.ac-rail-item:hover{background:var(--ac-color-glass-strong);color:var(--ac-color-ink)}.ac-rail-item[aria-current]{background:var(--ac-color-amber);color:var(--ac-color-amber-ink)}.ac-rail-item[aria-disabled=true]{color:var(--ac-color-ink-3);opacity:.5;cursor:default}.ac-bar{min-height:var(--ac-size-bar);grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:center;gap:16px;padding:8px 16px;display:grid}.ac-bar-start,.ac-bar-end{align-items:center;gap:16px;min-width:0;display:flex}.ac-bar-end{justify-content:flex-end}.ac-wordmark{letter-spacing:-.01em;white-space:nowrap;font-size:1rem;font-weight:600}.ac-root a.ac-wordmark{text-decoration:none}.ac-wordmark span{color:var(--ac-color-ink-2);font-weight:400}.ac-person{background:var(--ac-color-glass-strong);border:1px solid var(--ac-color-glass-line);border-radius:50%;flex:none;place-items:center;width:32px;height:32px;font-size:.75rem;font-weight:600;display:grid}.ac-crumbs ol{color:var(--ac-color-ink-2);white-space:nowrap;align-items:center;gap:8px;margin:0;padding:0;list-style:none;display:flex}.ac-crumbs li+li:before{content:"/";color:var(--ac-color-ink-3);margin-right:8px}.ac-root .ac-crumbs a{text-decoration:none}.ac-root .ac-crumbs a:hover{color:var(--ac-color-ink);text-decoration:underline;-webkit-text-decoration-color:var(--ac-color-amber);-webkit-text-decoration-color:var(--ac-color-amber);text-decoration-color:var(--ac-color-amber)}.ac-crumbs [aria-current=page]{color:var(--ac-color-ink);font-weight:500}.ac-listing{flex-direction:column;gap:12px;min-height:0;padding:14px;display:flex}.ac-listing-items{gap:4px;min-height:0;margin:0;padding:0;list-style:none;display:grid;overflow:auto}.ac-listing-items>li:has(>[aria-current=page]){z-index:1;position:sticky;top:0;bottom:0}.ac-listing-item{border-radius:var(--ac-radius-control);background:var(--ac-color-tile);border:1px solid #0000;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:2px 8px;padding:8px 10px;display:grid}.ac-root a.ac-listing-item{text-decoration:none}.ac-listing-item:hover{background:var(--ac-color-glass-strong)}.ac-listing-item[aria-current=page]{background:linear-gradient(var(--ac-color-glass-strong), var(--ac-color-glass-strong)), var(--ac-color-mesh-base);border-color:var(--ac-color-glass-line)}.ac-listing-name{text-overflow:ellipsis;white-space:nowrap;font-weight:500;overflow:hidden}.ac-listing-count{color:var(--ac-color-ink-2);grid-area:1/2/3;font-size:.75rem}.ac-section-title{letter-spacing:.08em;text-transform:uppercase;color:var(--ac-color-ink-3);justify-content:space-between;align-items:center;margin:0;font-size:.6875rem;font-weight:600;display:flex}.ac-seg{background:var(--ac-color-inset);border-radius:999px;grid-auto-columns:1fr;grid-auto-flow:column;padding:3px;display:inline-grid}.ac-seg a{text-align:center;color:var(--ac-color-ink-2);white-space:nowrap;border-radius:999px;padding:6px 14px;font-weight:500}.ac-root .ac-seg a{text-decoration:none}.ac-seg a[aria-current=page]{background:var(--ac-color-glass-strong);color:var(--ac-color-ink);box-shadow:0 1px 2px #0003}.ac-head{flex-wrap:wrap;align-items:center;gap:12px 16px;padding:4px 6px 0;display:flex}.ac-head .ac-seg{margin-left:auto}.ac-lede,.ac-hint,.ac-empty{color:var(--ac-color-ink-2)}.ac-hint{font-size:.8125rem}.ac-card,.ac-panel{background:var(--ac-color-tile);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border:1px solid var(--ac-color-tile-line);border-radius:var(--ac-radius-card);flex-direction:column;gap:12px;min-width:0;padding:16px;display:flex}.ac-panel-failed{color:var(--ac-color-red)}.ac-table-wrap{overflow-x:auto}.ac-table{border-collapse:collapse;width:100%}.ac-table th,.ac-table td{text-align:left;border-top:1px solid var(--ac-color-tile-line);vertical-align:top;padding:9px 12px 9px 0}.ac-table thead th{color:var(--ac-color-ink-2);border-top:0;padding-top:0;font-size:.8125rem;font-weight:500}.ac-table .ac-num{text-align:right}.ac-facts{grid-template-columns:minmax(8rem,max-content) minmax(0,1fr);column-gap:24px;display:grid}.ac-facts dt,.ac-facts dd{border-top:1px solid var(--ac-color-tile-line);padding:9px 0}.ac-facts dt{color:var(--ac-color-ink-2)}.ac-facts dd{overflow-wrap:anywhere}.ac-facts>div{display:contents}.ac-status{white-space:nowrap;align-items:baseline;gap:6px;font-weight:500;display:inline-flex}.ac-status-mark{letter-spacing:-.15em;font-size:.75em}.ac-status-ready .ac-status-mark{color:var(--ac-color-green)}.ac-status-moving .ac-status-mark,.ac-status-partial .ac-status-mark{color:var(--ac-color-amber)}.ac-status-trouble{color:var(--ac-color-red)}.ac-status-stopped .ac-status-mark,.ac-status-idle .ac-status-mark{color:var(--ac-color-ink-3)}.ac-status-note{color:var(--ac-color-ink-2);font-weight:400}.ac-pill{background:var(--ac-color-glass-strong);border:1px solid var(--ac-color-glass-line);border-radius:999px;padding:4px 10px 4px 8px}.ac-live{color:var(--ac-color-ink-2);align-items:center;gap:8px;font-size:.8125rem;display:inline-flex}.ac-live:before{content:"";background:var(--ac-color-amber);border-radius:50%;flex:none;width:8px;height:8px}@media (prefers-reduced-motion:no-preference){.ac-live:before{animation:2.4s ease-out infinite ac-ripple}}.ac-field{gap:4px;min-width:0;max-width:32rem;display:grid}.ac-field label{font-weight:500}.ac-field-error{color:var(--ac-color-red)}.ac-form{gap:16px;display:grid}.ac-inline{flex-wrap:wrap;align-items:end;gap:8px;display:flex}.ac-inline .ac-field{flex:12rem}.ac-inspector .ac-inline{flex-direction:column;align-items:stretch}.ac-inspector .ac-inline .ac-field{flex:none}.ac-inspector .ac-field{max-width:none}.ac-switch{cursor:pointer;align-items:center;gap:10px;display:inline-flex}.ac-root .ac-switch input{opacity:0;width:1px;height:1px;position:absolute}.ac-switch-track{background:var(--ac-color-inset);border:1px solid var(--ac-color-glass-line);border-radius:999px;flex:none;width:40px;height:24px;position:relative}.ac-switch-track:after{content:"";background:var(--ac-color-ink);border-radius:50%;width:18px;height:18px;position:absolute;top:2px;left:2px}.ac-switch input:checked+.ac-switch-track{background:var(--ac-color-amber);border-color:var(--ac-color-amber)}.ac-switch input:checked+.ac-switch-track:after{background:var(--ac-color-amber-ink);transform:translate(16px)}.ac-switch input:focus-visible+.ac-switch-track{outline:3px solid var(--ac-color-amber);outline-offset:2px}@media (prefers-reduced-motion:no-preference){.ac-switch-track,.ac-switch-track:after{transition:background .15s,transform .15s}}.ac-button{font:inherit;border:1px solid var(--ac-color-glass-line);background:var(--ac-color-glass-strong);color:var(--ac-color-ink);cursor:pointer;white-space:nowrap;border-radius:999px;justify-content:center;align-items:center;gap:8px;padding:7px 14px;font-weight:500;display:inline-flex}.ac-root a.ac-button{color:var(--ac-color-ink);text-decoration:none}.ac-button svg{width:16px;height:16px}.ac-button:hover{background:var(--ac-color-glass-line)}.ac-button-primary,.ac-root a.ac-button-primary{background:var(--ac-color-amber);border-color:var(--ac-color-amber);color:var(--ac-color-amber-ink)}.ac-button-primary:hover{background:var(--ac-color-amber)}@supports (color:color-mix(in lab, red, red)){.ac-button-primary:hover{background:color-mix(in srgb, var(--ac-color-amber) 88%, white)}}.ac-button-danger,.ac-root a.ac-button-danger{background:var(--ac-color-red);border-color:var(--ac-color-red);color:var(--ac-color-mesh-base)}.ac-button-danger:hover{background:var(--ac-color-red)}@supports (color:color-mix(in lab, red, red)){.ac-button-danger:hover{background:color-mix(in srgb, var(--ac-color-red) 88%, white)}}.ac-button-quiet{background:0 0}.ac-button-small{padding:4px 10px;font-size:.8125rem}.ac-button[disabled]{opacity:.55;cursor:progress}.ac-actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.ac-actions form{display:inline}.ac-ops{gap:8px;display:grid}.ac-ops>form,.ac-ops>.ac-button,.ac-ops>form>.ac-button{width:100%}.ac-more{border-top:1px solid var(--ac-color-glass-line);padding-top:12px}.ac-more summary{cursor:pointer;font-weight:500}.ac-more[open]>*+*{margin-top:12px}.ac-danger-zone{border-left:3px solid var(--ac-color-red);gap:10px;padding:8px 0 8px 12px;display:grid}.ac-danger-zone p{color:var(--ac-color-ink-2);font-size:.8125rem}.ac-refusal{border-left:3px solid var(--ac-color-red);background:var(--ac-color-red-wash);border-radius:0 var(--ac-radius-control) var(--ac-radius-control) 0;padding:10px 14px}.ac-refusal ul{margin:6px 0 0;padding-left:1.2rem}.ac-notice{border-left:3px solid var(--ac-color-amber);background:var(--ac-color-tile);border-radius:0 var(--ac-radius-control) var(--ac-radius-control) 0;padding:10px 14px}.ac-secret{font-family:var(--ac-font-mono);background:var(--ac-color-inset);border:1px dashed var(--ac-color-ink-3);border-radius:var(--ac-radius-control);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all;padding:10px;display:block}.ac-log{font-family:var(--ac-font-mono);background:var(--ac-color-inset);border:1px solid var(--ac-color-tile-line);border-radius:var(--ac-radius-control);white-space:pre-wrap;overflow-wrap:anywhere;max-height:32rem;margin:0;padding:12px;font-size:.8125rem;overflow:auto}.ac-mounts{gap:4px;margin:0;padding:0;list-style:none;display:grid}.ac-visually-hidden{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.ac-shape{border-radius:var(--ac-radius-panel);border:1px solid var(--ac-color-glass-line);padding:28px 20px 20px}.ac-tree{justify-items:center;max-width:720px;margin:0 auto;display:grid}.ac-row{justify-items:center;width:100%;display:grid}.ac-row-many{gap:24px}.ac-part{background:var(--ac-color-node);-webkit-backdrop-filter:blur(18px)saturate(140%);backdrop-filter:blur(18px)saturate(140%);border:1px solid var(--ac-color-node-line);border-radius:var(--ac-radius-node);width:100%;max-width:300px;box-shadow:var(--ac-shadow-part);grid-template-columns:auto minmax(0,1fr);align-items:center;gap:2px 12px;padding:16px 16px 14px;display:grid;position:relative}.ac-part-self{box-shadow:var(--ac-shadow-part), 0 0 0 2px var(--ac-color-amber), 0 0 24px var(--ac-color-amber)}@supports (color:color-mix(in lab, red, red)){.ac-part-self{box-shadow:var(--ac-shadow-part), 0 0 0 2px var(--ac-color-amber), 0 0 24px color-mix(in srgb, var(--ac-color-amber) 45%, transparent)}}.ac-part-icon{width:40px;height:40px;color:var(--ac-color-ink);grid-row:1/3}.ac-part-icon svg{width:40px;height:40px}.ac-part-title,.ac-part-sub{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.ac-part-title{font-weight:500}.ac-part-sub{color:var(--ac-color-ink-2);font-size:.8125rem}.ac-part-inset{background:var(--ac-color-inset);border-radius:10px;grid-column:1/3;justify-content:space-between;align-items:center;gap:8px;margin-top:10px;padding:7px 12px;font-size:.8125rem;display:flex}.ac-part-up:before,.ac-part-down:after{content:"";background:var(--ac-color-node);border:1px solid var(--ac-color-node-line);width:12px;height:7px;position:absolute;left:50%;transform:translate(-50%)}.ac-part-down:after{border-top:0;border-radius:0 0 7px 7px;bottom:-7px}.ac-part-up:before{border-bottom:0;border-radius:7px 7px 0 0;top:-7px}.ac-part-tab{background:var(--ac-color-node);border:1px solid var(--ac-color-node-line);border-bottom:0;border-radius:12px 12px 0 0;gap:2px;padding:2px 8px 6px;display:flex;position:absolute;top:-27px;left:50%;transform:translate(-50%)}.ac-part-tab form{display:contents}.ac-tab-control{width:24px;height:20px;color:var(--ac-color-ink);cursor:pointer;background:0 0;border:0;border-radius:6px;place-items:center;padding:0;display:grid}.ac-tab-control:hover{background:var(--ac-color-glass-strong)}.ac-tab-control svg{width:14px;height:14px}.ac-part-tabbed{margin-top:27px}.ac-part-tabbed.ac-part-up:before{display:none}.ac-edge{width:100%;height:48px;color:var(--ac-color-edge);display:block;overflow:visible}.ac-edge path{fill:none;stroke:currentColor;stroke-width:1.5px;vector-effect:non-scaling-stroke}.ac-topology{align-items:flex-start;gap:16px;display:flex}.ac-topology-picture{border-radius:var(--ac-radius-panel);border:1px solid var(--ac-color-glass-line);flex:1;min-width:0;padding:8px;overflow-x:auto}.ac-topology-detail{flex:0 0 18rem}.ac-topology-node rect{fill:var(--ac-color-node);stroke:var(--ac-color-node-line);stroke-width:1px}.ac-topology-node{cursor:pointer}.ac-topology-node:focus-visible rect,.ac-topology-selected rect{stroke:var(--ac-color-amber);stroke-width:2px}.ac-topology-node:focus{outline:none}.ac-topology-outside rect,.ac-topology-differs rect{stroke-dasharray:4 3}.ac-topology-platform rect{fill:var(--ac-color-inset)}.ac-topology-name{fill:var(--ac-color-ink);font-size:12px;font-weight:600}.ac-topology-kind{fill:var(--ac-color-ink-2);font-size:11px}.ac-topology-declared{fill:none;stroke:var(--ac-color-edge);stroke-width:1.25px}.ac-topology-call{fill:none;stroke:var(--ac-color-ink);stroke-dasharray:5 4}.ac-topology-warning{stroke:var(--ac-color-red)}.ac-topology-mark{fill:var(--ac-color-red);font-size:14px;font-weight:700}@media (forced-colors:active){.ac-rail,.ac-bar,.ac-listing,.ac-inspector,.ac-card,.ac-panel,.ac-part,.ac-listing-item{border:1px solid canvastext}.ac-button,.ac-rail-item,.ac-seg a{border:1px solid buttontext}.ac-rail-item[aria-current],.ac-seg a[aria-current=page],.ac-listing-item[aria-current=page]{outline:2px solid highlight}}@media (max-width:1180px){.ac-shell,.ac-shell:has(>.ac-listing),.ac-shell:has(.ac-inspector){grid-template-columns:var(--ac-shell-rail) minmax(0, 1fr);grid-template-rows:none;grid-auto-rows:auto}.ac-rail{grid-row:1/span 5}.ac-bar,.ac-listing,.ac-body,.ac-inspector{grid-area:auto/2;max-height:none;margin-inline:0;position:static}.ac-listing-items{grid-template-columns:repeat(auto-fill,minmax(200px,1fr));max-height:18rem}}@media (max-width:720px){.ac-shell,.ac-shell:has(>.ac-rail),.ac-shell:has(>.ac-listing),.ac-shell:has(.ac-inspector){grid-template-columns:minmax(0,1fr)}.ac-rail{flex-flow:wrap;grid-area:auto/1;justify-content:flex-start;max-height:none;margin:0;padding:8px 10px;position:static}.ac-rail-areas{flex-flow:wrap}.ac-mark{margin:0 6px 0 0}.ac-rail-foot{margin-top:0;margin-left:auto}.ac-bar,.ac-listing,.ac-body,.ac-inspector{grid-column:1}.ac-bar{grid-template-columns:minmax(0,1fr) auto}.ac-bar-start{overflow:hidden}.ac-wordmark span{display:none}.ac-crumbs{grid-area:2/1/auto/-1}.ac-crumbs ol{white-space:normal;flex-wrap:wrap;row-gap:2px}.ac-head .ac-seg{width:100%;margin-left:0}.ac-row-many{gap:20px;grid-template-columns:minmax(0,1fr)!important}.ac-edge-split{display:none}.ac-facts{grid-template-columns:minmax(0,1fr)}.ac-facts dd{border-top:0;padding-top:0}.ac-topology{flex-direction:column}.ac-topology-detail{flex-basis:auto;width:100%}}}@layer utilities;@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./fonts/inter-latin-wght-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./fonts/inter-latin-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@keyframes ac-ripple{0%{box-shadow:0 0 0 0 color-mix(in srgb, var(--ac-color-amber) 60%, transparent)}to{box-shadow:0 0 0 .6rem #0000}}
|
|
2
|
+
@layer theme{:root,:host{--ac-spacing:.25rem;--ac-color-mesh-base:#111f26;--ac-color-mesh-slate:#1e2e3a;--ac-color-glow:#d4805857;--ac-color-peach:#deaa8429;--ac-color-dot:#ffffff14;--ac-color-glass:#ffffff0d;--ac-color-glass-strong:#ffffff17;--ac-color-glass-line:#fff3;--ac-color-tile:#ffffff0f;--ac-color-tile-line:#ffffff24;--ac-color-node:#ffffff1a;--ac-color-node-line:#ffffff61;--ac-color-inset:#0003;--ac-color-edge:#ffffffb3;--ac-color-ink:#f5f8f7;--ac-color-ink-2:#dfe8e6;--ac-color-ink-3:#ccd9d6;--ac-color-amber:#f0b83c;--ac-color-amber-ink:#13343b;--ac-color-green:#8fe0ad;--ac-color-red:#ffc4bc;--ac-color-red-wash:#ff8a8029;--ac-shadow-part:0 18px 50px #050f1247;--ac-radius-panel:20px;--ac-radius-card:14px;--ac-radius-control:10px;--ac-radius-node:18px;--ac-font-sans:"Inter Variable", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--ac-font-mono:ui-monospace, "SF Mono", Menlo, Consolas, monospace;--ac-size-rail:56px;--ac-size-panel:232px;--ac-size-inspector:300px;--ac-size-bar:64px}:root:has(.ac-light){--ac-color-mesh-base:#e6eeee;--ac-color-mesh-slate:#cfe0dc;--ac-color-glow:#e0a5264d;--ac-color-peach:#f1d5c2cc;--ac-color-dot:#13343b1a;--ac-color-glass:#ffffff80;--ac-color-glass-strong:#ffffffd9;--ac-color-glass-line:#13343b24;--ac-color-tile:#ffffff80;--ac-color-tile-line:#13343b1a;--ac-color-node:#ffffff9e;--ac-color-node-line:#13343b38;--ac-color-inset:#13343b0f;--ac-color-edge:#13343b8c;--ac-color-ink:#13343b;--ac-color-ink-2:#33504f;--ac-color-ink-3:#4a6465;--ac-color-amber:#e0a526;--ac-color-amber-ink:#13343b;--ac-color-green:#1f6b3a;--ac-color-red:#a8231b;--ac-color-red-wash:#fbe9e7;--ac-shadow-part:0 18px 50px #13343b1a}}@layer base{.ac-root{color-scheme:dark;isolation:isolate;min-height:100vh;color:var(--ac-color-ink);font-family:var(--ac-font-sans);font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased;font-size:.875rem;line-height:1.5;position:relative}.ac-root.ac-light{color-scheme:light}.ac-root *,.ac-root :before,.ac-root :after{box-sizing:border-box}.ac-root h1,.ac-root h2,.ac-root h3,.ac-root p,.ac-root dl,.ac-root dd,.ac-root figure{margin:0}.ac-root h1{letter-spacing:-.01em;text-wrap:balance;font-size:1.5rem;font-weight:600;line-height:1.2}.ac-root h2{font-size:.9375rem;font-weight:600}.ac-root h3{font-size:.875rem;font-weight:600}.ac-root p{max-width:72ch}.ac-root a{color:inherit;-webkit-text-decoration-color:var(--ac-color-ink-3);-webkit-text-decoration-color:var(--ac-color-ink-3);text-decoration-color:var(--ac-color-ink-3);text-underline-offset:.2em}.ac-root a:hover{-webkit-text-decoration-color:var(--ac-color-amber);-webkit-text-decoration-color:var(--ac-color-amber);text-decoration-color:var(--ac-color-amber);text-decoration-thickness:2px}.ac-root :focus-visible{outline:3px solid var(--ac-color-amber);outline-offset:2px;border-radius:4px}.ac-root code,.ac-root pre{font-family:var(--ac-font-mono)}.ac-root input,.ac-root select,.ac-root textarea{font:inherit;color:var(--ac-color-ink);background:var(--ac-color-inset);border:1px solid var(--ac-color-glass-line);border-radius:var(--ac-radius-control);width:100%;padding:.5rem .75rem}.ac-root input::placeholder,.ac-root textarea::placeholder{color:var(--ac-color-ink-3)}.ac-root textarea{font-family:var(--ac-font-mono);min-height:16rem;font-size:.8125rem}.ac-root input[type=checkbox],.ac-root input[type=radio]{width:auto;accent-color:var(--ac-color-amber)}.ac-root input[type=file]{padding:.4rem}.ac-root [aria-invalid=true]{border-color:var(--ac-color-red)}}@layer components{.ac-backdrop{z-index:-1;pointer-events:none;background:radial-gradient(var(--ac-color-dot) 1px, transparent 1.3px) 0 0 / 16px 16px, radial-gradient(42% 46% at 56% 52%, var(--ac-color-glow) 0%, transparent 72%), radial-gradient(40% 50% at 90% 88%, var(--ac-color-peach) 0%, transparent 65%), radial-gradient(55% 60% at 8% 10%, var(--ac-color-mesh-slate) 0%, transparent 70%), linear-gradient(160deg, var(--ac-color-mesh-base), var(--ac-color-mesh-slate));position:fixed;inset:0}.ac-rail,.ac-bar,.ac-listing,.ac-inspector{background:var(--ac-color-glass);-webkit-backdrop-filter:blur(20px)saturate(150%);backdrop-filter:blur(20px)saturate(150%);border:1px solid var(--ac-color-glass-line);border-radius:var(--ac-radius-panel)}@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.ac-rail,.ac-bar,.ac-listing,.ac-inspector,.ac-card,.ac-panel,.ac-part{background:linear-gradient(var(--ac-color-glass), var(--ac-color-glass)), var(--ac-color-mesh-base)}}.ac-shell{--ac-shell-gap:12px;--ac-shell-rail:0px;--ac-shell-listing:0px;--ac-shell-inspector:0px;grid-template-columns:var(--ac-shell-rail) var(--ac-shell-listing) minmax(0, 1fr) var(--ac-shell-inspector);column-gap:0;row-gap:var(--ac-shell-gap);padding:var(--ac-shell-gap);grid-template-rows:auto 1fr;align-items:start;display:grid}.ac-shell:has(>.ac-rail){--ac-shell-rail:calc(var(--ac-size-rail) + var(--ac-shell-gap))}.ac-shell:has(>.ac-listing){--ac-shell-listing:calc(var(--ac-size-panel) + var(--ac-shell-gap))}.ac-shell:has(.ac-inspector){--ac-shell-inspector:calc(var(--ac-size-inspector) + var(--ac-shell-gap))}.ac-rail{top:var(--ac-shell-gap);max-height:calc(100vh - 2 * var(--ac-shell-gap));grid-area:1/1/3;margin-inline-end:var(--ac-shell-gap);position:sticky}.ac-bar{grid-area:1/2/auto/-1}.ac-listing{top:calc(var(--ac-size-bar) + 2 * var(--ac-shell-gap));max-height:calc(100vh - var(--ac-size-bar) - 3 * var(--ac-shell-gap));grid-area:2/2;margin-inline-end:var(--ac-shell-gap);position:sticky}.ac-page{display:contents}.ac-body{flex-direction:column;grid-area:2/3;gap:16px;min-width:0;padding-block-end:24px;display:flex}.ac-inspector{top:calc(var(--ac-size-bar) + 2 * var(--ac-shell-gap));max-height:calc(100vh - var(--ac-size-bar) - 3 * var(--ac-shell-gap));flex-direction:column;grid-area:2/4;gap:14px;margin-inline-start:var(--ac-shell-gap);padding:14px;display:flex;position:sticky;overflow:auto}.ac-rail{flex-direction:column;align-items:center;gap:6px;padding:10px 0;display:flex}.ac-rail-areas{flex-direction:column;align-items:center;gap:6px;margin:0;padding:0;list-style:none;display:flex}.ac-rail-foot{margin-top:auto}.ac-mark{width:40px;height:40px;color:var(--ac-color-ink);place-items:center;margin-bottom:8px;display:grid}.ac-mark-image{background-color:currentColor;width:32px;height:32px;-webkit-mask:url(./ankka-mark.png) 50%/contain no-repeat;mask:url(./ankka-mark.png) 50%/contain no-repeat}.ac-rail-item{width:40px;height:40px;color:var(--ac-color-ink-2);cursor:pointer;background:0 0;border:0;border-radius:12px;place-items:center;padding:0;display:grid}.ac-rail-item svg{width:20px;height:20px}a.ac-rail-item:hover,button.ac-rail-item:hover{background:var(--ac-color-glass-strong);color:var(--ac-color-ink)}.ac-rail-item[aria-current]{background:var(--ac-color-amber);color:var(--ac-color-amber-ink)}.ac-rail-item[aria-disabled=true]{color:var(--ac-color-ink-3);opacity:.5;cursor:default}.ac-bar{min-height:var(--ac-size-bar);grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:center;gap:16px;padding:8px 16px;display:grid}.ac-bar-start,.ac-bar-end{align-items:center;gap:16px;min-width:0;display:flex}.ac-bar-end{justify-content:flex-end}.ac-wordmark{letter-spacing:-.01em;white-space:nowrap;font-size:1rem;font-weight:600}.ac-root a.ac-wordmark{text-decoration:none}.ac-wordmark span{color:var(--ac-color-ink-2);font-weight:400}.ac-person{background:var(--ac-color-glass-strong);border:1px solid var(--ac-color-glass-line);border-radius:50%;flex:none;place-items:center;width:32px;height:32px;font-size:.75rem;font-weight:600;display:grid}.ac-crumbs ol{color:var(--ac-color-ink-2);white-space:nowrap;align-items:center;gap:8px;margin:0;padding:0;list-style:none;display:flex}.ac-crumbs li+li:before{content:"/";color:var(--ac-color-ink-3);margin-right:8px}.ac-root .ac-crumbs a{text-decoration:none}.ac-root .ac-crumbs a:hover{color:var(--ac-color-ink);text-decoration:underline;-webkit-text-decoration-color:var(--ac-color-amber);-webkit-text-decoration-color:var(--ac-color-amber);text-decoration-color:var(--ac-color-amber)}.ac-crumbs [aria-current=page]{color:var(--ac-color-ink);font-weight:500}.ac-listing{flex-direction:column;gap:12px;min-height:0;padding:14px;display:flex}.ac-listing-items{gap:4px;min-height:0;margin:0;padding:0;list-style:none;display:grid;overflow:auto}.ac-listing-items>li:has(>[aria-current=page]){z-index:1;position:sticky;top:0;bottom:0}.ac-listing-item{border-radius:var(--ac-radius-control);background:var(--ac-color-tile);border:1px solid #0000;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:2px 8px;padding:8px 10px;display:grid}.ac-root a.ac-listing-item{text-decoration:none}.ac-listing-item:hover{background:var(--ac-color-glass-strong)}.ac-listing-item[aria-current=page]{background:linear-gradient(var(--ac-color-glass-strong), var(--ac-color-glass-strong)), var(--ac-color-mesh-base);border-color:var(--ac-color-glass-line)}.ac-listing-name{text-overflow:ellipsis;white-space:nowrap;font-weight:500;overflow:hidden}.ac-listing-count{color:var(--ac-color-ink-2);grid-area:1/2/3;font-size:.75rem}.ac-section-title{letter-spacing:.08em;text-transform:uppercase;color:var(--ac-color-ink-3);justify-content:space-between;align-items:center;margin:0;font-size:.6875rem;font-weight:600;display:flex}.ac-seg{background:var(--ac-color-inset);border-radius:999px;grid-auto-columns:1fr;grid-auto-flow:column;padding:3px;display:inline-grid}.ac-seg a{text-align:center;color:var(--ac-color-ink-2);white-space:nowrap;border-radius:999px;padding:6px 14px;font-weight:500}.ac-root .ac-seg a{text-decoration:none}.ac-seg a[aria-current=page]{background:var(--ac-color-glass-strong);color:var(--ac-color-ink);box-shadow:0 1px 2px #0003}.ac-head{flex-wrap:wrap;align-items:center;gap:12px 16px;padding:4px 6px 0;display:flex}.ac-head .ac-seg{margin-left:auto}.ac-lede,.ac-hint,.ac-empty{color:var(--ac-color-ink-2)}.ac-hint{font-size:.8125rem}.ac-card,.ac-panel{background:var(--ac-color-tile);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);border:1px solid var(--ac-color-tile-line);border-radius:var(--ac-radius-card);flex-direction:column;gap:12px;min-width:0;padding:16px;display:flex}.ac-panel-failed{color:var(--ac-color-red)}.ac-table-wrap{overflow-x:auto}.ac-table{border-collapse:collapse;width:100%}.ac-table th,.ac-table td{text-align:left;border-top:1px solid var(--ac-color-tile-line);vertical-align:top;padding:9px 12px 9px 0}.ac-table thead th{color:var(--ac-color-ink-2);border-top:0;padding-top:0;font-size:.8125rem;font-weight:500}.ac-table .ac-num{text-align:right}.ac-facts{grid-template-columns:minmax(8rem,max-content) minmax(0,1fr);column-gap:24px;display:grid}.ac-facts dt,.ac-facts dd{border-top:1px solid var(--ac-color-tile-line);padding:9px 0}.ac-facts dt{color:var(--ac-color-ink-2)}.ac-facts dd{overflow-wrap:anywhere}.ac-facts>div{display:contents}.ac-status{white-space:nowrap;align-items:baseline;gap:6px;font-weight:500;display:inline-flex}.ac-status-mark{letter-spacing:-.15em;font-size:.75em}.ac-status-ready .ac-status-mark{color:var(--ac-color-green)}.ac-status-moving .ac-status-mark,.ac-status-partial .ac-status-mark{color:var(--ac-color-amber)}.ac-status-trouble{color:var(--ac-color-red)}.ac-status-stopped .ac-status-mark,.ac-status-idle .ac-status-mark{color:var(--ac-color-ink-3)}.ac-status-note{color:var(--ac-color-ink-2);font-weight:400}.ac-pill{background:var(--ac-color-glass-strong);border:1px solid var(--ac-color-glass-line);border-radius:999px;padding:4px 10px 4px 8px}.ac-live{color:var(--ac-color-ink-2);align-items:center;gap:8px;font-size:.8125rem;display:inline-flex}.ac-live:before{content:"";background:var(--ac-color-amber);border-radius:50%;flex:none;width:8px;height:8px}@media (prefers-reduced-motion:no-preference){.ac-live:before{animation:2.4s ease-out infinite ac-ripple}}.ac-field{gap:4px;min-width:0;max-width:32rem;display:grid}.ac-field label{font-weight:500}.ac-field-error{color:var(--ac-color-red)}.ac-form{gap:16px;display:grid}.ac-inline{flex-wrap:wrap;align-items:end;gap:8px;display:flex}.ac-inline .ac-field{flex:12rem}.ac-inspector .ac-inline{flex-direction:column;align-items:stretch}.ac-inspector .ac-inline .ac-field{flex:none}.ac-inspector .ac-field{max-width:none}.ac-switch{cursor:pointer;align-items:center;gap:10px;display:inline-flex}.ac-root .ac-switch input{opacity:0;width:1px;height:1px;position:absolute}.ac-switch-track{background:var(--ac-color-inset);border:1px solid var(--ac-color-glass-line);border-radius:999px;flex:none;width:40px;height:24px;position:relative}.ac-switch-track:after{content:"";background:var(--ac-color-ink);border-radius:50%;width:18px;height:18px;position:absolute;top:2px;left:2px}.ac-switch input:checked+.ac-switch-track{background:var(--ac-color-amber);border-color:var(--ac-color-amber)}.ac-switch input:checked+.ac-switch-track:after{background:var(--ac-color-amber-ink);transform:translate(16px)}.ac-switch input:focus-visible+.ac-switch-track{outline:3px solid var(--ac-color-amber);outline-offset:2px}@media (prefers-reduced-motion:no-preference){.ac-switch-track,.ac-switch-track:after{transition:background .15s,transform .15s}}.ac-button{font:inherit;border:1px solid var(--ac-color-glass-line);background:var(--ac-color-glass-strong);color:var(--ac-color-ink);cursor:pointer;white-space:nowrap;border-radius:999px;justify-content:center;align-items:center;gap:8px;padding:7px 14px;font-weight:500;display:inline-flex}.ac-root a.ac-button{color:var(--ac-color-ink);text-decoration:none}.ac-button svg{width:16px;height:16px}.ac-button:hover{background:var(--ac-color-glass-line)}.ac-button-primary,.ac-root a.ac-button-primary{background:var(--ac-color-amber);border-color:var(--ac-color-amber);color:var(--ac-color-amber-ink)}.ac-button-primary:hover{background:var(--ac-color-amber)}@supports (color:color-mix(in lab, red, red)){.ac-button-primary:hover{background:color-mix(in srgb, var(--ac-color-amber) 88%, white)}}.ac-button-danger,.ac-root a.ac-button-danger{background:var(--ac-color-red);border-color:var(--ac-color-red);color:var(--ac-color-mesh-base)}.ac-button-danger:hover{background:var(--ac-color-red)}@supports (color:color-mix(in lab, red, red)){.ac-button-danger:hover{background:color-mix(in srgb, var(--ac-color-red) 88%, white)}}.ac-button-quiet{background:0 0}.ac-button-small{padding:4px 10px;font-size:.8125rem}.ac-button[disabled]{opacity:.55;cursor:progress}.ac-actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.ac-actions form{display:inline}.ac-ops{gap:8px;display:grid}.ac-ops>form,.ac-ops>.ac-button,.ac-ops>form>.ac-button{width:100%}.ac-more{border-top:1px solid var(--ac-color-glass-line);padding-top:12px}.ac-more summary{cursor:pointer;font-weight:500}.ac-more[open]>*+*{margin-top:12px}.ac-danger-zone{border-left:3px solid var(--ac-color-red);gap:10px;padding:8px 0 8px 12px;display:grid}.ac-danger-zone p{color:var(--ac-color-ink-2);font-size:.8125rem}.ac-refusal{border-left:3px solid var(--ac-color-red);background:var(--ac-color-red-wash);border-radius:0 var(--ac-radius-control) var(--ac-radius-control) 0;padding:10px 14px}.ac-refusal ul{margin:6px 0 0;padding-left:1.2rem}.ac-notice{border-left:3px solid var(--ac-color-amber);background:var(--ac-color-tile);border-radius:0 var(--ac-radius-control) var(--ac-radius-control) 0;padding:10px 14px}.ac-secret{font-family:var(--ac-font-mono);background:var(--ac-color-inset);border:1px dashed var(--ac-color-ink-3);border-radius:var(--ac-radius-control);overflow-wrap:anywhere;-webkit-user-select:all;user-select:all;padding:10px;display:block}.ac-log{font-family:var(--ac-font-mono);background:var(--ac-color-inset);border:1px solid var(--ac-color-tile-line);border-radius:var(--ac-radius-control);white-space:pre-wrap;overflow-wrap:anywhere;max-height:32rem;margin:0;padding:12px;font-size:.8125rem;overflow:auto}.ac-mounts{gap:4px;margin:0;padding:0;list-style:none;display:grid}.ac-visually-hidden{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.ac-shape{border-radius:var(--ac-radius-panel);border:1px solid var(--ac-color-glass-line);padding:28px 20px 20px}.ac-tree{justify-items:center;max-width:720px;margin:0 auto;display:grid}.ac-row{justify-items:center;width:100%;display:grid}.ac-row-many{gap:24px}.ac-part{background:var(--ac-color-node);-webkit-backdrop-filter:blur(18px)saturate(140%);backdrop-filter:blur(18px)saturate(140%);border:1px solid var(--ac-color-node-line);border-radius:var(--ac-radius-node);width:100%;max-width:300px;box-shadow:var(--ac-shadow-part);grid-template-columns:auto minmax(0,1fr);align-items:center;gap:2px 12px;padding:16px 16px 14px;display:grid;position:relative}.ac-part-self{box-shadow:var(--ac-shadow-part), 0 0 0 2px var(--ac-color-amber), 0 0 24px var(--ac-color-amber)}@supports (color:color-mix(in lab, red, red)){.ac-part-self{box-shadow:var(--ac-shadow-part), 0 0 0 2px var(--ac-color-amber), 0 0 24px color-mix(in srgb, var(--ac-color-amber) 45%, transparent)}}.ac-part-icon{width:40px;height:40px;color:var(--ac-color-ink);grid-row:1/3}.ac-part-icon svg{width:40px;height:40px}.ac-part-title,.ac-part-sub{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.ac-part-title{font-weight:500}.ac-part-sub{color:var(--ac-color-ink-2);font-size:.8125rem}.ac-part-inset{background:var(--ac-color-inset);border-radius:10px;grid-column:1/3;justify-content:space-between;align-items:center;gap:8px;margin-top:10px;padding:7px 12px;font-size:.8125rem;display:flex}.ac-part-up:before,.ac-part-down:after{content:"";background:var(--ac-color-node);border:1px solid var(--ac-color-node-line);width:12px;height:7px;position:absolute;left:50%;transform:translate(-50%)}.ac-part-down:after{border-top:0;border-radius:0 0 7px 7px;bottom:-7px}.ac-part-up:before{border-bottom:0;border-radius:7px 7px 0 0;top:-7px}.ac-part-tab{background:var(--ac-color-node);border:1px solid var(--ac-color-node-line);border-bottom:0;border-radius:12px 12px 0 0;gap:2px;padding:2px 8px 6px;display:flex;position:absolute;top:-27px;left:50%;transform:translate(-50%)}.ac-part-tab form{display:contents}.ac-tab-control{width:24px;height:20px;color:var(--ac-color-ink);cursor:pointer;background:0 0;border:0;border-radius:6px;place-items:center;padding:0;display:grid}.ac-tab-control:hover{background:var(--ac-color-glass-strong)}.ac-tab-control svg{width:14px;height:14px}.ac-part-tabbed{margin-top:27px}.ac-part-tabbed.ac-part-up:before{display:none}.ac-edge{width:100%;height:48px;color:var(--ac-color-edge);display:block;overflow:visible}.ac-edge path{fill:none;stroke:currentColor;stroke-width:1.5px;vector-effect:non-scaling-stroke}.ac-topology{align-items:flex-start;gap:16px;display:flex}.ac-topology-picture{border-radius:var(--ac-radius-panel);border:1px solid var(--ac-color-glass-line);flex:1;min-width:0;padding:8px;overflow-x:auto}.ac-topology-detail{flex:0 0 18rem}.ac-topology-node rect{fill:var(--ac-color-node);stroke:var(--ac-color-node-line);stroke-width:1px}.ac-topology-node{cursor:pointer}.ac-topology-node:focus-visible rect,.ac-topology-selected rect{stroke:var(--ac-color-amber);stroke-width:2px}.ac-topology-node:focus{outline:none}.ac-topology-outside rect,.ac-topology-differs rect{stroke-dasharray:4 3}.ac-topology-platform rect{fill:var(--ac-color-inset)}.ac-topology-name{fill:var(--ac-color-ink);font-size:12px;font-weight:600}.ac-topology-kind{fill:var(--ac-color-ink-2);font-size:11px}.ac-topology-declared{fill:none;stroke:var(--ac-color-edge);stroke-width:1.25px}.ac-topology-call{fill:none;stroke:var(--ac-color-ink);stroke-dasharray:5 4}.ac-topology-warning{stroke:var(--ac-color-red)}.ac-topology-mark{fill:var(--ac-color-red);font-size:14px;font-weight:700}@media (forced-colors:active){.ac-rail,.ac-bar,.ac-listing,.ac-inspector,.ac-card,.ac-panel,.ac-part,.ac-listing-item{border:1px solid canvastext}.ac-button,.ac-rail-item,.ac-seg a{border:1px solid buttontext}.ac-rail-item[aria-current],.ac-seg a[aria-current=page],.ac-listing-item[aria-current=page]{outline:2px solid highlight}}@media (max-width:1180px){.ac-shell,.ac-shell:has(>.ac-listing),.ac-shell:has(.ac-inspector){grid-template-columns:var(--ac-shell-rail) minmax(0, 1fr);grid-template-rows:none;grid-auto-rows:auto}.ac-rail{grid-row:1/span 5}.ac-bar,.ac-listing,.ac-body,.ac-inspector{grid-area:auto/2;max-height:none;margin-inline:0;position:static}.ac-listing-items{grid-template-columns:repeat(auto-fill,minmax(200px,1fr));max-height:18rem}}@media (max-width:720px){.ac-shell,.ac-shell:has(>.ac-rail),.ac-shell:has(>.ac-listing),.ac-shell:has(.ac-inspector){grid-template-columns:minmax(0,1fr)}.ac-rail{flex-flow:wrap;grid-area:auto/1;justify-content:flex-start;max-height:none;margin:0;padding:8px 10px;position:static}.ac-rail-areas{flex-flow:wrap}.ac-mark{margin:0 6px 0 0}.ac-rail-foot{margin-top:0;margin-left:auto}.ac-bar,.ac-listing,.ac-body,.ac-inspector{grid-column:1}.ac-bar{grid-template-columns:minmax(0,1fr) auto}.ac-bar-start{overflow:hidden}.ac-wordmark span{display:none}.ac-crumbs{grid-area:2/1/auto/-1}.ac-crumbs ol{white-space:normal;flex-wrap:wrap;row-gap:2px}.ac-head .ac-seg{width:100%;margin-left:0}.ac-row-many{gap:20px;grid-template-columns:minmax(0,1fr)!important}.ac-edge-split{display:none}.ac-facts{grid-template-columns:minmax(0,1fr)}.ac-facts dd{border-top:0;padding-top:0}.ac-topology{flex-direction:column}.ac-topology-detail{flex-basis:auto;width:100%}}}@layer utilities;@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./fonts/inter-latin-wght-normal.woff2)format("woff2-variations");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(./fonts/inter-latin-ext-wght-normal.woff2)format("woff2-variations");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@keyframes ac-ripple{0%{box-shadow:0 0 0 0 color-mix(in srgb, var(--ac-color-amber) 60%, transparent)}to{box-shadow:0 0 0 .6rem #0000}}
|
|
@@ -204,6 +204,16 @@ interface TopicCheckRecord {
|
|
|
204
204
|
stated?: string;
|
|
205
205
|
state: string;
|
|
206
206
|
}
|
|
207
|
+
/** A named bucket as the operator reports it (feature 055). */
|
|
208
|
+
export interface BucketRecord {
|
|
209
|
+
name: string;
|
|
210
|
+
phase: string;
|
|
211
|
+
store?: string;
|
|
212
|
+
bucket?: string;
|
|
213
|
+
exposure: string;
|
|
214
|
+
publicAddress?: string;
|
|
215
|
+
kept?: boolean;
|
|
216
|
+
}
|
|
207
217
|
interface Service {
|
|
208
218
|
name: string;
|
|
209
219
|
projectId: string;
|
|
@@ -273,6 +283,8 @@ interface Service {
|
|
|
273
283
|
bucketLocation?: string;
|
|
274
284
|
/** Where a move of its bucket from Garage is, as the control plane phrases it. */
|
|
275
285
|
storageMove?: string;
|
|
286
|
+
/** Its named buckets as the operator would report them (feature 055), kept ones last. */
|
|
287
|
+
buckets?: BucketRecord[];
|
|
276
288
|
/** What the instances report when asked for the topology; generated from the service when unset. */
|
|
277
289
|
topology?: FakeTopology;
|
|
278
290
|
}
|
|
@@ -445,6 +457,8 @@ export interface FakeSeed {
|
|
|
445
457
|
/** The store its bucket is in, `garage` or `gcs`. */
|
|
446
458
|
objectStore?: string;
|
|
447
459
|
bucketLocation?: string;
|
|
460
|
+
/** Its named buckets as the operator reports them (feature 055). */
|
|
461
|
+
buckets?: BucketRecord[];
|
|
448
462
|
}[];
|
|
449
463
|
/** Project secrets, by name and entry: a value each, never listed. */
|
|
450
464
|
secrets?: {
|
|
@@ -165,6 +165,25 @@ export async function fakeControlPlane(options = {}) {
|
|
|
165
165
|
s.provisionObjectStorage = d.service?.provisionObjectStorage ?? false;
|
|
166
166
|
s.exposeObjectStorage = d.service?.exposeObjectStorage ?? false;
|
|
167
167
|
s.ownObjectStore = (d.service?.env ?? []).some((e) => e.name.startsWith("ANKKA_S3_"));
|
|
168
|
+
// Named buckets (feature 055): one report each, and one the descriptor stopped naming is kept.
|
|
169
|
+
const named = (d.service?.buckets ?? []).map((b) => {
|
|
170
|
+
if (b.supplied)
|
|
171
|
+
return { name: b.name, phase: "Supplied", bucket: b.supplied.bucket, exposure: "supplied" };
|
|
172
|
+
const exposure = b.exposure ?? "private";
|
|
173
|
+
const bucket = `${s.projectId}.${s.name}.${b.name}`;
|
|
174
|
+
return {
|
|
175
|
+
name: b.name,
|
|
176
|
+
phase: "Provisioned",
|
|
177
|
+
store: "garage",
|
|
178
|
+
bucket,
|
|
179
|
+
exposure,
|
|
180
|
+
...(exposure === "private" ? {} : { publicAddress: `https://storage.${options.baseDomain ?? "example.test"}/${bucket}` }),
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
const dropped = (s.buckets ?? [])
|
|
184
|
+
.filter((b) => b.phase !== "Supplied" && !named.some((n) => n.name === b.name))
|
|
185
|
+
.map((b) => ({ ...b, phase: "Kept", kept: true }));
|
|
186
|
+
s.buckets = [...named, ...dropped];
|
|
168
187
|
if (s.provisionObjectStorage && !s.objectStore) {
|
|
169
188
|
s.objectStore = objectStore;
|
|
170
189
|
if (objectStore === "gcs")
|
|
@@ -222,6 +241,7 @@ export async function fakeControlPlane(options = {}) {
|
|
|
222
241
|
bucketLocation: s.provisionObjectStorage && s.objectStore === "gcs" ? (s.bucketLocation ?? null) : null,
|
|
223
242
|
softDeleteDays: s.provisionObjectStorage && s.objectStore === "gcs" ? 7 : null,
|
|
224
243
|
storageMove: s.storageMove ?? null,
|
|
244
|
+
...(s.buckets && s.buckets.length > 0 ? { buckets: s.buckets } : {}),
|
|
225
245
|
customHostnames: (s.customHostnames ?? []).map((hostname) => ({
|
|
226
246
|
hostname,
|
|
227
247
|
// The fake has no authority to wait for: an exposed service's hostnames serve at once.
|
|
@@ -363,6 +383,10 @@ export async function fakeControlPlane(options = {}) {
|
|
|
363
383
|
...(cloud ? { cloud: { ...where, ...(kmsKey && owns ? { kmsKey } : {}) } } : {}),
|
|
364
384
|
// Feature 038: where secrets are kept, as an installation that has said nothing answers.
|
|
365
385
|
secrets: { backend: "postgres", recordRetention: "365d", auditLog: "unknown" },
|
|
386
|
+
// Spec 057: a one-node broker and no bound on retention, as the shipped settings say; no
|
|
387
|
+
// erasure, which the platform does not have yet.
|
|
388
|
+
broker: { nodes: 1, defaultCopies: 1, minInSync: 1 },
|
|
389
|
+
retention: { unbounded: true },
|
|
366
390
|
// Feature 041: where the backups go, as an installation with Garage and no copy says it.
|
|
367
391
|
backups: {
|
|
368
392
|
backupTarget: "object-store",
|
|
@@ -1827,6 +1851,7 @@ export async function fakeControlPlane(options = {}) {
|
|
|
1827
1851
|
ownObjectStore: s.ownObjectStore,
|
|
1828
1852
|
objectStore: s.objectStore,
|
|
1829
1853
|
bucketLocation: s.bucketLocation,
|
|
1854
|
+
buckets: s.buckets,
|
|
1830
1855
|
});
|
|
1831
1856
|
}
|
|
1832
1857
|
for (const sec of seed.secrets ?? []) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { BucketReport } from "../client/schemas.ts";
|
|
2
|
+
/** One row of a service's named buckets, as the service page shows it (feature 055). */
|
|
3
|
+
export interface BucketRow {
|
|
4
|
+
name: string;
|
|
5
|
+
/** The exposure, `supplied` for a bucket the developer made, or `kept` for one no longer named. */
|
|
6
|
+
exposure: string;
|
|
7
|
+
/** Its name in the store, when reported. */
|
|
8
|
+
bucket: string | null;
|
|
9
|
+
/** Where it is on the internet, as a link, when it is. */
|
|
10
|
+
address: string | null;
|
|
11
|
+
/** Said of a bucket the descriptor no longer names, which is kept rather than deleted. */
|
|
12
|
+
note: string | null;
|
|
13
|
+
}
|
|
14
|
+
export declare function bucketRows(buckets: readonly BucketReport[] | null | undefined): BucketRow[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function bucketRows(buckets) {
|
|
2
|
+
return (buckets ?? []).map((b) => ({
|
|
3
|
+
name: b.name,
|
|
4
|
+
exposure: b.kept ? "kept" : b.phase === "Supplied" || b.exposure === "supplied" ? "supplied" : b.exposure,
|
|
5
|
+
bucket: b.bucket ?? null,
|
|
6
|
+
address: b.kept ? null : (b.publicAddress ?? null),
|
|
7
|
+
note: b.kept ? "kept, no longer named" : null,
|
|
8
|
+
}));
|
|
9
|
+
}
|
package/dist/ui/shell.js
CHANGED
|
@@ -15,8 +15,12 @@ export function Shell({ children, className, theme = "dark" }) {
|
|
|
15
15
|
export function Backdrop() {
|
|
16
16
|
return _jsx("div", { className: "ac-backdrop", "aria-hidden": "true" });
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* The mark: the duck, as a mask over the current colour, so it follows `--ac-color-ink` and a host's
|
|
20
|
+
* override of it in either theme with one asset. The build copies the image beside the stylesheet.
|
|
21
|
+
*/
|
|
18
22
|
function Mark() {
|
|
19
|
-
return (
|
|
23
|
+
return _jsx("span", { className: "ac-mark-image", "aria-hidden": "true" });
|
|
20
24
|
}
|
|
21
25
|
const initials = (name) => name
|
|
22
26
|
.split(/[\s@.]+/)
|
|
@@ -38,10 +38,10 @@ export function Graph({ shown, differs, selected, onSelect, }) {
|
|
|
38
38
|
.filter(Boolean)
|
|
39
39
|
.join(" ");
|
|
40
40
|
const kind = kindInWords(n.kind) + (n.platform ? ", platform" : "") + (differs.has(n.id) ? ", not on every instance" : "");
|
|
41
|
-
return (_jsxs("g", { className: classes, transform: `translate(${x} ${y})`, tabIndex: 0, role: "button",
|
|
41
|
+
return (_jsxs("g", { className: classes, transform: `translate(${x} ${y})`, tabIndex: 0, role: "button", onClick: () => onSelect(n.id), onKeyDown: (e) => {
|
|
42
42
|
if (e.key === "Enter" || e.key === " ")
|
|
43
43
|
onSelect(n.id);
|
|
44
|
-
}, children: [_jsx("rect", { width: GRID.width, height: GRID.height, rx: 12, filter: "url(#ac-topology-shadow)" }), _jsx("text", { x: 10, y: 16, className: "ac-topology-name", children: clip(n.label, 22) }), _jsx("text", { x: 10, y: 30, className: "ac-topology-kind", children: clip(kind, 28) })] }, n.id));
|
|
44
|
+
}, children: [_jsx("title", { children: `${n.label}: ${kind}` }), _jsx("rect", { width: GRID.width, height: GRID.height, rx: 12, filter: "url(#ac-topology-shadow)" }), _jsx("text", { x: 10, y: 16, className: "ac-topology-name", "aria-hidden": "true", children: clip(n.label, 22) }), _jsx("text", { x: 10, y: 30, className: "ac-topology-kind", "aria-hidden": "true", children: clip(kind, 28) })] }, n.id));
|
|
45
45
|
};
|
|
46
46
|
return (_jsxs("svg", { className: "ac-topology-graph", viewBox: `0 0 ${width} ${height}`, width: width, height: height, role: "group", "aria-label": describe(shown), children: [_jsx("defs", { children: _jsx("filter", { id: "ac-topology-shadow", x: "-20%", y: "-30%", width: "140%", height: "180%", children: _jsx("feDropShadow", { dx: "0", dy: "6", stdDeviation: "8", floodColor: "#05090b", floodOpacity: "0.28" }) }) }), shown.declared.map((e) => {
|
|
47
47
|
const p = path(e.from, e.to, 0);
|
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
* read. Handled and unanswered are separate columns, because they are separate facts.
|
|
4
4
|
*/
|
|
5
5
|
import type { Pair, View } from "./layout.ts";
|
|
6
|
+
/**
|
|
7
|
+
* A handler as the table names it: a tool, an agent's or an MCP endpoint's, is marked with a tool
|
|
8
|
+
* glyph and the word, so an MCP endpoint's tools read apart from its routes, to a screen reader too.
|
|
9
|
+
*/
|
|
10
|
+
export declare function handlerInWords(h: {
|
|
11
|
+
name: string;
|
|
12
|
+
type: string;
|
|
13
|
+
}): string;
|
|
6
14
|
export declare function duration(pair: Pair): string;
|
|
7
15
|
export declare function Table({ shown, differs }: {
|
|
8
16
|
shown: View;
|
|
@@ -5,10 +5,17 @@ function nameOf(shown, id) {
|
|
|
5
5
|
function kindInWords(kind) {
|
|
6
6
|
return kind.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* A handler as the table names it: a tool, an agent's or an MCP endpoint's, is marked with a tool
|
|
10
|
+
* glyph and the word, so an MCP endpoint's tools read apart from its routes, to a screen reader too.
|
|
11
|
+
*/
|
|
12
|
+
export function handlerInWords(h) {
|
|
13
|
+
return h.type === "tool" ? `🔧 ${h.name} (tool)` : h.name;
|
|
14
|
+
}
|
|
8
15
|
export function duration(pair) {
|
|
9
16
|
const d = pair.durationMillis;
|
|
10
17
|
return d ? `~${d.p50} / ~${d.p99} / ~${d.max} ms` : "";
|
|
11
18
|
}
|
|
12
19
|
export function Table({ shown, differs }) {
|
|
13
|
-
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", "aria-label": "Components", children: [_jsx("caption", { className: "ac-visually-hidden", children: "Components" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Name" }), _jsx("th", { scope: "col", children: "Kind" }), _jsx("th", { scope: "col", children: "Handlers" })] }) }), _jsx("tbody", { children: shown.nodes.map((n) => (_jsxs("tr", { "data-node": n.id, children: [_jsx("td", { children: n.label }), _jsxs("td", { children: [kindInWords(n.kind), n.platform ? ", platform" : "", differs.has(n.id) ? `, only on ${differs.get(n.id).join(", ")}` : ""] }), _jsx("td", { children: n.handlers.map(
|
|
20
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", "aria-label": "Components", children: [_jsx("caption", { className: "ac-visually-hidden", children: "Components" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Name" }), _jsx("th", { scope: "col", children: "Kind" }), _jsx("th", { scope: "col", children: "Handlers" })] }) }), _jsx("tbody", { children: shown.nodes.map((n) => (_jsxs("tr", { "data-node": n.id, children: [_jsx("td", { children: n.label }), _jsxs("td", { children: [kindInWords(n.kind), n.platform ? ", platform" : "", differs.has(n.id) ? `, only on ${differs.get(n.id).join(", ")}` : ""] }), _jsx("td", { children: n.handlers.map(handlerInWords).join(", ") })] }, n.id))) })] }) }), shown.declared.length > 0 ? (_jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", "aria-label": "Declared connections", children: [_jsx("caption", { className: "ac-visually-hidden", children: "Declared connections" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "From" }), _jsx("th", { scope: "col", children: "To" }), _jsx("th", { scope: "col", children: "As" })] }) }), _jsx("tbody", { children: shown.declared.map((e) => (_jsxs("tr", { children: [_jsx("td", { children: nameOf(shown, e.from) }), _jsx("td", { children: nameOf(shown, e.to) }), _jsx("td", { children: e.kind })] }, `${e.from}>${e.to}:${e.kind}`))) })] }) })) : null, shown.calls.length > 0 ? (_jsx("div", { className: "ac-table-wrap", children: _jsxs("table", { className: "ac-table", "aria-label": "Observed calls", children: [_jsx("caption", { className: "ac-visually-hidden", children: "Observed calls" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "From" }), _jsx("th", { scope: "col", children: "To" }), _jsx("th", { scope: "col", children: "Handler to handler" }), _jsx("th", { scope: "col", className: "ac-num", children: "Ok" }), _jsx("th", { scope: "col", className: "ac-num", children: "Refused" }), _jsx("th", { scope: "col", className: "ac-num", children: "Failed" }), _jsx("th", { scope: "col", className: "ac-num", children: "Timed out" }), _jsx("th", { scope: "col", className: "ac-num", children: "Undelivered" }), _jsx("th", { scope: "col", children: "p50 / p99 / max" })] }) }), _jsx("tbody", { children: shown.calls.flatMap((c) => c.pairs.map((p) => (_jsxs("tr", { "data-pair": `${p.caller} -> ${p.callee}`, children: [_jsx("td", { children: nameOf(shown, c.from) }), _jsx("td", { children: nameOf(shown, c.to) }), _jsxs("td", { children: [p.caller, " \u2192 ", p.callee, p.streaming ? " (stream)" : ""] }), _jsx("td", { className: "ac-num", children: p.handled?.ok ?? 0 }), _jsx("td", { className: "ac-num", children: p.handled?.refused ?? 0 }), _jsx("td", { className: "ac-num", children: p.handled?.failed ?? 0 }), _jsx("td", { className: "ac-num", children: p.unanswered?.timedOut ?? 0 }), _jsx("td", { className: "ac-num", children: p.unanswered?.undelivered ?? 0 }), _jsx("td", { children: duration(p) })] }, `${c.from}>${c.to}:${p.caller}>${p.callee}`)))) })] }) })) : null] }));
|
|
14
21
|
}
|
package/dist/ui/use-stream.d.ts
CHANGED
|
@@ -85,6 +85,16 @@ export declare function useProjectStream(projectId: string, initial: ServiceStat
|
|
|
85
85
|
bucketLocation: string | undefined;
|
|
86
86
|
softDeleteDays: number | undefined;
|
|
87
87
|
storageMove: string | undefined;
|
|
88
|
+
buckets: {
|
|
89
|
+
name: string;
|
|
90
|
+
phase: string;
|
|
91
|
+
store: string | undefined;
|
|
92
|
+
bucket: string | undefined;
|
|
93
|
+
exposure: string;
|
|
94
|
+
publicAddress: string | undefined;
|
|
95
|
+
kept: boolean;
|
|
96
|
+
detail: string | undefined;
|
|
97
|
+
}[] | undefined;
|
|
88
98
|
databaseCluster: string | undefined;
|
|
89
99
|
grants: string | undefined;
|
|
90
100
|
crossProjectTopics: {
|
|
@@ -208,6 +218,16 @@ export declare function useServiceStream(projectId: string, name: string, initia
|
|
|
208
218
|
bucketLocation: string | undefined;
|
|
209
219
|
softDeleteDays: number | undefined;
|
|
210
220
|
storageMove: string | undefined;
|
|
221
|
+
buckets: {
|
|
222
|
+
name: string;
|
|
223
|
+
phase: string;
|
|
224
|
+
store: string | undefined;
|
|
225
|
+
bucket: string | undefined;
|
|
226
|
+
exposure: string;
|
|
227
|
+
publicAddress: string | undefined;
|
|
228
|
+
kept: boolean;
|
|
229
|
+
detail: string | undefined;
|
|
230
|
+
}[] | undefined;
|
|
211
231
|
databaseCluster: string | undefined;
|
|
212
232
|
grants: string | undefined;
|
|
213
233
|
crossProjectTopics: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ankka-console",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "The ankka console as a package: the control plane client, sign-in and sessions, and the pages as routes a React Router host mounts.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -52,13 +52,13 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"class-variance-authority": "^0.7.1",
|
|
54
54
|
"clsx": "^2.1.1",
|
|
55
|
-
"jose": "^6.2.
|
|
56
|
-
"lucide-react": "^1.
|
|
55
|
+
"jose": "^6.2.13",
|
|
56
|
+
"lucide-react": "^1.61.0",
|
|
57
57
|
"openid-client": "^6.8.8",
|
|
58
|
-
"zod": "^4.6.
|
|
58
|
+
"zod": "^4.6.7"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@react-router/dev": "^8.
|
|
61
|
+
"@react-router/dev": "^8.5.0",
|
|
62
62
|
"@react-router/node": "^8.4.0",
|
|
63
63
|
"react": "^19.2.7",
|
|
64
64
|
"react-dom": "^19.2.7",
|
|
@@ -71,17 +71,17 @@
|
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@fontsource-variable/inter": "^5.3.0",
|
|
74
|
-
"@react-router/dev": "^8.
|
|
74
|
+
"@react-router/dev": "^8.5.0",
|
|
75
75
|
"@react-router/node": "^8.4.0",
|
|
76
76
|
"@tailwindcss/cli": "^4.3.3",
|
|
77
|
-
"@types/node": "^26.6.
|
|
77
|
+
"@types/node": "^26.6.5",
|
|
78
78
|
"@types/react": "^19.3.0",
|
|
79
79
|
"@types/react-dom": "^19.3.0",
|
|
80
|
-
"react": "^19.3.
|
|
81
|
-
"react-dom": "^19.3.
|
|
80
|
+
"react": "^19.3.1",
|
|
81
|
+
"react-dom": "^19.3.1",
|
|
82
82
|
"react-router": "^8.4.0",
|
|
83
83
|
"tailwindcss": "^4.3.3",
|
|
84
84
|
"typescript": "^7.0.2",
|
|
85
|
-
"vite": "^8.3.
|
|
85
|
+
"vite": "^8.3.5"
|
|
86
86
|
}
|
|
87
87
|
}
|