@woosau/dsh-custom-env 0.1.6 → 0.1.9
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/README.md +28 -9
- package/README.zh-CN.md +28 -9
- package/lib/client.js +980 -289
- package/lib/index.js +288 -11
- package/lib/typert.host.js +407 -465
- package/lib/typert.remote-client.d.ts +2 -1
- package/lib/typert.remote-client.js +371 -373
- package/lib/types/client/EnvSettingsSection.d.ts +7 -3
- package/lib/types/client/env-row-select.d.ts +36 -0
- package/lib/types/client/locales.d.ts +22 -2
- package/lib/types/client/parse-env-paste.d.ts +21 -0
- package/lib/types/group-ids.d.ts +5 -0
- package/lib/types/groups-store.d.ts +73 -0
- package/lib/types/index.d.ts +40 -6
- package/lib/types/types.d.ts +22 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -179,18 +179,27 @@ var ResultValue = class {
|
|
|
179
179
|
};
|
|
180
180
|
|
|
181
181
|
// lib/typert.remote-client.js
|
|
182
|
+
var envGroupSchema = () => import_zod.z.object({
|
|
183
|
+
id: import_zod.z.string().readonly(),
|
|
184
|
+
title: import_zod.z.string().readonly()
|
|
185
|
+
}).readonly();
|
|
186
|
+
var envEntrySchema = () => import_zod.z.object({
|
|
187
|
+
id: import_zod.z.string().readonly(),
|
|
188
|
+
name: import_zod.z.string().readonly(),
|
|
189
|
+
value: import_zod.z.string().readonly(),
|
|
190
|
+
groupId: import_zod.z.string().readonly(),
|
|
191
|
+
kind: import_zod.z.enum(["unchanged", "modified", "added"]).readonly(),
|
|
192
|
+
previous: import_zod.z.string().nullable().readonly()
|
|
193
|
+
}).readonly();
|
|
182
194
|
var list$result$schema$value;
|
|
183
195
|
var list$result$schema = () => list$result$schema$value ??= import_zod.z.object({
|
|
184
196
|
path: import_zod.z.string().readonly(),
|
|
185
197
|
exists: import_zod.z.boolean().readonly(),
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
name: import_zod.z.string().readonly(),
|
|
189
|
-
value: import_zod.z.string().readonly(),
|
|
190
|
-
kind: import_zod.z.enum(["unchanged", "modified", "added"]).readonly(),
|
|
191
|
-
previous: import_zod.z.string().nullable().readonly()
|
|
192
|
-
}).readonly()).readonly()
|
|
198
|
+
groups: import_zod.z.array(envGroupSchema()).readonly(),
|
|
199
|
+
entries: import_zod.z.array(envEntrySchema()).readonly()
|
|
193
200
|
});
|
|
201
|
+
var envGroup$result$schema$value;
|
|
202
|
+
var envGroup$result$schema = () => envGroup$result$schema$value ??= envGroupSchema();
|
|
194
203
|
var cliStatus$result$schema$value;
|
|
195
204
|
var cliStatus$result$schema = () => cliStatus$result$schema$value ??= import_zod.z.object({
|
|
196
205
|
platform: import_zod.z.string().readonly(),
|
|
@@ -201,38 +210,38 @@ var cliStatus$result$schema = () => cliStatus$result$schema$value ??= import_zod
|
|
|
201
210
|
canInstall: import_zod.z.boolean().readonly(),
|
|
202
211
|
reason: import_zod.z.string().nullable().readonly()
|
|
203
212
|
});
|
|
204
|
-
var
|
|
205
|
-
var upsert$parameter$0$schema = () => upsert$parameter$0$schema$value ??= import_zod.z.string();
|
|
206
|
-
var upsert$parameter$1$schema$value;
|
|
207
|
-
var upsert$parameter$1$schema = () => upsert$parameter$1$schema$value ??= import_zod.z.string();
|
|
208
|
-
var upsert$parameter$2$schema$value;
|
|
209
|
-
var upsert$parameter$2$schema = () => upsert$parameter$2$schema$value ??= import_zod.z.string();
|
|
210
|
-
var remove$parameter$0$schema$value;
|
|
211
|
-
var remove$parameter$0$schema = () => remove$parameter$0$schema$value ??= import_zod.z.string();
|
|
212
|
-
var setVar$parameter$0$schema$value;
|
|
213
|
-
var setVar$parameter$0$schema = () => setVar$parameter$0$schema$value ??= import_zod.z.string();
|
|
214
|
-
var setVar$parameter$1$schema$value;
|
|
215
|
-
var setVar$parameter$1$schema = () => setVar$parameter$1$schema$value ??= import_zod.z.string();
|
|
213
|
+
var str = () => import_zod.z.string();
|
|
216
214
|
var setVars$parameter$0$schema$value;
|
|
217
215
|
var setVars$parameter$0$schema = () => setVars$parameter$0$schema$value ??= import_zod.z.array(import_zod.z.object({
|
|
218
216
|
name: import_zod.z.string().readonly(),
|
|
219
|
-
value: import_zod.z.string().readonly()
|
|
217
|
+
value: import_zod.z.string().readonly(),
|
|
218
|
+
group: import_zod.z.string().optional()
|
|
220
219
|
}).readonly()).readonly();
|
|
221
|
-
var removeVar$parameter$0$schema$value;
|
|
222
|
-
var removeVar$parameter$0$schema = () => removeVar$parameter$0$schema$value ??= import_zod.z.string();
|
|
223
220
|
var removeVars$parameter$0$schema$value;
|
|
224
221
|
var removeVars$parameter$0$schema = () => removeVars$parameter$0$schema$value ??= import_zod.z.array(import_zod.z.string()).readonly();
|
|
222
|
+
var deleteGroup$parameter$1$schema$value;
|
|
223
|
+
var deleteGroup$parameter$1$schema = () => deleteGroup$parameter$1$schema$value ??= import_zod.z.object({
|
|
224
|
+
moveToDefault: import_zod.z.boolean().readonly()
|
|
225
|
+
}).readonly();
|
|
225
226
|
var envVarWriteJsonSchema = {
|
|
226
227
|
type: "object",
|
|
227
228
|
properties: {
|
|
228
229
|
name: { type: "string" },
|
|
229
|
-
value: { type: "string" }
|
|
230
|
+
value: { type: "string" },
|
|
231
|
+
group: { type: "string" }
|
|
230
232
|
},
|
|
231
233
|
required: ["name", "value"],
|
|
232
234
|
additionalProperties: false
|
|
233
235
|
};
|
|
234
|
-
var
|
|
235
|
-
|
|
236
|
+
var envGroupJsonSchema = {
|
|
237
|
+
type: "object",
|
|
238
|
+
properties: {
|
|
239
|
+
id: { type: "string" },
|
|
240
|
+
title: { type: "string" }
|
|
241
|
+
},
|
|
242
|
+
required: ["id", "title"],
|
|
243
|
+
additionalProperties: true
|
|
244
|
+
};
|
|
236
245
|
var cliStatusJsonSchema = {
|
|
237
246
|
type: "object",
|
|
238
247
|
properties: {
|
|
@@ -252,6 +261,10 @@ var envSnapshotJsonSchema = {
|
|
|
252
261
|
properties: {
|
|
253
262
|
path: { type: "string" },
|
|
254
263
|
exists: { type: "boolean" },
|
|
264
|
+
groups: {
|
|
265
|
+
type: "array",
|
|
266
|
+
items: envGroupJsonSchema
|
|
267
|
+
},
|
|
255
268
|
entries: {
|
|
256
269
|
type: "array",
|
|
257
270
|
items: {
|
|
@@ -260,90 +273,84 @@ var envSnapshotJsonSchema = {
|
|
|
260
273
|
id: { type: "string" },
|
|
261
274
|
name: { type: "string" },
|
|
262
275
|
value: { type: "string" },
|
|
276
|
+
groupId: { type: "string" },
|
|
263
277
|
kind: { type: "string", enum: ["unchanged", "modified", "added"] },
|
|
264
278
|
previous: { type: ["string", "null"] }
|
|
265
279
|
},
|
|
266
|
-
required: ["id", "name", "value", "kind", "previous"],
|
|
280
|
+
required: ["id", "name", "value", "groupId", "kind", "previous"],
|
|
267
281
|
additionalProperties: true
|
|
268
282
|
}
|
|
269
283
|
}
|
|
270
284
|
},
|
|
271
|
-
required: ["path", "exists", "entries"],
|
|
285
|
+
required: ["path", "exists", "groups", "entries"],
|
|
272
286
|
additionalProperties: true
|
|
273
287
|
};
|
|
288
|
+
var stringParam = (name, description, options = {}) => ({
|
|
289
|
+
name,
|
|
290
|
+
description,
|
|
291
|
+
source: "json",
|
|
292
|
+
...options.acceptsUndefined ? { acceptsUndefined: true } : {},
|
|
293
|
+
codec: {
|
|
294
|
+
mode: "strict",
|
|
295
|
+
typeSymbol: "string",
|
|
296
|
+
create: str,
|
|
297
|
+
jsonSchema: { type: "string" }
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
var snapshotResult = (description = "updated snapshot.") => ({
|
|
301
|
+
mode: "strict",
|
|
302
|
+
typeSymbol: "@woosau/dsh-custom-env/types#EnvSnapshot",
|
|
303
|
+
create: list$result$schema,
|
|
304
|
+
description,
|
|
305
|
+
jsonSchema: envSnapshotJsonSchema
|
|
306
|
+
});
|
|
307
|
+
var groupResult = (description = "group record.") => ({
|
|
308
|
+
mode: "strict",
|
|
309
|
+
typeSymbol: "@woosau/dsh-custom-env/types#EnvGroup",
|
|
310
|
+
create: envGroup$result$schema,
|
|
311
|
+
description,
|
|
312
|
+
jsonSchema: envGroupJsonSchema
|
|
313
|
+
});
|
|
314
|
+
var voidResult = {
|
|
315
|
+
mode: "strict",
|
|
316
|
+
typeSymbol: "void",
|
|
317
|
+
create: () => import_zod.z.undefined(),
|
|
318
|
+
description: "no return value.",
|
|
319
|
+
jsonSchema: { type: "null" }
|
|
320
|
+
};
|
|
321
|
+
var src = { file: "src/index.ts", line: 1, column: 1 };
|
|
274
322
|
var TYPERT_REMOTE = createTypertRemoteInfo({
|
|
275
323
|
package: "@woosau/dsh-custom-env",
|
|
276
324
|
methods: {
|
|
277
325
|
"customEnv/list": {
|
|
278
326
|
service: "customEnv",
|
|
279
|
-
description: "List current $DSH_HOME/.env entries with pending classification.",
|
|
327
|
+
description: "List current $DSH_HOME/.env entries with groups and pending classification.",
|
|
280
328
|
invocation: { kind: "direct" },
|
|
281
329
|
parameters: [],
|
|
282
|
-
result:
|
|
283
|
-
|
|
284
|
-
typeSymbol: "@woosau/dsh-custom-env/types#EnvSnapshot",
|
|
285
|
-
create: list$result$schema,
|
|
286
|
-
description: "path, existence, and sorted entries.",
|
|
287
|
-
jsonSchema: envSnapshotJsonSchema
|
|
288
|
-
},
|
|
289
|
-
sourceLocation: { file: "src/index.ts", line: 1, column: 1 }
|
|
330
|
+
result: snapshotResult("path, existence, groups, and sorted entries."),
|
|
331
|
+
sourceLocation: src
|
|
290
332
|
},
|
|
291
333
|
"customEnv/upsert": {
|
|
292
334
|
service: "customEnv",
|
|
293
|
-
description: "Create or update one row. Empty id creates a new row;
|
|
335
|
+
description: "Create or update one row. Empty id creates a new row; optional groupId assigns membership.",
|
|
294
336
|
invocation: { kind: "direct" },
|
|
295
337
|
parameters: [
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
codec: {
|
|
301
|
-
mode: "strict",
|
|
302
|
-
typeSymbol: "string",
|
|
303
|
-
create: upsert$parameter$0$schema,
|
|
304
|
-
jsonSchema: { type: "string" }
|
|
305
|
-
}
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
name: "name",
|
|
309
|
-
description: "writable variable name.",
|
|
310
|
-
source: "json",
|
|
311
|
-
codec: {
|
|
312
|
-
mode: "strict",
|
|
313
|
-
typeSymbol: "string",
|
|
314
|
-
create: upsert$parameter$1$schema,
|
|
315
|
-
jsonSchema: { type: "string" }
|
|
316
|
-
}
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
name: "value",
|
|
320
|
-
description: "value (empty string allowed).",
|
|
321
|
-
source: "json",
|
|
322
|
-
codec: {
|
|
323
|
-
mode: "strict",
|
|
324
|
-
typeSymbol: "string",
|
|
325
|
-
create: upsert$parameter$2$schema,
|
|
326
|
-
jsonSchema: { type: "string" }
|
|
327
|
-
}
|
|
328
|
-
}
|
|
338
|
+
stringParam("id", "stable row id from list(), or empty string for a new row."),
|
|
339
|
+
stringParam("name", "writable variable name."),
|
|
340
|
+
stringParam("value", "value (empty string allowed)."),
|
|
341
|
+
stringParam("groupId", "target group id for create/move (optional).", { acceptsUndefined: true })
|
|
329
342
|
],
|
|
330
|
-
result:
|
|
331
|
-
|
|
332
|
-
typeSymbol: "@woosau/dsh-custom-env/types#EnvSnapshot",
|
|
333
|
-
create: list$result$schema,
|
|
334
|
-
description: "updated snapshot.",
|
|
335
|
-
jsonSchema: envSnapshotJsonSchema
|
|
336
|
-
},
|
|
337
|
-
sourceLocation: { file: "src/index.ts", line: 1, column: 1 }
|
|
343
|
+
result: snapshotResult(),
|
|
344
|
+
sourceLocation: src
|
|
338
345
|
},
|
|
339
346
|
"customEnv/setVars": {
|
|
340
347
|
service: "customEnv",
|
|
341
|
-
description: "Create or replace many variables by name in one rewrite.
|
|
348
|
+
description: "Create or replace many variables by name in one rewrite. Optional group per entry.",
|
|
342
349
|
invocation: { kind: "direct" },
|
|
343
350
|
parameters: [
|
|
344
351
|
{
|
|
345
352
|
name: "entries",
|
|
346
|
-
description: "name/value pairs (last duplicate name wins).",
|
|
353
|
+
description: "name/value pairs with optional group (last duplicate name wins).",
|
|
347
354
|
source: "json",
|
|
348
355
|
codec: {
|
|
349
356
|
mode: "strict",
|
|
@@ -353,51 +360,20 @@ var TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
353
360
|
}
|
|
354
361
|
}
|
|
355
362
|
],
|
|
356
|
-
result:
|
|
357
|
-
|
|
358
|
-
typeSymbol: "void",
|
|
359
|
-
create: () => import_zod.z.undefined(),
|
|
360
|
-
description: "no return value.",
|
|
361
|
-
jsonSchema: { type: "null" }
|
|
362
|
-
},
|
|
363
|
-
sourceLocation: { file: "src/index.ts", line: 1, column: 1 }
|
|
363
|
+
result: voidResult,
|
|
364
|
+
sourceLocation: src
|
|
364
365
|
},
|
|
365
366
|
"customEnv/setVar": {
|
|
366
367
|
service: "customEnv",
|
|
367
|
-
description: "Create or replace one variable by name.
|
|
368
|
+
description: "Create or replace one variable by name. Optional group: new names default to default; existing keep group when omitted.",
|
|
368
369
|
invocation: { kind: "direct" },
|
|
369
370
|
parameters: [
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
source: "json",
|
|
374
|
-
codec: {
|
|
375
|
-
mode: "strict",
|
|
376
|
-
typeSymbol: "string",
|
|
377
|
-
create: setVar$parameter$0$schema,
|
|
378
|
-
jsonSchema: { type: "string" }
|
|
379
|
-
}
|
|
380
|
-
},
|
|
381
|
-
{
|
|
382
|
-
name: "value",
|
|
383
|
-
description: "value to store (empty string allowed).",
|
|
384
|
-
source: "json",
|
|
385
|
-
codec: {
|
|
386
|
-
mode: "strict",
|
|
387
|
-
typeSymbol: "string",
|
|
388
|
-
create: setVar$parameter$1$schema,
|
|
389
|
-
jsonSchema: { type: "string" }
|
|
390
|
-
}
|
|
391
|
-
}
|
|
371
|
+
stringParam("name", "writable variable name."),
|
|
372
|
+
stringParam("value", "value to store (empty string allowed)."),
|
|
373
|
+
stringParam("group", "optional group id; omit to keep existing membership.", { acceptsUndefined: true })
|
|
392
374
|
],
|
|
393
|
-
result:
|
|
394
|
-
|
|
395
|
-
typeSymbol: "void",
|
|
396
|
-
create: () => import_zod.z.undefined(),
|
|
397
|
-
description: "no return value.",
|
|
398
|
-
jsonSchema: { type: "null" }
|
|
399
|
-
},
|
|
400
|
-
sourceLocation: { file: "src/index.ts", line: 1, column: 1 }
|
|
375
|
+
result: voidResult,
|
|
376
|
+
sourceLocation: src
|
|
401
377
|
},
|
|
402
378
|
"customEnv/removeVars": {
|
|
403
379
|
service: "customEnv",
|
|
@@ -423,24 +399,14 @@ var TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
423
399
|
description: "number of .env lines removed.",
|
|
424
400
|
jsonSchema: { type: "number" }
|
|
425
401
|
},
|
|
426
|
-
sourceLocation:
|
|
402
|
+
sourceLocation: src
|
|
427
403
|
},
|
|
428
404
|
"customEnv/removeVar": {
|
|
429
405
|
service: "customEnv",
|
|
430
406
|
description: "Remove one variable by name from the file, Host, and OS user environment.",
|
|
431
407
|
invocation: { kind: "direct" },
|
|
432
408
|
parameters: [
|
|
433
|
-
|
|
434
|
-
name: "name",
|
|
435
|
-
description: "writable variable name.",
|
|
436
|
-
source: "json",
|
|
437
|
-
codec: {
|
|
438
|
-
mode: "strict",
|
|
439
|
-
typeSymbol: "string",
|
|
440
|
-
create: removeVar$parameter$0$schema,
|
|
441
|
-
jsonSchema: { type: "string" }
|
|
442
|
-
}
|
|
443
|
-
}
|
|
409
|
+
stringParam("name", "writable variable name.")
|
|
444
410
|
],
|
|
445
411
|
result: {
|
|
446
412
|
mode: "strict",
|
|
@@ -449,59 +415,85 @@ var TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
449
415
|
description: "true when a .env line was removed.",
|
|
450
416
|
jsonSchema: { type: "boolean" }
|
|
451
417
|
},
|
|
452
|
-
sourceLocation:
|
|
418
|
+
sourceLocation: src
|
|
453
419
|
},
|
|
454
420
|
"customEnv/deleteEntry": {
|
|
455
421
|
service: "customEnv",
|
|
456
422
|
description: "Delete one entry from the file, Host, and OS user environment.",
|
|
457
423
|
invocation: { kind: "direct" },
|
|
458
424
|
parameters: [
|
|
459
|
-
|
|
460
|
-
name: "id",
|
|
461
|
-
description: "stable row id from list().",
|
|
462
|
-
source: "json",
|
|
463
|
-
codec: {
|
|
464
|
-
mode: "strict",
|
|
465
|
-
typeSymbol: "string",
|
|
466
|
-
create: remove$parameter$0$schema,
|
|
467
|
-
jsonSchema: { type: "string" }
|
|
468
|
-
}
|
|
469
|
-
}
|
|
425
|
+
stringParam("id", "stable row id from list().")
|
|
470
426
|
],
|
|
471
|
-
result:
|
|
472
|
-
|
|
473
|
-
typeSymbol: "@woosau/dsh-custom-env/types#EnvSnapshot",
|
|
474
|
-
create: list$result$schema,
|
|
475
|
-
description: "updated snapshot.",
|
|
476
|
-
jsonSchema: envSnapshotJsonSchema
|
|
477
|
-
},
|
|
478
|
-
sourceLocation: { file: "src/index.ts", line: 1, column: 1 }
|
|
427
|
+
result: snapshotResult(),
|
|
428
|
+
sourceLocation: src
|
|
479
429
|
},
|
|
480
430
|
"customEnv/restore": {
|
|
481
431
|
service: "customEnv",
|
|
482
432
|
description: "Restore Host-start original name+value for this id, or delete if added after start.",
|
|
483
433
|
invocation: { kind: "direct" },
|
|
484
434
|
parameters: [
|
|
435
|
+
stringParam("id", "stable row id from list().")
|
|
436
|
+
],
|
|
437
|
+
result: snapshotResult(),
|
|
438
|
+
sourceLocation: src
|
|
439
|
+
},
|
|
440
|
+
"customEnv/createGroup": {
|
|
441
|
+
service: "customEnv",
|
|
442
|
+
description: "Create a custom environment variable group.",
|
|
443
|
+
invocation: { kind: "direct" },
|
|
444
|
+
parameters: [
|
|
445
|
+
stringParam("title", "non-empty display title.")
|
|
446
|
+
],
|
|
447
|
+
result: groupResult("created group."),
|
|
448
|
+
sourceLocation: src
|
|
449
|
+
},
|
|
450
|
+
"customEnv/renameGroup": {
|
|
451
|
+
service: "customEnv",
|
|
452
|
+
description: "Rename a custom group (not the default group).",
|
|
453
|
+
invocation: { kind: "direct" },
|
|
454
|
+
parameters: [
|
|
455
|
+
stringParam("id", "group id."),
|
|
456
|
+
stringParam("title", "new non-empty title.")
|
|
457
|
+
],
|
|
458
|
+
result: groupResult("renamed group."),
|
|
459
|
+
sourceLocation: src
|
|
460
|
+
},
|
|
461
|
+
"customEnv/deleteGroup": {
|
|
462
|
+
service: "customEnv",
|
|
463
|
+
description: "Delete a custom group; optionally move members to default or remove their variables.",
|
|
464
|
+
invocation: { kind: "direct" },
|
|
465
|
+
parameters: [
|
|
466
|
+
stringParam("id", "group id (not default)."),
|
|
485
467
|
{
|
|
486
|
-
name: "
|
|
487
|
-
description: "
|
|
468
|
+
name: "options",
|
|
469
|
+
description: "moveToDefault controls whether members are kept.",
|
|
488
470
|
source: "json",
|
|
489
471
|
codec: {
|
|
490
472
|
mode: "strict",
|
|
491
|
-
typeSymbol: "
|
|
492
|
-
create:
|
|
493
|
-
jsonSchema: {
|
|
473
|
+
typeSymbol: "DeleteGroupOptions",
|
|
474
|
+
create: deleteGroup$parameter$1$schema,
|
|
475
|
+
jsonSchema: {
|
|
476
|
+
type: "object",
|
|
477
|
+
properties: { moveToDefault: { type: "boolean" } },
|
|
478
|
+
required: ["moveToDefault"],
|
|
479
|
+
additionalProperties: false
|
|
480
|
+
}
|
|
494
481
|
}
|
|
495
482
|
}
|
|
496
483
|
],
|
|
497
|
-
result:
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
},
|
|
504
|
-
|
|
484
|
+
result: snapshotResult(),
|
|
485
|
+
sourceLocation: src
|
|
486
|
+
},
|
|
487
|
+
"customEnv/moveEntry": {
|
|
488
|
+
service: "customEnv",
|
|
489
|
+
description: "Move one row into another group.",
|
|
490
|
+
invocation: { kind: "direct" },
|
|
491
|
+
parameters: [
|
|
492
|
+
stringParam("id", "stable row id from list()."),
|
|
493
|
+
stringParam("groupId", "target group id.")
|
|
494
|
+
],
|
|
495
|
+
result: snapshotResult(),
|
|
496
|
+
sourceLocation: src
|
|
505
497
|
},
|
|
506
498
|
"customEnv/cliStatus": {
|
|
507
499
|
service: "customEnv",
|
|
@@ -515,7 +507,7 @@ var TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
515
507
|
description: "active path, expected path, and whether Install should be offered.",
|
|
516
508
|
jsonSchema: cliStatusJsonSchema
|
|
517
509
|
},
|
|
518
|
-
sourceLocation:
|
|
510
|
+
sourceLocation: src
|
|
519
511
|
},
|
|
520
512
|
"customEnv/cliInstall": {
|
|
521
513
|
service: "customEnv",
|
|
@@ -529,7 +521,7 @@ var TYPERT_REMOTE = createTypertRemoteInfo({
|
|
|
529
521
|
description: "refreshed status after install.",
|
|
530
522
|
jsonSchema: cliStatusJsonSchema
|
|
531
523
|
},
|
|
532
|
-
sourceLocation:
|
|
524
|
+
sourceLocation: src
|
|
533
525
|
}
|
|
534
526
|
}
|
|
535
527
|
}, import_zod.z);
|
|
@@ -539,6 +531,9 @@ var typert_remote_client_default = TYPERT_REMOTE;
|
|
|
539
531
|
var import_react = require("react");
|
|
540
532
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
541
533
|
|
|
534
|
+
// src/group-ids.ts
|
|
535
|
+
var DEFAULT_GROUP_ID = "default";
|
|
536
|
+
|
|
542
537
|
// src/client/format-remote-error.ts
|
|
543
538
|
function isRemoteFailure(value) {
|
|
544
539
|
return typeof value === "object" && value !== null && value.isDSHRemoteError === true && typeof value.code === "string";
|
|
@@ -547,26 +542,121 @@ function formatRemoteError(error, t) {
|
|
|
547
542
|
if (isRemoteFailure(error)) {
|
|
548
543
|
if (error.code === "custom-env/invalid-name") return t("error.invalidName");
|
|
549
544
|
if (error.code === "custom-env/invalid-value") return t("error.invalidValue");
|
|
545
|
+
if (error.code === "custom-env/invalid-group") return t("error.invalidGroup");
|
|
550
546
|
if (error.code === "custom-env/restore-failed") return t("error.restoreFailed");
|
|
551
547
|
if (error.code === "custom-env/cli-install-failed") return t("error.cliInstall");
|
|
552
548
|
}
|
|
553
549
|
return t("error.generic");
|
|
554
550
|
}
|
|
555
551
|
|
|
552
|
+
// src/client/parse-env-paste.ts
|
|
553
|
+
var NAME_OK = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
554
|
+
function parseEnvPaste(text) {
|
|
555
|
+
const lastByName = /* @__PURE__ */ new Map();
|
|
556
|
+
const order = [];
|
|
557
|
+
for (const rawLine of text.split(/\r\n|\n|\r/u)) {
|
|
558
|
+
const line = rawLine.trim();
|
|
559
|
+
if (line === "") continue;
|
|
560
|
+
const eq = line.indexOf("=");
|
|
561
|
+
if (eq <= 0) continue;
|
|
562
|
+
const name = line.slice(0, eq).trim();
|
|
563
|
+
const value = line.slice(eq + 1).trim();
|
|
564
|
+
if (!NAME_OK.test(name)) continue;
|
|
565
|
+
if (!lastByName.has(name)) order.push(name);
|
|
566
|
+
lastByName.set(name, value);
|
|
567
|
+
}
|
|
568
|
+
return order.map((name) => ({ name, value: lastByName.get(name) }));
|
|
569
|
+
}
|
|
570
|
+
function formatEnvCopy(pairs) {
|
|
571
|
+
const lines = [];
|
|
572
|
+
for (const pair of pairs) {
|
|
573
|
+
const name = pair.name.trim();
|
|
574
|
+
if (name === "") continue;
|
|
575
|
+
lines.push(`${name}=${pair.value}`);
|
|
576
|
+
}
|
|
577
|
+
return lines.join("\n");
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// src/client/env-row-select.ts
|
|
581
|
+
function isSelectionEditKey(event) {
|
|
582
|
+
return event.ctrlKey || event.metaKey;
|
|
583
|
+
}
|
|
584
|
+
function rangeIds(ordered, from, to) {
|
|
585
|
+
const a = ordered.indexOf(from);
|
|
586
|
+
const b = ordered.indexOf(to);
|
|
587
|
+
if (a < 0 || b < 0) return from === to && a >= 0 ? [from] : [];
|
|
588
|
+
const start = Math.min(a, b);
|
|
589
|
+
const end = Math.max(a, b);
|
|
590
|
+
return ordered.slice(start, end + 1);
|
|
591
|
+
}
|
|
592
|
+
function clearDomTextSelection() {
|
|
593
|
+
const selection = window.getSelection();
|
|
594
|
+
if (selection !== null && selection.rangeCount > 0) selection.removeAllRanges();
|
|
595
|
+
}
|
|
596
|
+
function hasFocusedInputTextSelection() {
|
|
597
|
+
const active = document.activeElement;
|
|
598
|
+
if (!(active instanceof HTMLInputElement) && !(active instanceof HTMLTextAreaElement)) return false;
|
|
599
|
+
const start = active.selectionStart;
|
|
600
|
+
const end = active.selectionEnd;
|
|
601
|
+
return start !== null && end !== null && start !== end;
|
|
602
|
+
}
|
|
603
|
+
function selectedEnvCopyText(selectedIds, orderedIds, drafts) {
|
|
604
|
+
if (selectedIds.size === 0) return "";
|
|
605
|
+
const pairs = orderedIds.flatMap((id) => {
|
|
606
|
+
if (!selectedIds.has(id)) return [];
|
|
607
|
+
const draft = drafts[id];
|
|
608
|
+
if (draft === void 0) return [];
|
|
609
|
+
const name = draft.name.trim();
|
|
610
|
+
if (name === "") return [];
|
|
611
|
+
return [{ name, value: draft.value }];
|
|
612
|
+
});
|
|
613
|
+
return formatEnvCopy(pairs);
|
|
614
|
+
}
|
|
615
|
+
function rowIdFromPoint(clientX, clientY) {
|
|
616
|
+
const hit = document.elementFromPoint(clientX, clientY);
|
|
617
|
+
if (!(hit instanceof Element)) return void 0;
|
|
618
|
+
const row = hit.closest("[data-env-row]");
|
|
619
|
+
if (!(row instanceof HTMLElement)) return void 0;
|
|
620
|
+
const id = row.dataset.envRow;
|
|
621
|
+
return id === void 0 || id === "" ? void 0 : id;
|
|
622
|
+
}
|
|
623
|
+
|
|
556
624
|
// src/client/EnvSettingsSection.module.css
|
|
557
|
-
var css = ".EnvSettingsSection_section {\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-width: 760px;\n color: var(--dsw-alias-label-primary);\n}\n\n.EnvSettingsSection_heading {\n margin: 0;\n font-size: 18px;\n font-weight: 500;\n line-height: 1.3;\n}\n\n/* \u2014\u2014 dsh CLI: exactly two lines (label + path) \u2014\u2014 */\n.EnvSettingsSection_cli {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.EnvSettingsSection_cliHeading {\n margin: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.EnvSettingsSection_cliBody {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 28px;\n gap: 8px;\n align-items: center;\n height: 28px;\n}\n\n.EnvSettingsSection_cliPath {\n margin: 0;\n min-width: 0;\n font-size: 13px;\n line-height: 28px;\n color: var(--dsw-alias-label-tertiary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.EnvSettingsSection_cliSlot {\n display: flex;\n width: 28px;\n height: 28px;\n align-items: center;\n justify-content: center;\n}\n\n.EnvSettingsSection_cliSlot[data-empty='true'] {\n visibility: hidden;\n pointer-events: none;\n}\n\n.EnvSettingsSection_notice
|
|
625
|
+
var css = ".EnvSettingsSection_section {\n display: flex;\n flex-direction: column;\n gap: 16px;\n max-width: 760px;\n min-width: 0;\n color: var(--dsw-alias-label-primary);\n container-type: inline-size;\n}\n\n.EnvSettingsSection_heading {\n margin: 0;\n font-size: 18px;\n font-weight: 500;\n line-height: 1.3;\n}\n\n/* \u2014\u2014 dsh CLI: exactly two lines (label + path) \u2014\u2014 */\n.EnvSettingsSection_cli {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.EnvSettingsSection_cliHeading {\n margin: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.EnvSettingsSection_cliBody {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 28px;\n gap: 8px;\n align-items: center;\n height: 28px;\n}\n\n.EnvSettingsSection_cliPath {\n margin: 0;\n min-width: 0;\n font-size: 13px;\n line-height: 28px;\n color: var(--dsw-alias-label-tertiary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.EnvSettingsSection_cliSlot {\n display: flex;\n width: 28px;\n height: 28px;\n align-items: center;\n justify-content: center;\n}\n\n.EnvSettingsSection_cliSlot[data-empty='true'] {\n visibility: hidden;\n pointer-events: none;\n}\n\n.EnvSettingsSection_notice {\n margin: 0;\n font-size: 13px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.EnvSettingsSection_notice[data-tone='error'] {\n color: var(--dsw-alias-label-danger, #c62828);\n}\n\n/* \u2014\u2014 variable rows: name | value | actions \u2014\u2014 */\n.EnvSettingsSection_header,\n.EnvSettingsSection_row {\n display: grid;\n grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.25fr) 116px;\n gap: 10px;\n align-items: center;\n min-width: 0;\n}\n\n.EnvSettingsSection_row {\n padding: 4px 6px;\n margin: 0 -6px;\n user-select: none;\n}\n\n.EnvSettingsSection_row[data-selected='true'] {\n background: var(--dsw-alias-fill-hover, rgba(127, 127, 127, 0.1));\n}\n\n.EnvSettingsSection_row[data-composer='true'] {\n user-select: auto;\n}\n\n.EnvSettingsSection_header {\n padding: 0 0 2px;\n}\n\n.EnvSettingsSection_headerLabel {\n margin: 0;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.3;\n color: var(--dsw-alias-label-tertiary);\n}\n\n.EnvSettingsSection_headerActions {\n width: 116px;\n}\n\n/* Extremely narrow pane: value wraps under name; actions stay on the first row. */\n@container (max-width: 360px) {\n .EnvSettingsSection_header,\n .EnvSettingsSection_row {\n grid-template-columns: minmax(0, 1fr) 116px;\n align-items: start;\n row-gap: 8px;\n }\n\n .EnvSettingsSection_header {\n align-items: end;\n }\n\n .EnvSettingsSection_header > :nth-child(1),\n .EnvSettingsSection_row > :nth-child(1) {\n grid-column: 1;\n grid-row: 1;\n }\n\n .EnvSettingsSection_header > :nth-child(3),\n .EnvSettingsSection_row > :nth-child(3) {\n grid-column: 2;\n grid-row: 1;\n }\n\n .EnvSettingsSection_header > :nth-child(2),\n .EnvSettingsSection_row > :nth-child(2) {\n grid-column: 1 / -1;\n grid-row: 2;\n }\n\n .EnvSettingsSection_actions {\n margin-left: 0;\n }\n}\n\n.EnvSettingsSection_field {\n min-width: 0;\n overflow: hidden;\n}\n\n.EnvSettingsSection_fieldInput {\n display: flex;\n box-sizing: border-box;\n width: 100%;\n max-width: 100%;\n min-width: 0;\n user-select: none;\n}\n\n.EnvSettingsSection_field:focus-within,\n.EnvSettingsSection_field:focus-within .EnvSettingsSection_fieldInput,\n.EnvSettingsSection_row[data-composer='true'] .EnvSettingsSection_fieldInput {\n user-select: text;\n}\n\n.EnvSettingsSection_actions {\n display: grid;\n grid-template-columns: repeat(4, 26px);\n gap: 2px;\n align-items: center;\n justify-content: end;\n width: 116px;\n margin-left: auto;\n flex-shrink: 0;\n}\n\n.EnvSettingsSection_slot {\n display: flex;\n width: 26px;\n height: 26px;\n align-items: center;\n justify-content: center;\n}\n\n.EnvSettingsSection_slot[data-empty='true'] {\n visibility: hidden;\n pointer-events: none;\n}\n\n.EnvSettingsSection_iconButton {\n display: inline-flex;\n width: 26px;\n height: 26px;\n margin: 0;\n padding: 0;\n align-items: center;\n justify-content: center;\n border: none;\n border-radius: var(--dsw-radius-sm, 6px);\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n.EnvSettingsSection_iconButton:hover:not(:disabled) {\n background: var(--dsw-alias-fill-hover, rgba(127, 127, 127, 0.12));\n color: var(--dsw-alias-label-primary);\n}\n\n.EnvSettingsSection_iconButton:disabled {\n opacity: 0.45;\n cursor: default;\n}\n\n.EnvSettingsSection_iconButtonDanger:hover:not(:disabled) {\n color: var(--dsw-alias-label-danger, #c62828);\n}\n\n.EnvSettingsSection_iconButtonPrimary {\n color: var(--dsw-alias-brand-primary, #247bbf);\n}\n\n.EnvSettingsSection_restartBadge {\n display: inline-flex;\n width: 26px;\n height: 26px;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-warning, #c67c00);\n}\n\n.EnvSettingsSection_spinner {\n animation: spin 1s linear infinite;\n}\n\n@keyframes spin {\n to { transform: rotate(360deg); }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .EnvSettingsSection_spinner {\n animation: none;\n }\n}\n\n.EnvSettingsSection_groups {\n display: flex;\n flex-direction: column;\n gap: 14px;\n min-width: 0;\n}\n\n.EnvSettingsSection_group {\n display: flex;\n flex-direction: column;\n gap: 10px;\n min-width: 0;\n}\n\n.EnvSettingsSection_group + .EnvSettingsSection_group {\n border-top: 0.5px solid var(--dsw-alias-border-l2, rgba(127, 127, 127, 0.25));\n padding-top: 14px;\n}\n\n.EnvSettingsSection_groupTitleRow {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 36px;\n}\n\n.EnvSettingsSection_groupToggle {\n display: flex;\n flex: none;\n align-items: center;\n gap: 8px;\n border: 0;\n padding: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.EnvSettingsSection_groupToggle:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary, #247bbf);\n outline-offset: 2px;\n}\n\n.EnvSettingsSection_groupToggle > .EnvSettingsSection_chevron {\n transform: rotate(-90deg);\n}\n\n.EnvSettingsSection_groupToggle[aria-expanded='true'] > .EnvSettingsSection_chevron {\n transform: none;\n}\n\n.EnvSettingsSection_groupTitle {\n font-size: 14px;\n line-height: 22px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n}\n\n.EnvSettingsSection_headerEnd {\n display: flex;\n align-items: center;\n gap: 4px;\n margin-left: auto;\n}\n\n.EnvSettingsSection_groupBody {\n display: flex;\n flex-direction: column;\n gap: 8px;\n min-width: 0;\n}\n\n.EnvSettingsSection_modalField {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.EnvSettingsSection_modalCheck {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n font-size: 13px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n";
|
|
558
626
|
if (typeof document !== "undefined" && !document.getElementById("dsh-custom-env-css")) {
|
|
559
627
|
const style = document.createElement("style");
|
|
560
628
|
style.id = "dsh-custom-env-css";
|
|
561
629
|
style.textContent = css;
|
|
562
630
|
document.head.appendChild(style);
|
|
563
631
|
}
|
|
564
|
-
var EnvSettingsSection_default = { "section": "EnvSettingsSection_section", "heading": "EnvSettingsSection_heading", "cli": "EnvSettingsSection_cli", "cliHeading": "EnvSettingsSection_cliHeading", "cliBody": "EnvSettingsSection_cliBody", "cliPath": "EnvSettingsSection_cliPath", "cliSlot": "EnvSettingsSection_cliSlot", "notice": "EnvSettingsSection_notice", "
|
|
632
|
+
var EnvSettingsSection_default = { "section": "EnvSettingsSection_section", "heading": "EnvSettingsSection_heading", "cli": "EnvSettingsSection_cli", "cliHeading": "EnvSettingsSection_cliHeading", "cliBody": "EnvSettingsSection_cliBody", "cliPath": "EnvSettingsSection_cliPath", "cliSlot": "EnvSettingsSection_cliSlot", "notice": "EnvSettingsSection_notice", "header": "EnvSettingsSection_header", "row": "EnvSettingsSection_row", "headerLabel": "EnvSettingsSection_headerLabel", "headerActions": "EnvSettingsSection_headerActions", "actions": "EnvSettingsSection_actions", "field": "EnvSettingsSection_field", "fieldInput": "EnvSettingsSection_fieldInput", "slot": "EnvSettingsSection_slot", "iconButton": "EnvSettingsSection_iconButton", "iconButtonDanger": "EnvSettingsSection_iconButtonDanger", "iconButtonPrimary": "EnvSettingsSection_iconButtonPrimary", "restartBadge": "EnvSettingsSection_restartBadge", "spinner": "EnvSettingsSection_spinner", "groups": "EnvSettingsSection_groups", "group": "EnvSettingsSection_group", "groupTitleRow": "EnvSettingsSection_groupTitleRow", "groupToggle": "EnvSettingsSection_groupToggle", "chevron": "EnvSettingsSection_chevron", "groupTitle": "EnvSettingsSection_groupTitle", "headerEnd": "EnvSettingsSection_headerEnd", "groupBody": "EnvSettingsSection_groupBody", "modalField": "EnvSettingsSection_modalField", "modalCheck": "EnvSettingsSection_modalCheck" };
|
|
565
633
|
|
|
566
634
|
// src/client/EnvSettingsSection.tsx
|
|
567
635
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
568
|
-
var
|
|
569
|
-
var
|
|
636
|
+
var NAME_OK2 = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
637
|
+
var PENDING_PREFIX = "pending:";
|
|
638
|
+
var COMPOSER_PREFIX = "composer:";
|
|
639
|
+
function isPendingId(id) {
|
|
640
|
+
return id.startsWith(PENDING_PREFIX);
|
|
641
|
+
}
|
|
642
|
+
function composerId(groupId) {
|
|
643
|
+
return `${COMPOSER_PREFIX}${groupId}`;
|
|
644
|
+
}
|
|
645
|
+
function isComposerId(id) {
|
|
646
|
+
return id.startsWith(COMPOSER_PREFIX);
|
|
647
|
+
}
|
|
648
|
+
function rowsByGroup(groups, entries, pendingOrder, pendingGroup) {
|
|
649
|
+
const saved = new Map(groups.map((group) => [group.id, []]));
|
|
650
|
+
const pending = new Map(groups.map((group) => [group.id, []]));
|
|
651
|
+
for (const entry of entries) {
|
|
652
|
+
(saved.get(saved.has(entry.groupId) ? entry.groupId : DEFAULT_GROUP_ID) ?? saved.get(DEFAULT_GROUP_ID)).push(entry);
|
|
653
|
+
}
|
|
654
|
+
for (const id of pendingOrder) {
|
|
655
|
+
const groupId = pendingGroup[id] ?? DEFAULT_GROUP_ID;
|
|
656
|
+
(pending.get(pending.has(groupId) ? groupId : DEFAULT_GROUP_ID) ?? pending.get(DEFAULT_GROUP_ID)).push(id);
|
|
657
|
+
}
|
|
658
|
+
return { saved, pending };
|
|
659
|
+
}
|
|
570
660
|
function IconAction({
|
|
571
661
|
label,
|
|
572
662
|
disabled,
|
|
@@ -599,14 +689,37 @@ function RowActions({
|
|
|
599
689
|
canConfirm,
|
|
600
690
|
pending = false,
|
|
601
691
|
showRemove = true,
|
|
692
|
+
moveItems,
|
|
602
693
|
onConfirm,
|
|
603
694
|
onCancel,
|
|
604
695
|
onRestore,
|
|
605
|
-
onRemove
|
|
696
|
+
onRemove,
|
|
697
|
+
onMove
|
|
606
698
|
}) {
|
|
699
|
+
const [moveOpen, setMoveOpen] = (0, import_react.useState)(false);
|
|
700
|
+
const showMove = moveItems !== void 0 && moveItems.length > 0 && onMove !== void 0;
|
|
607
701
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.actions, role: "group", "aria-label": t("field.actions"), children: [
|
|
608
702
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Slot, { empty: !dirty && !pending, children: dirty ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconAction, { label: loading ? t("panel.loading") : t("action.confirm"), primary: true, disabled: busy || !canConfirm, onClick: onConfirm, children: loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconLoadingOutlineRegular, { className: EnvSettingsSection_default.spinner, size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconCheckOutlineRegular, { size: 14 }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Tooltip, { portal: true, label: t("status.restartRequired"), side: "top", delayMs: 400, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: EnvSettingsSection_default.restartBadge, role: "img", "aria-label": t("status.restartRequired"), title: t("status.restartRequired"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconWarningOutlineRegular, { size: 14 }) }) }) }),
|
|
609
703
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Slot, { empty: !dirty && !pending, children: dirty ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconAction, { label: t("action.cancel"), disabled: busy, onClick: onCancel, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconCloseOutlineRegular, { size: 14 }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconAction, { label: t("action.restore"), disabled: busy, onClick: onRestore, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconRefreshOutlineRegular, { size: 14 }) }) }),
|
|
704
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Slot, { empty: !showMove, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
705
|
+
import_dsh_client_ui_primitives.Menu,
|
|
706
|
+
{
|
|
707
|
+
open: moveOpen,
|
|
708
|
+
onClose: () => {
|
|
709
|
+
setMoveOpen(false);
|
|
710
|
+
},
|
|
711
|
+
items: (moveItems ?? []).map((item) => ({ id: item.id, label: item.label })),
|
|
712
|
+
onSelect: (groupId) => {
|
|
713
|
+
setMoveOpen(false);
|
|
714
|
+
onMove?.(groupId);
|
|
715
|
+
},
|
|
716
|
+
align: "end",
|
|
717
|
+
portal: true,
|
|
718
|
+
anchor: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconAction, { label: t("action.moveGroup"), disabled: busy, onClick: () => {
|
|
719
|
+
setMoveOpen((value) => !value);
|
|
720
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconFolderOpenOutlineRegular, { size: 14 }) })
|
|
721
|
+
}
|
|
722
|
+
) }),
|
|
610
723
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Slot, { empty: !showRemove, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconAction, { label: t("action.remove"), danger: true, disabled: busy, onClick: onRemove, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 14 }) }) })
|
|
611
724
|
] });
|
|
612
725
|
}
|
|
@@ -622,9 +735,17 @@ function Field(props) {
|
|
|
622
735
|
title: props.title,
|
|
623
736
|
"aria-invalid": props.invalid || void 0,
|
|
624
737
|
"aria-label": props.label,
|
|
738
|
+
onMouseDown: (event) => {
|
|
739
|
+
if (!props.rowSelectGestures) {
|
|
740
|
+
event.stopPropagation();
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
if (isSelectionEditKey(event)) event.preventDefault();
|
|
744
|
+
},
|
|
625
745
|
onChange: (event) => {
|
|
626
746
|
props.onChange(event.target.value);
|
|
627
|
-
}
|
|
747
|
+
},
|
|
748
|
+
onPaste: props.onPaste
|
|
628
749
|
}
|
|
629
750
|
) });
|
|
630
751
|
}
|
|
@@ -634,25 +755,98 @@ function EnvSettingsSection({
|
|
|
634
755
|
upsert,
|
|
635
756
|
remove,
|
|
636
757
|
restore,
|
|
758
|
+
moveEntry,
|
|
759
|
+
createGroup,
|
|
760
|
+
renameGroup,
|
|
761
|
+
deleteGroup,
|
|
637
762
|
cliStatus,
|
|
638
763
|
cliInstall
|
|
639
764
|
}) {
|
|
640
765
|
const [snapshot, setSnapshot] = (0, import_react.useState)();
|
|
641
766
|
const [cli, setCli] = (0, import_react.useState)();
|
|
642
|
-
const [drafts, setDrafts] = (0, import_react.useState)({
|
|
767
|
+
const [drafts, setDrafts] = (0, import_react.useState)({});
|
|
768
|
+
const [pendingOrder, setPendingOrder] = (0, import_react.useState)([]);
|
|
769
|
+
const [pendingGroup, setPendingGroup] = (0, import_react.useState)({});
|
|
770
|
+
const [openGroups, setOpenGroups] = (0, import_react.useState)({ [DEFAULT_GROUP_ID]: true });
|
|
643
771
|
const [busyTarget, setBusyTarget] = (0, import_react.useState)();
|
|
644
772
|
const [error, setError] = (0, import_react.useState)();
|
|
645
773
|
const [nameError, setNameError] = (0, import_react.useState)(false);
|
|
646
774
|
const [pendingRemove, setPendingRemove] = (0, import_react.useState)();
|
|
775
|
+
const [groupModal, setGroupModal] = (0, import_react.useState)();
|
|
776
|
+
const [groupTitleDraft, setGroupTitleDraft] = (0, import_react.useState)("");
|
|
777
|
+
const [selectedIds, setSelectedIds] = (0, import_react.useState)(() => /* @__PURE__ */ new Set());
|
|
778
|
+
const pendingSeq = (0, import_react.useRef)(0);
|
|
779
|
+
const draftsRef = (0, import_react.useRef)(drafts);
|
|
780
|
+
draftsRef.current = drafts;
|
|
781
|
+
const pendingOrderRef = (0, import_react.useRef)(pendingOrder);
|
|
782
|
+
pendingOrderRef.current = pendingOrder;
|
|
783
|
+
const pendingGroupRef = (0, import_react.useRef)(pendingGroup);
|
|
784
|
+
pendingGroupRef.current = pendingGroup;
|
|
785
|
+
const selectedRef = (0, import_react.useRef)(selectedIds);
|
|
786
|
+
selectedRef.current = selectedIds;
|
|
787
|
+
const anchorIdRef = (0, import_react.useRef)(void 0);
|
|
788
|
+
const dragModeRef = (0, import_react.useRef)(void 0);
|
|
789
|
+
const dragVisitedRef = (0, import_react.useRef)(/* @__PURE__ */ new Set());
|
|
790
|
+
const dragPendingCrossRef = (0, import_react.useRef)(false);
|
|
791
|
+
const pendingRemoveRef = (0, import_react.useRef)(pendingRemove);
|
|
792
|
+
pendingRemoveRef.current = pendingRemove;
|
|
793
|
+
const groupModalRef = (0, import_react.useRef)(groupModal);
|
|
794
|
+
groupModalRef.current = groupModal;
|
|
647
795
|
const busy = busyTarget !== void 0;
|
|
796
|
+
const groups = snapshot?.groups ?? [{ id: DEFAULT_GROUP_ID, title: t("group.defaultTitle") }];
|
|
648
797
|
const entries = snapshot?.entries ?? [];
|
|
649
798
|
const taken = new Set(entries.map((entry) => entry.name));
|
|
650
|
-
const
|
|
799
|
+
const grouped = rowsByGroup(groups, entries, pendingOrder, pendingGroup);
|
|
800
|
+
const selectableOrder = groups.flatMap((group) => [
|
|
801
|
+
...(grouped.saved.get(group.id) ?? []).map((entry) => entry.id),
|
|
802
|
+
...grouped.pending.get(group.id) ?? []
|
|
803
|
+
]);
|
|
804
|
+
const selectableOrderRef = (0, import_react.useRef)(selectableOrder);
|
|
805
|
+
selectableOrderRef.current = selectableOrder;
|
|
806
|
+
const groupLabel = (group) => group.id === DEFAULT_GROUP_ID ? t("group.defaultTitle") : group.title;
|
|
807
|
+
const keepTransientDrafts = (current, dropId) => {
|
|
808
|
+
const kept = {};
|
|
809
|
+
for (const [id, draft] of Object.entries(current)) {
|
|
810
|
+
if (isComposerId(id)) kept[id] = draft;
|
|
811
|
+
else if (isPendingId(id) && id !== dropId) kept[id] = draft;
|
|
812
|
+
}
|
|
813
|
+
return kept;
|
|
814
|
+
};
|
|
815
|
+
const emptyComposers = (nextGroups, current) => Object.fromEntries(nextGroups.map((group) => {
|
|
816
|
+
const id = composerId(group.id);
|
|
817
|
+
return [id, current[id] ?? { name: "", value: "" }];
|
|
818
|
+
}));
|
|
819
|
+
const forgetPendingId = (id) => {
|
|
820
|
+
setPendingOrder((order) => order.filter((item) => item !== id));
|
|
821
|
+
setPendingGroup((previous) => {
|
|
822
|
+
if (previous[id] === void 0) return previous;
|
|
823
|
+
const next = { ...previous };
|
|
824
|
+
delete next[id];
|
|
825
|
+
return next;
|
|
826
|
+
});
|
|
827
|
+
setSelectedIds((previous) => {
|
|
828
|
+
if (!previous.has(id)) return previous;
|
|
829
|
+
const next = new Set(previous);
|
|
830
|
+
next.delete(id);
|
|
831
|
+
return next;
|
|
832
|
+
});
|
|
833
|
+
if (anchorIdRef.current === id) anchorIdRef.current = void 0;
|
|
834
|
+
};
|
|
835
|
+
const applySnapshot = (next, dropPendingId) => {
|
|
651
836
|
setSnapshot(next);
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
837
|
+
setOpenGroups((previous) => {
|
|
838
|
+
const merged = { ...previous };
|
|
839
|
+
for (const group of next.groups) {
|
|
840
|
+
if (merged[group.id] === void 0) merged[group.id] = group.id === DEFAULT_GROUP_ID;
|
|
841
|
+
}
|
|
842
|
+
return merged;
|
|
655
843
|
});
|
|
844
|
+
if (dropPendingId !== void 0) forgetPendingId(dropPendingId);
|
|
845
|
+
setDrafts((current) => ({
|
|
846
|
+
...emptyComposers(next.groups, current),
|
|
847
|
+
...keepTransientDrafts(current, dropPendingId),
|
|
848
|
+
...Object.fromEntries(next.entries.map((entry) => [entry.id, { name: entry.name, value: entry.value }]))
|
|
849
|
+
}));
|
|
656
850
|
};
|
|
657
851
|
const setDraft = (id, patch) => {
|
|
658
852
|
setDrafts((previous) => ({
|
|
@@ -660,12 +854,39 @@ function EnvSettingsSection({
|
|
|
660
854
|
[id]: { name: patch.name ?? previous[id]?.name ?? "", value: patch.value ?? previous[id]?.value ?? "" }
|
|
661
855
|
}));
|
|
662
856
|
};
|
|
663
|
-
const
|
|
857
|
+
const dropPending = (id) => {
|
|
858
|
+
forgetPendingId(id);
|
|
859
|
+
setDrafts((previous) => {
|
|
860
|
+
const next = { ...previous };
|
|
861
|
+
delete next[id];
|
|
862
|
+
return next;
|
|
863
|
+
});
|
|
864
|
+
};
|
|
865
|
+
const clearSelection = () => {
|
|
866
|
+
setSelectedIds(/* @__PURE__ */ new Set());
|
|
867
|
+
anchorIdRef.current = void 0;
|
|
868
|
+
clearDomTextSelection();
|
|
869
|
+
};
|
|
870
|
+
const pruneSelection = (allowed) => {
|
|
871
|
+
setSelectedIds((previous) => {
|
|
872
|
+
let changed = false;
|
|
873
|
+
const next = /* @__PURE__ */ new Set();
|
|
874
|
+
for (const id of previous) {
|
|
875
|
+
if (allowed.has(id)) next.add(id);
|
|
876
|
+
else changed = true;
|
|
877
|
+
}
|
|
878
|
+
return changed ? next : previous;
|
|
879
|
+
});
|
|
880
|
+
if (anchorIdRef.current !== void 0 && !allowed.has(anchorIdRef.current)) {
|
|
881
|
+
anchorIdRef.current = void 0;
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
const run = async (target, action, dropPendingId) => {
|
|
664
885
|
if (busyTarget !== void 0) return;
|
|
665
886
|
setBusyTarget(target);
|
|
666
887
|
setError(void 0);
|
|
667
888
|
try {
|
|
668
|
-
applySnapshot(await action());
|
|
889
|
+
applySnapshot(await action(), dropPendingId);
|
|
669
890
|
} catch (err) {
|
|
670
891
|
setError(formatRemoteError(err, t));
|
|
671
892
|
} finally {
|
|
@@ -676,7 +897,16 @@ function EnvSettingsSection({
|
|
|
676
897
|
setBusyTarget("boot");
|
|
677
898
|
setError(void 0);
|
|
678
899
|
try {
|
|
679
|
-
|
|
900
|
+
setPendingOrder([]);
|
|
901
|
+
setPendingGroup({});
|
|
902
|
+
clearSelection();
|
|
903
|
+
const next = await load();
|
|
904
|
+
setSnapshot(next);
|
|
905
|
+
setOpenGroups(Object.fromEntries(next.groups.map((group) => [group.id, group.id === DEFAULT_GROUP_ID])));
|
|
906
|
+
setDrafts({
|
|
907
|
+
...emptyComposers(next.groups, {}),
|
|
908
|
+
...Object.fromEntries(next.entries.map((entry) => [entry.id, { name: entry.name, value: entry.value }]))
|
|
909
|
+
});
|
|
680
910
|
try {
|
|
681
911
|
setCli(await cliStatus());
|
|
682
912
|
} catch {
|
|
@@ -691,79 +921,277 @@ function EnvSettingsSection({
|
|
|
691
921
|
(0, import_react.useEffect)(() => {
|
|
692
922
|
void refresh();
|
|
693
923
|
}, [refresh]);
|
|
694
|
-
|
|
924
|
+
(0, import_react.useEffect)(() => {
|
|
925
|
+
pruneSelection(new Set(selectableOrder));
|
|
926
|
+
}, [selectableOrder.join("\0")]);
|
|
927
|
+
const stopEditingGesture = () => {
|
|
928
|
+
clearDomTextSelection();
|
|
929
|
+
const active = document.activeElement;
|
|
930
|
+
if (active instanceof HTMLInputElement && active.closest(`.${EnvSettingsSection_default.groups}`) !== null) active.blur();
|
|
931
|
+
};
|
|
932
|
+
const applyDragOverRow = (id) => {
|
|
933
|
+
if (dragModeRef.current === void 0) return;
|
|
934
|
+
if (dragModeRef.current === "toggle") {
|
|
935
|
+
if (dragVisitedRef.current.has(id)) return;
|
|
936
|
+
stopEditingGesture();
|
|
937
|
+
dragVisitedRef.current.add(id);
|
|
938
|
+
setSelectedIds((previous) => {
|
|
939
|
+
const next = new Set(previous);
|
|
940
|
+
if (next.has(id)) next.delete(id);
|
|
941
|
+
else next.add(id);
|
|
942
|
+
return next;
|
|
943
|
+
});
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
if (dragPendingCrossRef.current && id === anchorIdRef.current) return;
|
|
947
|
+
if (dragPendingCrossRef.current || id !== anchorIdRef.current) {
|
|
948
|
+
dragPendingCrossRef.current = false;
|
|
949
|
+
stopEditingGesture();
|
|
950
|
+
}
|
|
951
|
+
dragVisitedRef.current.add(id);
|
|
952
|
+
setSelectedIds(new Set(rangeIds(selectableOrderRef.current, anchorIdRef.current ?? id, id)));
|
|
953
|
+
};
|
|
954
|
+
(0, import_react.useEffect)(() => {
|
|
955
|
+
if (selectedIds.size > 0) clearDomTextSelection();
|
|
956
|
+
}, [selectedIds]);
|
|
957
|
+
(0, import_react.useEffect)(() => {
|
|
958
|
+
const endDrag = () => {
|
|
959
|
+
dragModeRef.current = void 0;
|
|
960
|
+
dragVisitedRef.current = /* @__PURE__ */ new Set();
|
|
961
|
+
dragPendingCrossRef.current = false;
|
|
962
|
+
};
|
|
963
|
+
const onMove = (event) => {
|
|
964
|
+
if (event.buttons !== 1 || dragModeRef.current === void 0) return;
|
|
965
|
+
const id = rowIdFromPoint(event.clientX, event.clientY);
|
|
966
|
+
if (id !== void 0) applyDragOverRow(id);
|
|
967
|
+
};
|
|
968
|
+
const onPointerDown = (event) => {
|
|
969
|
+
if (selectedRef.current.size === 0 || pendingRemoveRef.current !== void 0 || groupModalRef.current !== void 0) return;
|
|
970
|
+
if (!(event.target instanceof Element)) return;
|
|
971
|
+
if (event.target.closest("[data-env-row]") !== null) return;
|
|
972
|
+
clearSelection();
|
|
973
|
+
};
|
|
974
|
+
const copyText = () => selectedEnvCopyText(selectedRef.current, selectableOrderRef.current, draftsRef.current);
|
|
975
|
+
const onKeyDown = (event) => {
|
|
976
|
+
if (selectedRef.current.size === 0) return;
|
|
977
|
+
if (event.key !== "c" && event.key !== "C" || !isSelectionEditKey(event) || event.altKey || event.shiftKey) return;
|
|
978
|
+
if (hasFocusedInputTextSelection()) return;
|
|
979
|
+
const text = copyText();
|
|
980
|
+
if (text === "") return;
|
|
981
|
+
event.preventDefault();
|
|
982
|
+
void navigator.clipboard.writeText(text);
|
|
983
|
+
};
|
|
984
|
+
const onCopy = (event) => {
|
|
985
|
+
if (selectedRef.current.size === 0 || hasFocusedInputTextSelection()) return;
|
|
986
|
+
const text = copyText();
|
|
987
|
+
if (text === "") return;
|
|
988
|
+
event.preventDefault();
|
|
989
|
+
event.clipboardData?.setData("text/plain", text);
|
|
990
|
+
};
|
|
991
|
+
window.addEventListener("mouseup", endDrag);
|
|
992
|
+
window.addEventListener("mousemove", onMove);
|
|
993
|
+
document.addEventListener("mousedown", onPointerDown, true);
|
|
994
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
995
|
+
document.addEventListener("copy", onCopy, true);
|
|
996
|
+
return () => {
|
|
997
|
+
window.removeEventListener("mouseup", endDrag);
|
|
998
|
+
window.removeEventListener("mousemove", onMove);
|
|
999
|
+
document.removeEventListener("mousedown", onPointerDown, true);
|
|
1000
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
1001
|
+
document.removeEventListener("copy", onCopy, true);
|
|
1002
|
+
};
|
|
1003
|
+
}, []);
|
|
1004
|
+
const saveExisting = (id, entryName) => {
|
|
695
1005
|
const draft = drafts[id] ?? { name: "", value: "" };
|
|
696
1006
|
const name = draft.name.trim();
|
|
697
1007
|
const takenByOther = name !== entryName && taken.has(name);
|
|
698
|
-
if (!
|
|
1008
|
+
if (!NAME_OK2.test(name) || takenByOther) {
|
|
1009
|
+
setNameError(true);
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
if (draft.value === "") return;
|
|
1013
|
+
setNameError(false);
|
|
1014
|
+
void run(`row:${id}`, () => upsert(id, name, draft.value));
|
|
1015
|
+
};
|
|
1016
|
+
const savePending = (id) => {
|
|
1017
|
+
const draft = drafts[id] ?? { name: "", value: "" };
|
|
1018
|
+
const name = draft.name.trim();
|
|
1019
|
+
if (!NAME_OK2.test(name) || taken.has(name)) {
|
|
699
1020
|
setNameError(true);
|
|
700
1021
|
return;
|
|
701
1022
|
}
|
|
702
1023
|
if (draft.value === "") return;
|
|
703
1024
|
setNameError(false);
|
|
704
|
-
const
|
|
705
|
-
void run(
|
|
1025
|
+
const groupId = pendingGroup[id] ?? DEFAULT_GROUP_ID;
|
|
1026
|
+
void run(`pending:${id}`, () => upsert("", name, draft.value, groupId), id);
|
|
1027
|
+
};
|
|
1028
|
+
const typeIntoComposer = (groupId, patch, focus) => {
|
|
1029
|
+
setNameError(false);
|
|
1030
|
+
const key = composerId(groupId);
|
|
1031
|
+
const base = draftsRef.current[key] ?? { name: "", value: "" };
|
|
1032
|
+
const next = { name: patch.name ?? base.name, value: patch.value ?? base.value };
|
|
1033
|
+
const id = `${PENDING_PREFIX}${++pendingSeq.current}`;
|
|
1034
|
+
setDrafts((previous) => ({
|
|
1035
|
+
...previous,
|
|
1036
|
+
[id]: next,
|
|
1037
|
+
[key]: { name: "", value: "" }
|
|
1038
|
+
}));
|
|
1039
|
+
setPendingOrder((order) => [...order, id]);
|
|
1040
|
+
setPendingGroup((previous) => ({ ...previous, [id]: groupId }));
|
|
1041
|
+
queueMicrotask(() => {
|
|
1042
|
+
document.getElementById(`env-${focus}-${id}`)?.focus();
|
|
1043
|
+
});
|
|
1044
|
+
};
|
|
1045
|
+
const appendPendingPairs = (groupId, pairs) => {
|
|
1046
|
+
if (pairs.length === 0) return;
|
|
1047
|
+
setNameError(false);
|
|
1048
|
+
const previous = draftsRef.current;
|
|
1049
|
+
const order = pendingOrderRef.current;
|
|
1050
|
+
const groupsByPending = pendingGroupRef.current;
|
|
1051
|
+
const nextDrafts = { ...previous, [composerId(groupId)]: { name: "", value: "" } };
|
|
1052
|
+
const existingPendingByName = /* @__PURE__ */ new Map();
|
|
1053
|
+
for (const id of order) {
|
|
1054
|
+
const draft = previous[id];
|
|
1055
|
+
if (draft !== void 0) existingPendingByName.set(draft.name.trim(), id);
|
|
1056
|
+
}
|
|
1057
|
+
const savedByName = new Map(entries.map((entry) => [entry.name, entry.id]));
|
|
1058
|
+
const added = [];
|
|
1059
|
+
const dropPendingIds = /* @__PURE__ */ new Set();
|
|
1060
|
+
const nextPendingGroup = { ...groupsByPending };
|
|
1061
|
+
for (const pair of pairs) {
|
|
1062
|
+
const savedId = savedByName.get(pair.name);
|
|
1063
|
+
if (savedId !== void 0) {
|
|
1064
|
+
nextDrafts[savedId] = { name: pair.name, value: pair.value };
|
|
1065
|
+
const pendingDup = existingPendingByName.get(pair.name);
|
|
1066
|
+
if (pendingDup !== void 0) {
|
|
1067
|
+
delete nextDrafts[pendingDup];
|
|
1068
|
+
dropPendingIds.add(pendingDup);
|
|
1069
|
+
delete nextPendingGroup[pendingDup];
|
|
1070
|
+
existingPendingByName.delete(pair.name);
|
|
1071
|
+
}
|
|
1072
|
+
continue;
|
|
1073
|
+
}
|
|
1074
|
+
const reuse = existingPendingByName.get(pair.name);
|
|
1075
|
+
if (reuse !== void 0) {
|
|
1076
|
+
nextDrafts[reuse] = { name: pair.name, value: pair.value };
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
const id = `${PENDING_PREFIX}${++pendingSeq.current}`;
|
|
1080
|
+
nextDrafts[id] = { name: pair.name, value: pair.value };
|
|
1081
|
+
existingPendingByName.set(pair.name, id);
|
|
1082
|
+
nextPendingGroup[id] = groupId;
|
|
1083
|
+
added.push(id);
|
|
1084
|
+
}
|
|
1085
|
+
setDrafts(nextDrafts);
|
|
1086
|
+
setPendingGroup(nextPendingGroup);
|
|
1087
|
+
if (added.length > 0 || dropPendingIds.size > 0) {
|
|
1088
|
+
setPendingOrder([...order.filter((id) => !dropPendingIds.has(id)), ...added]);
|
|
1089
|
+
}
|
|
1090
|
+
};
|
|
1091
|
+
const onComposerPaste = (groupId, event) => {
|
|
1092
|
+
const text = event.clipboardData.getData("text");
|
|
1093
|
+
const pairs = parseEnvPaste(text);
|
|
1094
|
+
if (pairs.length === 0) return;
|
|
1095
|
+
event.preventDefault();
|
|
1096
|
+
appendPendingPairs(groupId, pairs);
|
|
1097
|
+
};
|
|
1098
|
+
const onRowMouseDown = (id, event) => {
|
|
1099
|
+
if (event.button !== 0) return;
|
|
1100
|
+
const target = event.target;
|
|
1101
|
+
const onInput = target?.closest("input") !== null;
|
|
1102
|
+
const onControl = target?.closest('button, a, [role="button"]') !== null;
|
|
1103
|
+
if (isSelectionEditKey(event)) {
|
|
1104
|
+
event.preventDefault();
|
|
1105
|
+
clearDomTextSelection();
|
|
1106
|
+
dragPendingCrossRef.current = false;
|
|
1107
|
+
if (event.shiftKey && anchorIdRef.current !== void 0) {
|
|
1108
|
+
const spanned = rangeIds(selectableOrder, anchorIdRef.current, id);
|
|
1109
|
+
setSelectedIds(new Set(spanned));
|
|
1110
|
+
dragModeRef.current = "range";
|
|
1111
|
+
dragVisitedRef.current = new Set(spanned);
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
setSelectedIds((previous) => {
|
|
1115
|
+
const next = new Set(previous);
|
|
1116
|
+
if (next.has(id)) next.delete(id);
|
|
1117
|
+
else next.add(id);
|
|
1118
|
+
return next;
|
|
1119
|
+
});
|
|
1120
|
+
anchorIdRef.current = id;
|
|
1121
|
+
dragModeRef.current = "toggle";
|
|
1122
|
+
dragVisitedRef.current = /* @__PURE__ */ new Set([id]);
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
if (!onInput && !onControl) event.preventDefault();
|
|
1126
|
+
anchorIdRef.current = id;
|
|
1127
|
+
dragModeRef.current = "range";
|
|
1128
|
+
dragVisitedRef.current = /* @__PURE__ */ new Set([id]);
|
|
1129
|
+
dragPendingCrossRef.current = true;
|
|
1130
|
+
};
|
|
1131
|
+
const submitGroupModal = () => {
|
|
1132
|
+
if (groupModal === void 0 || busyTarget !== void 0) return;
|
|
1133
|
+
if (groupModal.kind === "create" || groupModal.kind === "rename") {
|
|
1134
|
+
const title = groupTitleDraft.trim();
|
|
1135
|
+
if (title === "") return;
|
|
1136
|
+
setBusyTarget("group");
|
|
1137
|
+
setError(void 0);
|
|
1138
|
+
void (async () => {
|
|
1139
|
+
try {
|
|
1140
|
+
if (groupModal.kind === "create") {
|
|
1141
|
+
const group = await createGroup(title);
|
|
1142
|
+
const next = await load();
|
|
1143
|
+
applySnapshot(next);
|
|
1144
|
+
setOpenGroups((previous) => ({ ...previous, [group.id]: true }));
|
|
1145
|
+
} else {
|
|
1146
|
+
await renameGroup(groupModal.id, title);
|
|
1147
|
+
applySnapshot(await load());
|
|
1148
|
+
}
|
|
1149
|
+
setGroupModal(void 0);
|
|
1150
|
+
} catch (err) {
|
|
1151
|
+
setError(formatRemoteError(err, t));
|
|
1152
|
+
} finally {
|
|
1153
|
+
setBusyTarget(void 0);
|
|
1154
|
+
}
|
|
1155
|
+
})();
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
setBusyTarget("group");
|
|
1159
|
+
setError(void 0);
|
|
1160
|
+
void (async () => {
|
|
1161
|
+
try {
|
|
1162
|
+
applySnapshot(await deleteGroup(groupModal.id, groupModal.moveToDefault));
|
|
1163
|
+
setGroupModal(void 0);
|
|
1164
|
+
} catch (err) {
|
|
1165
|
+
setError(formatRemoteError(err, t));
|
|
1166
|
+
} finally {
|
|
1167
|
+
setBusyTarget(void 0);
|
|
1168
|
+
}
|
|
1169
|
+
})();
|
|
706
1170
|
};
|
|
707
|
-
const newDraft = drafts[NEW_ID] ?? { name: "", value: "" };
|
|
708
|
-
const newDirty = newDraft.name.trim() !== "" || newDraft.value !== "";
|
|
709
1171
|
const cliInstalling = busyTarget === "cli";
|
|
710
1172
|
const cliBooting = busyTarget === "boot" || cli === void 0;
|
|
711
1173
|
const showCliAction = cli?.canInstall === true || cliInstalling;
|
|
712
1174
|
const notice = error ?? (nameError ? t("error.invalidName") : void 0) ?? (cli?.reason === "could-not-resolve-expected-cli" ? t("error.cliUnresolved") : void 0) ?? (cli?.reason === "unsupported-platform" ? t("error.cliUnsupported") : void 0);
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
if (busyTarget !== void 0) return;
|
|
734
|
-
setBusyTarget("cli");
|
|
735
|
-
setError(void 0);
|
|
736
|
-
void (async () => {
|
|
737
|
-
try {
|
|
738
|
-
setCli(await cliInstall());
|
|
739
|
-
} catch (err) {
|
|
740
|
-
setError(formatRemoteError(err, t));
|
|
741
|
-
} finally {
|
|
742
|
-
setBusyTarget(void 0);
|
|
743
|
-
}
|
|
744
|
-
})();
|
|
745
|
-
},
|
|
746
|
-
children: cliInstalling ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconLoadingOutlineRegular, { className: EnvSettingsSection_default.spinner, size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconLinkOutlineRegular, { size: 14 })
|
|
747
|
-
}
|
|
748
|
-
) : null })
|
|
749
|
-
] })
|
|
750
|
-
] }),
|
|
751
|
-
notice !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: EnvSettingsSection_default.notice, "data-tone": error !== void 0 || nameError ? "error" : void 0, role: "status", children: notice }) : null,
|
|
752
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.list, children: [
|
|
753
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.header, children: [
|
|
754
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: EnvSettingsSection_default.headerLabel, children: t("field.name") }),
|
|
755
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: EnvSettingsSection_default.headerLabel, children: t("field.value") }),
|
|
756
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: EnvSettingsSection_default.headerActions, "aria-hidden": "true" })
|
|
757
|
-
] }),
|
|
758
|
-
snapshot !== void 0 && entries.length === 0 && notice === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: EnvSettingsSection_default.empty, children: t("panel.empty") }) : null,
|
|
759
|
-
entries.map((entry) => {
|
|
760
|
-
const draft = drafts[entry.id] ?? { name: entry.name, value: entry.value };
|
|
761
|
-
const dirty = draft.name !== entry.name || draft.value !== entry.value;
|
|
762
|
-
const pending = entry.kind === "added" || entry.kind === "modified";
|
|
763
|
-
const loading = busyTarget === `row:${entry.id}`;
|
|
764
|
-
const nextName = draft.name.trim();
|
|
765
|
-
const canConfirm = NAME_OK.test(nextName) && draft.value !== "" && !(nextName !== entry.name && taken.has(nextName));
|
|
766
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.row, children: [
|
|
1175
|
+
const moveTargets = (currentGroupId) => groups.filter((group) => group.id !== currentGroupId).map((group) => ({ id: group.id, label: groupLabel(group) }));
|
|
1176
|
+
const renderRow = (entry) => {
|
|
1177
|
+
const draft = drafts[entry.id] ?? { name: entry.name, value: entry.value };
|
|
1178
|
+
const dirty = draft.name !== entry.name || draft.value !== entry.value;
|
|
1179
|
+
const pendingKind = entry.kind === "added" || entry.kind === "modified";
|
|
1180
|
+
const loading = busyTarget === `row:${entry.id}`;
|
|
1181
|
+
const nextName = draft.name.trim();
|
|
1182
|
+
const canConfirm = NAME_OK2.test(nextName) && draft.value !== "" && !(nextName !== entry.name && taken.has(nextName));
|
|
1183
|
+
const selected = selectedIds.has(entry.id);
|
|
1184
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1185
|
+
"div",
|
|
1186
|
+
{
|
|
1187
|
+
className: EnvSettingsSection_default.row,
|
|
1188
|
+
"data-env-row": entry.id,
|
|
1189
|
+
"data-selected": selected ? "true" : "false",
|
|
1190
|
+
"aria-selected": selected,
|
|
1191
|
+
onMouseDown: (event) => {
|
|
1192
|
+
onRowMouseDown(entry.id, event);
|
|
1193
|
+
},
|
|
1194
|
+
children: [
|
|
767
1195
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
768
1196
|
Field,
|
|
769
1197
|
{
|
|
@@ -773,6 +1201,7 @@ function EnvSettingsSection({
|
|
|
773
1201
|
title: draft.name,
|
|
774
1202
|
invalid: nameError && dirty,
|
|
775
1203
|
label: t("field.name"),
|
|
1204
|
+
rowSelectGestures: true,
|
|
776
1205
|
onChange: (name) => {
|
|
777
1206
|
setNameError(false);
|
|
778
1207
|
setDraft(entry.id, { name });
|
|
@@ -787,6 +1216,7 @@ function EnvSettingsSection({
|
|
|
787
1216
|
disabled: busy,
|
|
788
1217
|
title: draft.value,
|
|
789
1218
|
label: t("field.value"),
|
|
1219
|
+
rowSelectGestures: true,
|
|
790
1220
|
onChange: (value) => {
|
|
791
1221
|
setDraft(entry.id, { value });
|
|
792
1222
|
}
|
|
@@ -800,9 +1230,10 @@ function EnvSettingsSection({
|
|
|
800
1230
|
loading,
|
|
801
1231
|
dirty: dirty || loading,
|
|
802
1232
|
canConfirm,
|
|
803
|
-
pending,
|
|
1233
|
+
pending: pendingKind && !dirty ? true : false,
|
|
1234
|
+
moveItems: moveTargets(entry.groupId),
|
|
804
1235
|
onConfirm: () => {
|
|
805
|
-
|
|
1236
|
+
saveExisting(entry.id, entry.name);
|
|
806
1237
|
},
|
|
807
1238
|
onCancel: () => {
|
|
808
1239
|
setNameError(false);
|
|
@@ -813,64 +1244,246 @@ function EnvSettingsSection({
|
|
|
813
1244
|
},
|
|
814
1245
|
onRemove: () => {
|
|
815
1246
|
setPendingRemove({ id: entry.id, name: entry.name });
|
|
1247
|
+
},
|
|
1248
|
+
onMove: (groupId) => {
|
|
1249
|
+
void run(`row:${entry.id}`, () => moveEntry(entry.id, groupId));
|
|
816
1250
|
}
|
|
817
1251
|
}
|
|
818
1252
|
)
|
|
819
|
-
]
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1253
|
+
]
|
|
1254
|
+
},
|
|
1255
|
+
entry.id
|
|
1256
|
+
);
|
|
1257
|
+
};
|
|
1258
|
+
const renderPending = (id, groupId) => {
|
|
1259
|
+
const draft = drafts[id] ?? { name: "", value: "" };
|
|
1260
|
+
const loading = busyTarget === `pending:${id}`;
|
|
1261
|
+
const nextName = draft.name.trim();
|
|
1262
|
+
const canConfirm = NAME_OK2.test(nextName) && draft.value !== "" && !taken.has(nextName);
|
|
1263
|
+
const selected = selectedIds.has(id);
|
|
1264
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1265
|
+
"div",
|
|
1266
|
+
{
|
|
1267
|
+
className: EnvSettingsSection_default.row,
|
|
1268
|
+
"data-env-row": id,
|
|
1269
|
+
"data-selected": selected ? "true" : "false",
|
|
1270
|
+
"aria-selected": selected,
|
|
1271
|
+
onMouseDown: (event) => {
|
|
1272
|
+
onRowMouseDown(id, event);
|
|
1273
|
+
},
|
|
1274
|
+
children: [
|
|
1275
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1276
|
+
Field,
|
|
1277
|
+
{
|
|
1278
|
+
id: `env-name-${id}`,
|
|
1279
|
+
value: draft.name,
|
|
1280
|
+
disabled: busy,
|
|
1281
|
+
title: draft.name,
|
|
1282
|
+
invalid: nameError,
|
|
1283
|
+
label: t("field.name"),
|
|
1284
|
+
rowSelectGestures: true,
|
|
1285
|
+
onChange: (name) => {
|
|
1286
|
+
setNameError(false);
|
|
1287
|
+
setDraft(id, { name });
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
),
|
|
1291
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1292
|
+
Field,
|
|
1293
|
+
{
|
|
1294
|
+
id: `env-value-${id}`,
|
|
1295
|
+
value: draft.value,
|
|
1296
|
+
disabled: busy,
|
|
1297
|
+
title: draft.value,
|
|
1298
|
+
label: t("field.value"),
|
|
1299
|
+
rowSelectGestures: true,
|
|
1300
|
+
onChange: (value) => {
|
|
1301
|
+
setDraft(id, { value });
|
|
1302
|
+
}
|
|
835
1303
|
}
|
|
1304
|
+
),
|
|
1305
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1306
|
+
RowActions,
|
|
1307
|
+
{
|
|
1308
|
+
t,
|
|
1309
|
+
busy,
|
|
1310
|
+
loading,
|
|
1311
|
+
dirty: true,
|
|
1312
|
+
canConfirm,
|
|
1313
|
+
showRemove: false,
|
|
1314
|
+
onConfirm: () => {
|
|
1315
|
+
savePending(id);
|
|
1316
|
+
},
|
|
1317
|
+
onCancel: () => {
|
|
1318
|
+
setNameError(false);
|
|
1319
|
+
dropPending(id);
|
|
1320
|
+
},
|
|
1321
|
+
onRestore: () => void 0,
|
|
1322
|
+
onRemove: () => void 0
|
|
1323
|
+
}
|
|
1324
|
+
)
|
|
1325
|
+
]
|
|
1326
|
+
},
|
|
1327
|
+
id
|
|
1328
|
+
);
|
|
1329
|
+
};
|
|
1330
|
+
const renderComposer = (groupId) => {
|
|
1331
|
+
const key = composerId(groupId);
|
|
1332
|
+
const composer = drafts[key] ?? { name: "", value: "" };
|
|
1333
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.row, "data-composer": "true", children: [
|
|
1334
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1335
|
+
Field,
|
|
1336
|
+
{
|
|
1337
|
+
id: `env-new-name-${groupId}`,
|
|
1338
|
+
value: composer.name,
|
|
1339
|
+
disabled: busy,
|
|
1340
|
+
placeholder: t("field.namePlaceholder"),
|
|
1341
|
+
title: composer.name || t("field.namePlaceholder"),
|
|
1342
|
+
label: t("field.name"),
|
|
1343
|
+
onChange: (name) => {
|
|
1344
|
+
typeIntoComposer(groupId, { name }, "name");
|
|
1345
|
+
},
|
|
1346
|
+
onPaste: (event) => {
|
|
1347
|
+
onComposerPaste(groupId, event);
|
|
836
1348
|
}
|
|
837
|
-
|
|
1349
|
+
}
|
|
1350
|
+
),
|
|
1351
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1352
|
+
Field,
|
|
1353
|
+
{
|
|
1354
|
+
id: `env-new-value-${groupId}`,
|
|
1355
|
+
value: composer.value,
|
|
1356
|
+
disabled: busy,
|
|
1357
|
+
placeholder: t("field.valuePlaceholder"),
|
|
1358
|
+
title: composer.value || t("field.valuePlaceholder"),
|
|
1359
|
+
label: t("field.value"),
|
|
1360
|
+
onChange: (value) => {
|
|
1361
|
+
typeIntoComposer(groupId, { value }, "value");
|
|
1362
|
+
},
|
|
1363
|
+
onPaste: (event) => {
|
|
1364
|
+
onComposerPaste(groupId, event);
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
),
|
|
1368
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: EnvSettingsSection_default.actions, "aria-hidden": "true" })
|
|
1369
|
+
] });
|
|
1370
|
+
};
|
|
1371
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.section, children: [
|
|
1372
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: EnvSettingsSection_default.heading, children: t("panel.title") }),
|
|
1373
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: EnvSettingsSection_default.cli, "aria-label": t("cli.title"), children: [
|
|
1374
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { className: EnvSettingsSection_default.cliHeading, children: t("cli.title") }),
|
|
1375
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.cliBody, children: [
|
|
838
1376
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
839
|
-
|
|
1377
|
+
"p",
|
|
840
1378
|
{
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
title: newDraft.value || t("field.valuePlaceholder"),
|
|
846
|
-
label: t("field.value"),
|
|
847
|
-
onChange: (value) => {
|
|
848
|
-
setDraft(NEW_ID, { value });
|
|
849
|
-
}
|
|
1379
|
+
className: EnvSettingsSection_default.cliPath,
|
|
1380
|
+
title: cliBooting ? void 0 : cli.activePath ?? void 0,
|
|
1381
|
+
"aria-busy": cliBooting || cliInstalling,
|
|
1382
|
+
children: cliBooting ? t("panel.loading") : cli.activePath === null ? t("cli.activeMissing") : cli.activePath
|
|
850
1383
|
}
|
|
851
1384
|
),
|
|
852
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
853
|
-
|
|
1385
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: EnvSettingsSection_default.cliSlot, "data-empty": showCliAction ? "false" : "true", children: showCliAction ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1386
|
+
IconAction,
|
|
854
1387
|
{
|
|
855
|
-
t,
|
|
856
|
-
busy,
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
1388
|
+
label: cliInstalling ? t("panel.loading") : cli?.platform === "darwin" ? t("cli.macConflict") : t("cli.install"),
|
|
1389
|
+
disabled: busy,
|
|
1390
|
+
onClick: () => {
|
|
1391
|
+
if (busyTarget !== void 0) return;
|
|
1392
|
+
setBusyTarget("cli");
|
|
1393
|
+
setError(void 0);
|
|
1394
|
+
void (async () => {
|
|
1395
|
+
try {
|
|
1396
|
+
setCli(await cliInstall());
|
|
1397
|
+
} catch (err) {
|
|
1398
|
+
setError(formatRemoteError(err, t));
|
|
1399
|
+
} finally {
|
|
1400
|
+
setBusyTarget(void 0);
|
|
1401
|
+
}
|
|
1402
|
+
})();
|
|
867
1403
|
},
|
|
868
|
-
|
|
869
|
-
onRemove: () => void 0
|
|
1404
|
+
children: cliInstalling ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconLoadingOutlineRegular, { className: EnvSettingsSection_default.spinner, size: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconLinkOutlineRegular, { size: 14 })
|
|
870
1405
|
}
|
|
871
|
-
)
|
|
1406
|
+
) : null })
|
|
872
1407
|
] })
|
|
873
1408
|
] }),
|
|
1409
|
+
notice !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: EnvSettingsSection_default.notice, "data-tone": error !== void 0 || nameError ? "error" : void 0, role: "status", children: notice }) : null,
|
|
1410
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: EnvSettingsSection_default.groups, children: groups.map((group) => {
|
|
1411
|
+
const expanded = openGroups[group.id] === true;
|
|
1412
|
+
const groupEntries = grouped.saved.get(group.id) ?? [];
|
|
1413
|
+
const groupPending = grouped.pending.get(group.id) ?? [];
|
|
1414
|
+
const isDefault = group.id === DEFAULT_GROUP_ID;
|
|
1415
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: EnvSettingsSection_default.group, children: [
|
|
1416
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.groupTitleRow, children: [
|
|
1417
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1418
|
+
"button",
|
|
1419
|
+
{
|
|
1420
|
+
type: "button",
|
|
1421
|
+
className: EnvSettingsSection_default.groupToggle,
|
|
1422
|
+
"aria-expanded": expanded,
|
|
1423
|
+
onClick: () => {
|
|
1424
|
+
setOpenGroups((previous) => ({ ...previous, [group.id]: !expanded }));
|
|
1425
|
+
},
|
|
1426
|
+
children: [
|
|
1427
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: EnvSettingsSection_default.chevron, size: 12, "aria-hidden": "true" }),
|
|
1428
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: EnvSettingsSection_default.groupTitle, children: groupLabel(group) })
|
|
1429
|
+
]
|
|
1430
|
+
}
|
|
1431
|
+
),
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: EnvSettingsSection_default.headerEnd, children: isDefault ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1433
|
+
IconAction,
|
|
1434
|
+
{
|
|
1435
|
+
label: t("action.createGroup"),
|
|
1436
|
+
disabled: busy,
|
|
1437
|
+
onClick: () => {
|
|
1438
|
+
setGroupTitleDraft("");
|
|
1439
|
+
setGroupModal({ kind: "create" });
|
|
1440
|
+
},
|
|
1441
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: 14 })
|
|
1442
|
+
}
|
|
1443
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1444
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1445
|
+
IconAction,
|
|
1446
|
+
{
|
|
1447
|
+
label: t("action.renameGroup"),
|
|
1448
|
+
disabled: busy,
|
|
1449
|
+
onClick: () => {
|
|
1450
|
+
setGroupTitleDraft(group.title);
|
|
1451
|
+
setGroupModal({ kind: "rename", id: group.id, title: group.title });
|
|
1452
|
+
},
|
|
1453
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconEditOutlineRegular, { size: 14 })
|
|
1454
|
+
}
|
|
1455
|
+
),
|
|
1456
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1457
|
+
IconAction,
|
|
1458
|
+
{
|
|
1459
|
+
label: t("action.deleteGroup"),
|
|
1460
|
+
danger: true,
|
|
1461
|
+
disabled: busy,
|
|
1462
|
+
onClick: () => {
|
|
1463
|
+
setGroupModal({
|
|
1464
|
+
kind: "delete",
|
|
1465
|
+
id: group.id,
|
|
1466
|
+
title: group.title,
|
|
1467
|
+
moveToDefault: true
|
|
1468
|
+
});
|
|
1469
|
+
},
|
|
1470
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 14 })
|
|
1471
|
+
}
|
|
1472
|
+
)
|
|
1473
|
+
] }) })
|
|
1474
|
+
] }),
|
|
1475
|
+
expanded ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.groupBody, children: [
|
|
1476
|
+
isDefault ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: EnvSettingsSection_default.header, children: [
|
|
1477
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: EnvSettingsSection_default.headerLabel, children: t("field.name") }),
|
|
1478
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: EnvSettingsSection_default.headerLabel, children: t("field.value") }),
|
|
1479
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: EnvSettingsSection_default.headerActions, "aria-hidden": "true" })
|
|
1480
|
+
] }) : null,
|
|
1481
|
+
groupEntries.map((entry) => renderRow(entry)),
|
|
1482
|
+
groupPending.map((id) => renderPending(id, group.id)),
|
|
1483
|
+
renderComposer(group.id)
|
|
1484
|
+
] }) : null
|
|
1485
|
+
] }, group.id);
|
|
1486
|
+
}) }),
|
|
874
1487
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
875
1488
|
import_dsh_client_ui_primitives.Modal,
|
|
876
1489
|
{
|
|
@@ -901,6 +1514,60 @@ function EnvSettingsSection({
|
|
|
901
1514
|
)
|
|
902
1515
|
] })
|
|
903
1516
|
}
|
|
1517
|
+
),
|
|
1518
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1519
|
+
import_dsh_client_ui_primitives.Modal,
|
|
1520
|
+
{
|
|
1521
|
+
open: groupModal !== void 0,
|
|
1522
|
+
onClose: () => {
|
|
1523
|
+
if (!busy) setGroupModal(void 0);
|
|
1524
|
+
},
|
|
1525
|
+
title: groupModal?.kind === "create" ? t("action.createGroup") : groupModal?.kind === "rename" ? t("action.renameGroup") : t("action.deleteGroupTitle"),
|
|
1526
|
+
closeLabel: t("action.close"),
|
|
1527
|
+
description: groupModal?.kind === "delete" ? t("action.deleteGroupConfirm", { title: groupModal.title }) : void 0,
|
|
1528
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1529
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "outline", disabled: busy, onClick: () => {
|
|
1530
|
+
setGroupModal(void 0);
|
|
1531
|
+
}, children: t("action.cancel") }),
|
|
1532
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1533
|
+
import_dsh_client_ui_primitives.Button,
|
|
1534
|
+
{
|
|
1535
|
+
variant: "primary",
|
|
1536
|
+
disabled: busy || (groupModal?.kind === "create" || groupModal?.kind === "rename") && groupTitleDraft.trim() === "",
|
|
1537
|
+
onClick: () => {
|
|
1538
|
+
submitGroupModal();
|
|
1539
|
+
},
|
|
1540
|
+
children: groupModal?.kind === "delete" ? t("action.deleteGroup") : t("action.confirm")
|
|
1541
|
+
}
|
|
1542
|
+
)
|
|
1543
|
+
] }),
|
|
1544
|
+
children: [
|
|
1545
|
+
groupModal?.kind === "create" || groupModal?.kind === "rename" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: EnvSettingsSection_default.modalField, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1546
|
+
import_dsh_client_ui_primitives.Input,
|
|
1547
|
+
{
|
|
1548
|
+
value: groupTitleDraft,
|
|
1549
|
+
placeholder: t("action.groupTitlePlaceholder"),
|
|
1550
|
+
"aria-label": t("action.groupTitle"),
|
|
1551
|
+
disabled: busy,
|
|
1552
|
+
onChange: (event) => {
|
|
1553
|
+
setGroupTitleDraft(event.target.value);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
) }) : null,
|
|
1557
|
+
groupModal?.kind === "delete" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1558
|
+
import_dsh_client_ui_primitives.Checkbox,
|
|
1559
|
+
{
|
|
1560
|
+
className: EnvSettingsSection_default.modalCheck,
|
|
1561
|
+
checked: groupModal.moveToDefault,
|
|
1562
|
+
disabled: busy,
|
|
1563
|
+
label: t("action.deleteGroupMove"),
|
|
1564
|
+
onChange: (checked) => {
|
|
1565
|
+
setGroupModal({ ...groupModal, moveToDefault: checked });
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
) : null
|
|
1569
|
+
]
|
|
1570
|
+
}
|
|
904
1571
|
)
|
|
905
1572
|
] });
|
|
906
1573
|
}
|
|
@@ -910,7 +1577,6 @@ var NS = "settings.env";
|
|
|
910
1577
|
var zh = {
|
|
911
1578
|
"panel.nav": "\u73AF\u5883\u53D8\u91CF",
|
|
912
1579
|
"panel.title": "\u73AF\u5883\u53D8\u91CF",
|
|
913
|
-
"panel.empty": "\u6682\u65E0\u53D8\u91CF",
|
|
914
1580
|
"panel.loading": "\u52A0\u8F7D\u4E2D\u2026",
|
|
915
1581
|
"field.name": "\u540D\u79F0",
|
|
916
1582
|
"field.value": "\u503C",
|
|
@@ -924,6 +1590,16 @@ var zh = {
|
|
|
924
1590
|
"action.removeConfirm": "\u5220\u9664 {name}\uFF1F",
|
|
925
1591
|
"action.restore": "\u6062\u590D\u539F\u503C",
|
|
926
1592
|
"action.close": "\u5173\u95ED",
|
|
1593
|
+
"action.moveGroup": "\u4FEE\u6539\u5206\u7EC4",
|
|
1594
|
+
"action.createGroup": "\u65B0\u5EFA\u5206\u7EC4",
|
|
1595
|
+
"action.renameGroup": "\u91CD\u547D\u540D\u5206\u7EC4",
|
|
1596
|
+
"action.deleteGroup": "\u5220\u9664\u5206\u7EC4",
|
|
1597
|
+
"action.deleteGroupTitle": "\u5220\u9664\u5206\u7EC4",
|
|
1598
|
+
"action.deleteGroupConfirm": "\u5220\u9664\u5206\u7EC4\u300C{title}\u300D\uFF1F",
|
|
1599
|
+
"action.deleteGroupMove": "\u53D8\u91CF\u79FB\u5165\u9ED8\u8BA4\u5206\u7EC4",
|
|
1600
|
+
"action.groupTitle": "\u5206\u7EC4\u540D\u79F0",
|
|
1601
|
+
"action.groupTitlePlaceholder": "\u5206\u7EC4\u540D\u79F0",
|
|
1602
|
+
"group.defaultTitle": "\u9ED8\u8BA4\u5206\u7EC4",
|
|
927
1603
|
"status.restartRequired": "\u9700\u91CD\u542F\u5BA2\u6237\u7AEF",
|
|
928
1604
|
"cli.title": "dsh",
|
|
929
1605
|
"cli.activeMissing": "\u672A\u627E\u5230",
|
|
@@ -932,6 +1608,7 @@ var zh = {
|
|
|
932
1608
|
"error.generic": "\u66F4\u65B0\u5931\u8D25",
|
|
933
1609
|
"error.invalidName": "\u540D\u79F0\u65E0\u6548",
|
|
934
1610
|
"error.invalidValue": "\u503C\u65E0\u6548",
|
|
1611
|
+
"error.invalidGroup": "\u5206\u7EC4\u65E0\u6548",
|
|
935
1612
|
"error.restoreFailed": "\u6062\u590D\u5931\u8D25",
|
|
936
1613
|
"error.cliInstall": "\u5B89\u88C5\u5931\u8D25",
|
|
937
1614
|
"error.cliUnresolved": "\u65E0\u6CD5\u5B89\u88C5",
|
|
@@ -940,7 +1617,6 @@ var zh = {
|
|
|
940
1617
|
var en = {
|
|
941
1618
|
"panel.nav": "Environment",
|
|
942
1619
|
"panel.title": "Environment",
|
|
943
|
-
"panel.empty": "No variables",
|
|
944
1620
|
"panel.loading": "Loading\u2026",
|
|
945
1621
|
"field.name": "Name",
|
|
946
1622
|
"field.value": "Value",
|
|
@@ -954,6 +1630,16 @@ var en = {
|
|
|
954
1630
|
"action.removeConfirm": "Delete {name}?",
|
|
955
1631
|
"action.restore": "Restore original",
|
|
956
1632
|
"action.close": "Close",
|
|
1633
|
+
"action.moveGroup": "Move to group",
|
|
1634
|
+
"action.createGroup": "New group",
|
|
1635
|
+
"action.renameGroup": "Rename group",
|
|
1636
|
+
"action.deleteGroup": "Delete group",
|
|
1637
|
+
"action.deleteGroupTitle": "Delete group",
|
|
1638
|
+
"action.deleteGroupConfirm": 'Delete group "{title}"?',
|
|
1639
|
+
"action.deleteGroupMove": "Move variables into Default",
|
|
1640
|
+
"action.groupTitle": "Group name",
|
|
1641
|
+
"action.groupTitlePlaceholder": "Group name",
|
|
1642
|
+
"group.defaultTitle": "Default",
|
|
957
1643
|
"status.restartRequired": "Restart the client",
|
|
958
1644
|
"cli.title": "dsh",
|
|
959
1645
|
"cli.activeMissing": "Not found",
|
|
@@ -962,6 +1648,7 @@ var en = {
|
|
|
962
1648
|
"error.generic": "Update failed",
|
|
963
1649
|
"error.invalidName": "Invalid name",
|
|
964
1650
|
"error.invalidValue": "Invalid value",
|
|
1651
|
+
"error.invalidGroup": "Invalid group",
|
|
965
1652
|
"error.restoreFailed": "Restore failed",
|
|
966
1653
|
"error.cliInstall": "Install failed",
|
|
967
1654
|
"error.cliUnresolved": "Install unavailable",
|
|
@@ -985,9 +1672,13 @@ function registerUi(ctx) {
|
|
|
985
1672
|
locale: NS,
|
|
986
1673
|
inject: () => ({
|
|
987
1674
|
load: async () => call(await ctx.remote.customEnv.list()),
|
|
988
|
-
upsert: async (id, name, value) => call(await ctx.remote.customEnv.upsert(id, name, value)),
|
|
1675
|
+
upsert: async (id, name, value, groupId) => call(await ctx.remote.customEnv.upsert(id, name, value, groupId)),
|
|
989
1676
|
remove: async (id) => call(await ctx.remote.customEnv.deleteEntry(id)),
|
|
990
1677
|
restore: async (id) => call(await ctx.remote.customEnv.restore(id)),
|
|
1678
|
+
moveEntry: async (id, groupId) => call(await ctx.remote.customEnv.moveEntry(id, groupId)),
|
|
1679
|
+
createGroup: async (title) => call(await ctx.remote.customEnv.createGroup(title)),
|
|
1680
|
+
renameGroup: async (id, title) => call(await ctx.remote.customEnv.renameGroup(id, title)),
|
|
1681
|
+
deleteGroup: async (id, moveToDefault) => call(await ctx.remote.customEnv.deleteGroup(id, { moveToDefault })),
|
|
991
1682
|
cliStatus: async () => call(await ctx.remote.customEnv.cliStatus()),
|
|
992
1683
|
cliInstall: async () => call(await ctx.remote.customEnv.cliInstall())
|
|
993
1684
|
})
|