@attraccess/plugin-rabbitmq 0.1.0-nightly.1076.1 → 0.1.0-nightly.1079.1
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/index.js
CHANGED
|
@@ -34,17 +34,14 @@ __export(plugin_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(plugin_exports);
|
|
36
36
|
var import_plugins_backend_sdk3 = require("@attraccess/plugins-backend-sdk");
|
|
37
|
-
var
|
|
37
|
+
var import_common5 = require("@nestjs/common");
|
|
38
38
|
|
|
39
|
-
// backend/
|
|
39
|
+
// backend/detection/service.ts
|
|
40
40
|
var import_plugins_backend_sdk = require("@attraccess/plugins-backend-sdk");
|
|
41
|
-
var import_common2 = require("@nestjs/common");
|
|
42
|
-
|
|
43
|
-
// backend/rabbitmq-detection.service.ts
|
|
44
41
|
var import_common = require("@nestjs/common");
|
|
45
42
|
var import_node_crypto2 = require("node:crypto");
|
|
46
43
|
|
|
47
|
-
// backend/
|
|
44
|
+
// backend/management/transport.ts
|
|
48
45
|
var import_node_crypto = require("node:crypto");
|
|
49
46
|
var import_node_https = require("node:https");
|
|
50
47
|
var import_node_net = require("node:net");
|
|
@@ -175,7 +172,7 @@ function describeManagementError(error, timeoutMs) {
|
|
|
175
172
|
}
|
|
176
173
|
}
|
|
177
174
|
|
|
178
|
-
// backend/
|
|
175
|
+
// backend/detection/service.ts
|
|
179
176
|
var PLUGIN_CONTEXT = /* @__PURE__ */ Symbol.for("attraccess.plugin.context");
|
|
180
177
|
var CACHE_TTL_MS = 6e4;
|
|
181
178
|
var PROBE_TIMEOUT_MS = 5e3;
|
|
@@ -302,8 +299,6 @@ RabbitmqDetectionService = __decorateClass([
|
|
|
302
299
|
(0, import_common.Injectable)(),
|
|
303
300
|
__decorateParam(0, (0, import_common.Inject)(PLUGIN_CONTEXT))
|
|
304
301
|
], RabbitmqDetectionService);
|
|
305
|
-
|
|
306
|
-
// backend/rabbitmq-detection.controller.ts
|
|
307
302
|
var RabbitmqDetectionController = class {
|
|
308
303
|
// esbuild does not emit decorator metadata, so Nest cannot infer constructor
|
|
309
304
|
// types for injection — always inject by an explicit token.
|
|
@@ -315,18 +310,18 @@ var RabbitmqDetectionController = class {
|
|
|
315
310
|
}
|
|
316
311
|
};
|
|
317
312
|
__decorateClass([
|
|
318
|
-
(0,
|
|
319
|
-
__decorateParam(0, (0,
|
|
320
|
-
__decorateParam(1, (0,
|
|
313
|
+
(0, import_common.Get)("detection/:mqttServerId"),
|
|
314
|
+
__decorateParam(0, (0, import_common.Param)("mqttServerId", import_common.ParseIntPipe)),
|
|
315
|
+
__decorateParam(1, (0, import_common.Query)("refresh"))
|
|
321
316
|
], RabbitmqDetectionController.prototype, "detect", 1);
|
|
322
317
|
RabbitmqDetectionController = __decorateClass([
|
|
323
318
|
(0, import_plugins_backend_sdk.Auth)("resources.update"),
|
|
324
|
-
(0,
|
|
325
|
-
__decorateParam(0, (0,
|
|
319
|
+
(0, import_common.Controller)("rabbitmq"),
|
|
320
|
+
__decorateParam(0, (0, import_common.Inject)(RabbitmqDetectionService))
|
|
326
321
|
], RabbitmqDetectionController);
|
|
327
322
|
|
|
328
|
-
// backend/
|
|
329
|
-
var
|
|
323
|
+
// backend/management/client.ts
|
|
324
|
+
var import_common2 = require("@nestjs/common");
|
|
330
325
|
var REQUEST_TIMEOUT_MS = 1e4;
|
|
331
326
|
var RabbitmqManagementClient = class {
|
|
332
327
|
// Builds the management API base URL from the generic MQTT config (same
|
|
@@ -343,9 +338,9 @@ var RabbitmqManagementClient = class {
|
|
|
343
338
|
try {
|
|
344
339
|
response = await managementRequest(config, `${base}/api${path}`, method, body, REQUEST_TIMEOUT_MS);
|
|
345
340
|
} catch (error) {
|
|
346
|
-
throw new
|
|
341
|
+
throw new import_common2.HttpException(
|
|
347
342
|
`Cannot reach the RabbitMQ management API at ${base}: ${describeManagementError(error, REQUEST_TIMEOUT_MS)}`,
|
|
348
|
-
|
|
343
|
+
import_common2.HttpStatus.BAD_GATEWAY
|
|
349
344
|
);
|
|
350
345
|
}
|
|
351
346
|
if (!response.ok) {
|
|
@@ -360,26 +355,26 @@ var RabbitmqManagementClient = class {
|
|
|
360
355
|
const upstream = await this.parseErrorBody(response);
|
|
361
356
|
const reason = upstream?.reason || upstream?.error || "";
|
|
362
357
|
if (response.status === 401) {
|
|
363
|
-
return new
|
|
358
|
+
return new import_common2.HttpException(
|
|
364
359
|
"The RabbitMQ management API rejected the configured MQTT server credentials (401). Check the username/password configured for this MQTT server.",
|
|
365
|
-
|
|
360
|
+
import_common2.HttpStatus.BAD_GATEWAY
|
|
366
361
|
);
|
|
367
362
|
}
|
|
368
363
|
if (response.status === 403 || /not.?authori[sz]ed/i.test(reason)) {
|
|
369
|
-
return new
|
|
364
|
+
return new import_common2.HttpException(
|
|
370
365
|
'The configured MQTT server user lacks management privileges on RabbitMQ. User management requires a user with the "administrator" tag.',
|
|
371
|
-
|
|
366
|
+
import_common2.HttpStatus.BAD_GATEWAY
|
|
372
367
|
);
|
|
373
368
|
}
|
|
374
369
|
if (response.status === 404) {
|
|
375
|
-
return new
|
|
370
|
+
return new import_common2.HttpException("Not found on the RabbitMQ side.", import_common2.HttpStatus.NOT_FOUND);
|
|
376
371
|
}
|
|
377
372
|
if (response.status === 400) {
|
|
378
|
-
return new
|
|
373
|
+
return new import_common2.HttpException("RabbitMQ rejected the request.", import_common2.HttpStatus.BAD_REQUEST);
|
|
379
374
|
}
|
|
380
|
-
return new
|
|
375
|
+
return new import_common2.HttpException(
|
|
381
376
|
`RabbitMQ management API request failed (HTTP ${response.status}).`,
|
|
382
|
-
|
|
377
|
+
import_common2.HttpStatus.BAD_GATEWAY
|
|
383
378
|
);
|
|
384
379
|
}
|
|
385
380
|
async parseBody(response) {
|
|
@@ -390,9 +385,9 @@ var RabbitmqManagementClient = class {
|
|
|
390
385
|
try {
|
|
391
386
|
return JSON.parse(text);
|
|
392
387
|
} catch {
|
|
393
|
-
throw new
|
|
388
|
+
throw new import_common2.HttpException(
|
|
394
389
|
"The RabbitMQ management API returned a response that is not valid JSON.",
|
|
395
|
-
|
|
390
|
+
import_common2.HttpStatus.BAD_GATEWAY
|
|
396
391
|
);
|
|
397
392
|
}
|
|
398
393
|
}
|
|
@@ -405,15 +400,12 @@ var RabbitmqManagementClient = class {
|
|
|
405
400
|
}
|
|
406
401
|
};
|
|
407
402
|
RabbitmqManagementClient = __decorateClass([
|
|
408
|
-
(0,
|
|
403
|
+
(0, import_common2.Injectable)()
|
|
409
404
|
], RabbitmqManagementClient);
|
|
410
405
|
|
|
411
|
-
// backend/
|
|
406
|
+
// backend/users/service.ts
|
|
412
407
|
var import_plugins_backend_sdk2 = require("@attraccess/plugins-backend-sdk");
|
|
413
|
-
var
|
|
414
|
-
|
|
415
|
-
// backend/rabbitmq-users.service.ts
|
|
416
|
-
var import_common4 = require("@nestjs/common");
|
|
408
|
+
var import_common3 = require("@nestjs/common");
|
|
417
409
|
var PLUGIN_CONTEXT2 = /* @__PURE__ */ Symbol.for("attraccess.plugin.context");
|
|
418
410
|
var RabbitmqUsersService = class {
|
|
419
411
|
constructor(context, client) {
|
|
@@ -460,7 +452,7 @@ var RabbitmqUsersService = class {
|
|
|
460
452
|
const existing = await this.findUser(config, username);
|
|
461
453
|
const password = dto.password?.length ? dto.password : void 0;
|
|
462
454
|
if (!existing && !password) {
|
|
463
|
-
throw new
|
|
455
|
+
throw new import_common3.HttpException("Password is required when creating a new user.", import_common3.HttpStatus.BAD_REQUEST);
|
|
464
456
|
}
|
|
465
457
|
const body = { tags: (dto.tags ?? this.normalizeTags(existing?.tags)).join(",") };
|
|
466
458
|
if (password) {
|
|
@@ -480,9 +472,9 @@ var RabbitmqUsersService = class {
|
|
|
480
472
|
this.assertValidName(username, "Username");
|
|
481
473
|
const config = await this.requireConfig(mqttServerId);
|
|
482
474
|
if (config.username !== null && config.username === username) {
|
|
483
|
-
throw new
|
|
475
|
+
throw new import_common3.HttpException(
|
|
484
476
|
"Refusing to delete the user the MQTT server connection is configured with.",
|
|
485
|
-
|
|
477
|
+
import_common3.HttpStatus.BAD_REQUEST
|
|
486
478
|
);
|
|
487
479
|
}
|
|
488
480
|
await this.client.request(config, "DELETE", `/users/${encodeURIComponent(username)}`);
|
|
@@ -520,7 +512,7 @@ var RabbitmqUsersService = class {
|
|
|
520
512
|
try {
|
|
521
513
|
return await this.client.request(config, "GET", `/users/${encodeURIComponent(username)}`);
|
|
522
514
|
} catch (error) {
|
|
523
|
-
if (error instanceof
|
|
515
|
+
if (error instanceof import_common3.HttpException && error.getStatus() === import_common3.HttpStatus.NOT_FOUND) {
|
|
524
516
|
return null;
|
|
525
517
|
}
|
|
526
518
|
throw error;
|
|
@@ -529,7 +521,7 @@ var RabbitmqUsersService = class {
|
|
|
529
521
|
async requireConfig(mqttServerId) {
|
|
530
522
|
const config = await this.context.getMqttServerConfig(mqttServerId);
|
|
531
523
|
if (!config) {
|
|
532
|
-
throw new
|
|
524
|
+
throw new import_common3.HttpException("MQTT server not found.", import_common3.HttpStatus.NOT_FOUND);
|
|
533
525
|
}
|
|
534
526
|
return config;
|
|
535
527
|
}
|
|
@@ -544,20 +536,18 @@ var RabbitmqUsersService = class {
|
|
|
544
536
|
}
|
|
545
537
|
assertValidName(value, label) {
|
|
546
538
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
547
|
-
throw new
|
|
539
|
+
throw new import_common3.HttpException(`${label} must not be empty.`, import_common3.HttpStatus.BAD_REQUEST);
|
|
548
540
|
}
|
|
549
541
|
if (value.length > 255) {
|
|
550
|
-
throw new
|
|
542
|
+
throw new import_common3.HttpException(`${label} must be at most 255 characters.`, import_common3.HttpStatus.BAD_REQUEST);
|
|
551
543
|
}
|
|
552
544
|
}
|
|
553
545
|
};
|
|
554
546
|
RabbitmqUsersService = __decorateClass([
|
|
555
|
-
(0,
|
|
556
|
-
__decorateParam(0, (0,
|
|
557
|
-
__decorateParam(1, (0,
|
|
547
|
+
(0, import_common3.Injectable)(),
|
|
548
|
+
__decorateParam(0, (0, import_common3.Inject)(PLUGIN_CONTEXT2)),
|
|
549
|
+
__decorateParam(1, (0, import_common3.Inject)(RabbitmqManagementClient))
|
|
558
550
|
], RabbitmqUsersService);
|
|
559
|
-
|
|
560
|
-
// backend/rabbitmq-users.controller.ts
|
|
561
551
|
var RabbitmqUsersController = class {
|
|
562
552
|
// esbuild does not emit decorator metadata, so Nest cannot infer constructor
|
|
563
553
|
// types for injection — always inject by an explicit token.
|
|
@@ -575,53 +565,52 @@ var RabbitmqUsersController = class {
|
|
|
575
565
|
}
|
|
576
566
|
setPermissions(mqttServerId, username, dto) {
|
|
577
567
|
if (!dto || typeof dto.vhost !== "string") {
|
|
578
|
-
throw new
|
|
568
|
+
throw new import_common3.HttpException("A vhost is required.", import_common3.HttpStatus.BAD_REQUEST);
|
|
579
569
|
}
|
|
580
570
|
return this.users.setPermissions(mqttServerId, username, dto);
|
|
581
571
|
}
|
|
582
572
|
clearPermissions(mqttServerId, username, vhost) {
|
|
583
573
|
if (typeof vhost !== "string" || vhost.length === 0) {
|
|
584
|
-
throw new
|
|
574
|
+
throw new import_common3.HttpException("A vhost query parameter is required.", import_common3.HttpStatus.BAD_REQUEST);
|
|
585
575
|
}
|
|
586
576
|
return this.users.clearPermissions(mqttServerId, username, vhost);
|
|
587
577
|
}
|
|
588
578
|
};
|
|
589
579
|
__decorateClass([
|
|
590
|
-
(0,
|
|
591
|
-
__decorateParam(0, (0,
|
|
580
|
+
(0, import_common3.Get)("users/:mqttServerId"),
|
|
581
|
+
__decorateParam(0, (0, import_common3.Param)("mqttServerId", import_common3.ParseIntPipe))
|
|
592
582
|
], RabbitmqUsersController.prototype, "list", 1);
|
|
593
583
|
__decorateClass([
|
|
594
|
-
(0,
|
|
595
|
-
__decorateParam(0, (0,
|
|
596
|
-
__decorateParam(1, (0,
|
|
597
|
-
__decorateParam(2, (0,
|
|
584
|
+
(0, import_common3.Put)("users/:mqttServerId/:username"),
|
|
585
|
+
__decorateParam(0, (0, import_common3.Param)("mqttServerId", import_common3.ParseIntPipe)),
|
|
586
|
+
__decorateParam(1, (0, import_common3.Param)("username")),
|
|
587
|
+
__decorateParam(2, (0, import_common3.Body)())
|
|
598
588
|
], RabbitmqUsersController.prototype, "upsert", 1);
|
|
599
589
|
__decorateClass([
|
|
600
|
-
(0,
|
|
601
|
-
__decorateParam(0, (0,
|
|
602
|
-
__decorateParam(1, (0,
|
|
590
|
+
(0, import_common3.Delete)("users/:mqttServerId/:username"),
|
|
591
|
+
__decorateParam(0, (0, import_common3.Param)("mqttServerId", import_common3.ParseIntPipe)),
|
|
592
|
+
__decorateParam(1, (0, import_common3.Param)("username"))
|
|
603
593
|
], RabbitmqUsersController.prototype, "remove", 1);
|
|
604
594
|
__decorateClass([
|
|
605
|
-
(0,
|
|
606
|
-
__decorateParam(0, (0,
|
|
607
|
-
__decorateParam(1, (0,
|
|
608
|
-
__decorateParam(2, (0,
|
|
595
|
+
(0, import_common3.Put)("users/:mqttServerId/:username/permissions"),
|
|
596
|
+
__decorateParam(0, (0, import_common3.Param)("mqttServerId", import_common3.ParseIntPipe)),
|
|
597
|
+
__decorateParam(1, (0, import_common3.Param)("username")),
|
|
598
|
+
__decorateParam(2, (0, import_common3.Body)())
|
|
609
599
|
], RabbitmqUsersController.prototype, "setPermissions", 1);
|
|
610
600
|
__decorateClass([
|
|
611
|
-
(0,
|
|
612
|
-
__decorateParam(0, (0,
|
|
613
|
-
__decorateParam(1, (0,
|
|
614
|
-
__decorateParam(2, (0,
|
|
601
|
+
(0, import_common3.Delete)("users/:mqttServerId/:username/permissions"),
|
|
602
|
+
__decorateParam(0, (0, import_common3.Param)("mqttServerId", import_common3.ParseIntPipe)),
|
|
603
|
+
__decorateParam(1, (0, import_common3.Param)("username")),
|
|
604
|
+
__decorateParam(2, (0, import_common3.Query)("vhost"))
|
|
615
605
|
], RabbitmqUsersController.prototype, "clearPermissions", 1);
|
|
616
606
|
RabbitmqUsersController = __decorateClass([
|
|
617
607
|
(0, import_plugins_backend_sdk2.Auth)("resources.update"),
|
|
618
|
-
(0,
|
|
619
|
-
__decorateParam(0, (0,
|
|
608
|
+
(0, import_common3.Controller)("rabbitmq"),
|
|
609
|
+
__decorateParam(0, (0, import_common3.Inject)(RabbitmqUsersService))
|
|
620
610
|
], RabbitmqUsersController);
|
|
621
611
|
|
|
622
|
-
// backend/
|
|
623
|
-
var
|
|
624
|
-
var import_common6 = require("@nestjs/common");
|
|
612
|
+
// backend/credentials/provider.ts
|
|
613
|
+
var import_common4 = require("@nestjs/common");
|
|
625
614
|
|
|
626
615
|
// ../../../node_modules/.pnpm/async-mutex@0.5.0/node_modules/async-mutex/index.mjs
|
|
627
616
|
var E_TIMEOUT = new Error("timeout while waiting for mutex to become available");
|
|
@@ -829,7 +818,31 @@ var Mutex = class {
|
|
|
829
818
|
}
|
|
830
819
|
};
|
|
831
820
|
|
|
832
|
-
// backend/
|
|
821
|
+
// backend/credentials/provider.ts
|
|
822
|
+
var import_crypto = require("crypto");
|
|
823
|
+
function escapeRegex(value) {
|
|
824
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
825
|
+
}
|
|
826
|
+
function mqttFilterToRegex(filter) {
|
|
827
|
+
const terminalMultiLevel = filter.endsWith("/#");
|
|
828
|
+
const prefix = terminalMultiLevel ? filter.slice(0, -2) : filter;
|
|
829
|
+
const translated = prefix.split("/").map((segment) => {
|
|
830
|
+
if (segment === "+") {
|
|
831
|
+
return "[^.]+";
|
|
832
|
+
}
|
|
833
|
+
if (segment === "#") {
|
|
834
|
+
return ".*";
|
|
835
|
+
}
|
|
836
|
+
return segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
837
|
+
}).join("\\.");
|
|
838
|
+
return terminalMultiLevel ? `${translated}(?:\\..*)?` : translated;
|
|
839
|
+
}
|
|
840
|
+
function mqttFiltersToRegex(filters) {
|
|
841
|
+
if (filters.length === 0) {
|
|
842
|
+
return "$(?!)";
|
|
843
|
+
}
|
|
844
|
+
return `^(?:${filters.map(mqttFilterToRegex).join("|")})$`;
|
|
845
|
+
}
|
|
833
846
|
var _RabbitmqCredentialProvisioningProvider = class _RabbitmqCredentialProvisioningProvider {
|
|
834
847
|
constructor(context) {
|
|
835
848
|
__publicField(this, "context", context);
|
|
@@ -839,46 +852,114 @@ var _RabbitmqCredentialProvisioningProvider = class _RabbitmqCredentialProvision
|
|
|
839
852
|
__publicField(this, "detection");
|
|
840
853
|
this.detection = new RabbitmqDetectionService(context);
|
|
841
854
|
}
|
|
842
|
-
|
|
843
|
-
|
|
855
|
+
assertNotManagementUser(config, username) {
|
|
856
|
+
if (config.username === username) {
|
|
857
|
+
throw new import_common4.BadRequestException("Refusing to modify the MQTT server management identity.");
|
|
858
|
+
}
|
|
844
859
|
}
|
|
845
|
-
|
|
846
|
-
|
|
860
|
+
assertName(value, label) {
|
|
861
|
+
if (typeof value !== "string" || value.trim().length === 0 || value.length > 255) {
|
|
862
|
+
throw new import_common4.BadRequestException(`${label} must be a non-empty string no longer than 255 characters.`);
|
|
863
|
+
}
|
|
847
864
|
}
|
|
848
|
-
|
|
849
|
-
|
|
865
|
+
assertTopicFilter(filter) {
|
|
866
|
+
if (filter.includes(".")) {
|
|
867
|
+
throw new import_common4.BadRequestException("RabbitMQ MQTT topic policies cannot contain dots.");
|
|
868
|
+
}
|
|
869
|
+
const segments = filter.split("/");
|
|
870
|
+
for (const [index, segment] of segments.entries()) {
|
|
871
|
+
if (segment.includes("+") && segment !== "+" || segment.includes("#") && (segment !== "#" || index !== segments.length - 1)) {
|
|
872
|
+
throw new import_common4.BadRequestException(
|
|
873
|
+
"MQTT wildcards must occupy a complete topic level, and # must be the final level."
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
850
877
|
}
|
|
851
|
-
|
|
878
|
+
assertRequest(request2) {
|
|
879
|
+
this.assertName(request2.identity, "Identity");
|
|
852
880
|
this.assertName(request2.username, "Username");
|
|
853
|
-
|
|
854
|
-
|
|
881
|
+
this.assertName(request2.vhost, "Vhost");
|
|
882
|
+
if (!Array.isArray(request2.topicPolicy.publish) || !Array.isArray(request2.topicPolicy.subscribe)) {
|
|
883
|
+
throw new import_common4.BadRequestException("Publish and subscribe topic policies must be arrays.");
|
|
884
|
+
}
|
|
885
|
+
for (const filter of [...request2.topicPolicy.publish, ...request2.topicPolicy.subscribe]) {
|
|
886
|
+
if (typeof filter !== "string" || filter.length === 0 || filter.length > 1024) {
|
|
887
|
+
throw new import_common4.BadRequestException("MQTT topic filters must be non-empty strings no longer than 1024 characters.");
|
|
888
|
+
}
|
|
889
|
+
this.assertTopicFilter(filter);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
async requireConfig(mqttServerId) {
|
|
893
|
+
const config = await this.context.getMqttServerConfig(mqttServerId);
|
|
894
|
+
if (!config) {
|
|
895
|
+
throw new import_common4.BadRequestException("MQTT server not found.");
|
|
896
|
+
}
|
|
897
|
+
return config;
|
|
898
|
+
}
|
|
899
|
+
async failAfterRollback(error, rollback) {
|
|
900
|
+
const results = await Promise.allSettled(rollback.map((operation) => operation()));
|
|
901
|
+
const failures = results.filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
902
|
+
if (failures.length > 0) {
|
|
903
|
+
throw new AggregateError([error, ...failures], "Credential provisioning failed and rollback was incomplete.");
|
|
904
|
+
}
|
|
905
|
+
throw error;
|
|
906
|
+
}
|
|
907
|
+
async restorePermission(config, path, permissions) {
|
|
908
|
+
await this.client.request(config, permissions ? "PUT" : "DELETE", path, permissions ?? void 0);
|
|
909
|
+
}
|
|
910
|
+
async restorePermissions(config, vhost, username, permissions, topicPermissions) {
|
|
911
|
+
const results = await Promise.allSettled([
|
|
912
|
+
this.restorePermission(config, `/permissions/${vhost}/${username}`, permissions),
|
|
913
|
+
this.restorePermission(config, `/topic-permissions/${vhost}/${username}`, topicPermissions)
|
|
914
|
+
]);
|
|
915
|
+
const failures = results.filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
916
|
+
if (failures.length > 0) {
|
|
917
|
+
throw new AggregateError(failures, "Failed to restore RabbitMQ permissions.");
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
async getOptional(config, path) {
|
|
855
921
|
try {
|
|
856
|
-
await this.client.request(config, "
|
|
922
|
+
return await this.client.request(config, "GET", path);
|
|
857
923
|
} catch (error) {
|
|
858
|
-
if (error instanceof
|
|
924
|
+
if (error instanceof import_common4.HttpException && error.getStatus() === import_common4.HttpStatus.NOT_FOUND) {
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
859
927
|
throw error;
|
|
860
928
|
}
|
|
861
929
|
}
|
|
862
|
-
async
|
|
863
|
-
this.
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
lock = { mutex: new Mutex(), users: 0 };
|
|
870
|
-
_RabbitmqCredentialProvisioningProvider.vhostLocks.set(lockKey, lock);
|
|
871
|
-
}
|
|
872
|
-
lock.users += 1;
|
|
930
|
+
async getTopicPermissions(config, vhost, username) {
|
|
931
|
+
return this.getOptional(config, `/topic-permissions/${vhost}/${username}`);
|
|
932
|
+
}
|
|
933
|
+
async getPermissions(config, vhost, username) {
|
|
934
|
+
return this.getOptional(config, `/permissions/${vhost}/${username}`);
|
|
935
|
+
}
|
|
936
|
+
async exists(config, path) {
|
|
873
937
|
try {
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
if (
|
|
878
|
-
|
|
938
|
+
await this.client.request(config, "GET", path);
|
|
939
|
+
return true;
|
|
940
|
+
} catch (error) {
|
|
941
|
+
if (error instanceof import_common4.HttpException && error.getStatus() === import_common4.HttpStatus.NOT_FOUND) {
|
|
942
|
+
return false;
|
|
879
943
|
}
|
|
944
|
+
throw error;
|
|
880
945
|
}
|
|
881
946
|
}
|
|
947
|
+
async userExists(config, username) {
|
|
948
|
+
return this.exists(config, `/users/${username}`);
|
|
949
|
+
}
|
|
950
|
+
async writePermissions(config, request2, vhost, username) {
|
|
951
|
+
const subscriptionQueue = `mqtt-subscription-${escapeRegex(request2.identity)}.*`;
|
|
952
|
+
await this.client.request(config, "PUT", `/permissions/${vhost}/${username}`, {
|
|
953
|
+
configure: `^${subscriptionQueue}$`,
|
|
954
|
+
write: `^(amq\\.topic|${subscriptionQueue})$`,
|
|
955
|
+
read: `^(amq\\.topic|${subscriptionQueue})$`
|
|
956
|
+
});
|
|
957
|
+
await this.client.request(config, "PUT", `/topic-permissions/${vhost}/${username}`, {
|
|
958
|
+
exchange: "amq.topic",
|
|
959
|
+
write: mqttFiltersToRegex(request2.topicPolicy.publish),
|
|
960
|
+
read: mqttFiltersToRegex(request2.topicPolicy.subscribe)
|
|
961
|
+
});
|
|
962
|
+
}
|
|
882
963
|
async writeCredentialLocked(request2, config) {
|
|
883
964
|
const password = (0, import_crypto.randomBytes)(24).toString("base64url");
|
|
884
965
|
const vhost = encodeURIComponent(request2.vhost);
|
|
@@ -915,140 +996,49 @@ var _RabbitmqCredentialProvisioningProvider = class _RabbitmqCredentialProvision
|
|
|
915
996
|
password
|
|
916
997
|
};
|
|
917
998
|
}
|
|
918
|
-
async
|
|
919
|
-
|
|
920
|
-
await this.
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
});
|
|
930
|
-
}
|
|
931
|
-
async userExists(config, username) {
|
|
932
|
-
return this.exists(config, `/users/${username}`);
|
|
933
|
-
}
|
|
934
|
-
async exists(config, path) {
|
|
999
|
+
async writeCredential(request2) {
|
|
1000
|
+
this.assertRequest(request2);
|
|
1001
|
+
const config = await this.requireConfig(request2.mqttServerId);
|
|
1002
|
+
this.assertNotManagementUser(config, request2.username);
|
|
1003
|
+
const lockKey = `${config.id}:${request2.vhost}`;
|
|
1004
|
+
let lock = _RabbitmqCredentialProvisioningProvider.vhostLocks.get(lockKey);
|
|
1005
|
+
if (!lock) {
|
|
1006
|
+
lock = { mutex: new Mutex(), users: 0 };
|
|
1007
|
+
_RabbitmqCredentialProvisioningProvider.vhostLocks.set(lockKey, lock);
|
|
1008
|
+
}
|
|
1009
|
+
lock.users += 1;
|
|
935
1010
|
try {
|
|
936
|
-
await
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
if (
|
|
940
|
-
|
|
1011
|
+
return await lock.mutex.runExclusive(() => this.writeCredentialLocked(request2, config));
|
|
1012
|
+
} finally {
|
|
1013
|
+
lock.users -= 1;
|
|
1014
|
+
if (lock.users === 0 && _RabbitmqCredentialProvisioningProvider.vhostLocks.get(lockKey) === lock) {
|
|
1015
|
+
_RabbitmqCredentialProvisioningProvider.vhostLocks.delete(lockKey);
|
|
941
1016
|
}
|
|
942
|
-
throw error;
|
|
943
1017
|
}
|
|
944
1018
|
}
|
|
945
|
-
async
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
return this.getOptional(config, `/topic-permissions/${vhost}/${username}`);
|
|
950
|
-
}
|
|
951
|
-
async getOptional(config, path) {
|
|
1019
|
+
async revoke(request2) {
|
|
1020
|
+
this.assertName(request2.username, "Username");
|
|
1021
|
+
const config = await this.requireConfig(request2.mqttServerId);
|
|
1022
|
+
this.assertNotManagementUser(config, request2.username);
|
|
952
1023
|
try {
|
|
953
|
-
|
|
1024
|
+
await this.client.request(config, "DELETE", `/users/${encodeURIComponent(request2.username)}`);
|
|
954
1025
|
} catch (error) {
|
|
955
|
-
if (error instanceof
|
|
956
|
-
return null;
|
|
957
|
-
}
|
|
1026
|
+
if (error instanceof import_common4.HttpException && error.getStatus() === import_common4.HttpStatus.NOT_FOUND) return;
|
|
958
1027
|
throw error;
|
|
959
1028
|
}
|
|
960
1029
|
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
this.restorePermission(config, `/permissions/${vhost}/${username}`, permissions),
|
|
964
|
-
this.restorePermission(config, `/topic-permissions/${vhost}/${username}`, topicPermissions)
|
|
965
|
-
]);
|
|
966
|
-
const failures = results.filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
967
|
-
if (failures.length > 0) {
|
|
968
|
-
throw new AggregateError(failures, "Failed to restore RabbitMQ permissions.");
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
async restorePermission(config, path, permissions) {
|
|
972
|
-
await this.client.request(config, permissions ? "PUT" : "DELETE", path, permissions ?? void 0);
|
|
973
|
-
}
|
|
974
|
-
async failAfterRollback(error, rollback) {
|
|
975
|
-
const results = await Promise.allSettled(rollback.map((operation) => operation()));
|
|
976
|
-
const failures = results.filter((result) => result.status === "rejected").map((result) => result.reason);
|
|
977
|
-
if (failures.length > 0) {
|
|
978
|
-
throw new AggregateError([error, ...failures], "Credential provisioning failed and rollback was incomplete.");
|
|
979
|
-
}
|
|
980
|
-
throw error;
|
|
981
|
-
}
|
|
982
|
-
async requireConfig(mqttServerId) {
|
|
983
|
-
const config = await this.context.getMqttServerConfig(mqttServerId);
|
|
984
|
-
if (!config) {
|
|
985
|
-
throw new import_common6.BadRequestException("MQTT server not found.");
|
|
986
|
-
}
|
|
987
|
-
return config;
|
|
988
|
-
}
|
|
989
|
-
assertRequest(request2) {
|
|
990
|
-
this.assertName(request2.identity, "Identity");
|
|
991
|
-
this.assertName(request2.username, "Username");
|
|
992
|
-
this.assertName(request2.vhost, "Vhost");
|
|
993
|
-
if (!Array.isArray(request2.topicPolicy.publish) || !Array.isArray(request2.topicPolicy.subscribe)) {
|
|
994
|
-
throw new import_common6.BadRequestException("Publish and subscribe topic policies must be arrays.");
|
|
995
|
-
}
|
|
996
|
-
for (const filter of [...request2.topicPolicy.publish, ...request2.topicPolicy.subscribe]) {
|
|
997
|
-
if (typeof filter !== "string" || filter.length === 0 || filter.length > 1024) {
|
|
998
|
-
throw new import_common6.BadRequestException("MQTT topic filters must be non-empty strings no longer than 1024 characters.");
|
|
999
|
-
}
|
|
1000
|
-
this.assertTopicFilter(filter);
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
assertTopicFilter(filter) {
|
|
1004
|
-
if (filter.includes(".")) {
|
|
1005
|
-
throw new import_common6.BadRequestException("RabbitMQ MQTT topic policies cannot contain dots.");
|
|
1006
|
-
}
|
|
1007
|
-
const segments = filter.split("/");
|
|
1008
|
-
for (const [index, segment] of segments.entries()) {
|
|
1009
|
-
if (segment.includes("+") && segment !== "+" || segment.includes("#") && (segment !== "#" || index !== segments.length - 1)) {
|
|
1010
|
-
throw new import_common6.BadRequestException(
|
|
1011
|
-
"MQTT wildcards must occupy a complete topic level, and # must be the final level."
|
|
1012
|
-
);
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1030
|
+
rotate(request2) {
|
|
1031
|
+
return this.writeCredential(request2);
|
|
1015
1032
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
throw new import_common6.BadRequestException(`${label} must be a non-empty string no longer than 255 characters.`);
|
|
1019
|
-
}
|
|
1033
|
+
provision(request2) {
|
|
1034
|
+
return this.writeCredential(request2);
|
|
1020
1035
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
throw new import_common6.BadRequestException("Refusing to modify the MQTT server management identity.");
|
|
1024
|
-
}
|
|
1036
|
+
async supports(config) {
|
|
1037
|
+
return (await this.detection.detect(config.id)).isRabbitMQ;
|
|
1025
1038
|
}
|
|
1026
1039
|
};
|
|
1027
1040
|
__publicField(_RabbitmqCredentialProvisioningProvider, "vhostLocks", /* @__PURE__ */ new Map());
|
|
1028
1041
|
var RabbitmqCredentialProvisioningProvider = _RabbitmqCredentialProvisioningProvider;
|
|
1029
|
-
function mqttFiltersToRegex(filters) {
|
|
1030
|
-
if (filters.length === 0) {
|
|
1031
|
-
return "$(?!)";
|
|
1032
|
-
}
|
|
1033
|
-
return `^(?:${filters.map(mqttFilterToRegex).join("|")})$`;
|
|
1034
|
-
}
|
|
1035
|
-
function mqttFilterToRegex(filter) {
|
|
1036
|
-
const terminalMultiLevel = filter.endsWith("/#");
|
|
1037
|
-
const prefix = terminalMultiLevel ? filter.slice(0, -2) : filter;
|
|
1038
|
-
const translated = prefix.split("/").map((segment) => {
|
|
1039
|
-
if (segment === "+") {
|
|
1040
|
-
return "[^.]+";
|
|
1041
|
-
}
|
|
1042
|
-
if (segment === "#") {
|
|
1043
|
-
return ".*";
|
|
1044
|
-
}
|
|
1045
|
-
return segment.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1046
|
-
}).join("\\.");
|
|
1047
|
-
return terminalMultiLevel ? `${translated}(?:\\..*)?` : translated;
|
|
1048
|
-
}
|
|
1049
|
-
function escapeRegex(value) {
|
|
1050
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1051
|
-
}
|
|
1052
1042
|
|
|
1053
1043
|
// backend/plugin.ts
|
|
1054
1044
|
var PLUGIN_CONTEXT3 = /* @__PURE__ */ Symbol.for("attraccess.plugin.context");
|
|
@@ -1064,8 +1054,8 @@ var RabbitmqService = class {
|
|
|
1064
1054
|
}
|
|
1065
1055
|
};
|
|
1066
1056
|
RabbitmqService = __decorateClass([
|
|
1067
|
-
(0,
|
|
1068
|
-
__decorateParam(0, (0,
|
|
1057
|
+
(0, import_common5.Injectable)(),
|
|
1058
|
+
__decorateParam(0, (0, import_common5.Inject)(PLUGIN_CONTEXT3))
|
|
1069
1059
|
], RabbitmqService);
|
|
1070
1060
|
var RabbitmqController = class {
|
|
1071
1061
|
// esbuild does not emit decorator metadata, so Nest cannot infer constructor
|
|
@@ -1078,12 +1068,12 @@ var RabbitmqController = class {
|
|
|
1078
1068
|
}
|
|
1079
1069
|
};
|
|
1080
1070
|
__decorateClass([
|
|
1081
|
-
(0,
|
|
1071
|
+
(0, import_common5.Get)("status")
|
|
1082
1072
|
], RabbitmqController.prototype, "status", 1);
|
|
1083
1073
|
RabbitmqController = __decorateClass([
|
|
1084
1074
|
(0, import_plugins_backend_sdk3.Auth)("resources.update"),
|
|
1085
|
-
(0,
|
|
1086
|
-
__decorateParam(0, (0,
|
|
1075
|
+
(0, import_common5.Controller)("rabbitmq"),
|
|
1076
|
+
__decorateParam(0, (0, import_common5.Inject)(RabbitmqService))
|
|
1087
1077
|
], RabbitmqController);
|
|
1088
1078
|
var RabbitmqPluginModule = class {
|
|
1089
1079
|
};
|
package/frontend/{__federation_expose_Plugin-CZ3ZqxcO.js → __federation_expose_Plugin-5jDTnovW.js}
RENAMED
|
@@ -105,6 +105,9 @@ var { createContext, useCallback: useCallback$2, useContext, useEffect: useEffec
|
|
|
105
105
|
var contextKey = Symbol.for("attraccess.plugin.live-updates.context");
|
|
106
106
|
var contexts = globalThis;
|
|
107
107
|
contexts[contextKey] ??= createContext(null);
|
|
108
|
+
var identityKey = Symbol.for("attraccess.plugin.live-updates.identity");
|
|
109
|
+
var identities = globalThis;
|
|
110
|
+
identities[identityKey] ??= createContext(null);
|
|
108
111
|
//#endregion
|
|
109
112
|
//#region ../../../libs/plugins-frontend-sdk/src/lib/frontend.standard-drawer.tsx
|
|
110
113
|
var { DrawerBackdrop, DrawerContent, DrawerDialog } = await importShared("@heroui/react");
|
|
@@ -112,7 +115,7 @@ var { DrawerBackdrop, DrawerContent, DrawerDialog } = await importShared("@herou
|
|
|
112
115
|
//#region ../../../libs/plugins-frontend-sdk/src/lib/frontend.standard-modal.tsx
|
|
113
116
|
var { Modal: Modal$3, ModalBackdrop: ModalBackdrop$3, ModalContainer: ModalContainer$3, ModalDialog: ModalDialog$3 } = await importShared("@heroui/react");
|
|
114
117
|
//#endregion
|
|
115
|
-
//#region frontend/src/detection.ts
|
|
118
|
+
//#region frontend/src/detection/detection.ts
|
|
116
119
|
var { useCallback: useCallback$1, useEffect: useEffect$3, useState: useState$3 } = await importShared("react");
|
|
117
120
|
var api$1 = createPluginApiClient("/api/rabbitmq/detection");
|
|
118
121
|
function fetchDetection(mqttServerId, refresh) {
|
|
@@ -185,7 +188,7 @@ function useDetection(mqttServerId) {
|
|
|
185
188
|
};
|
|
186
189
|
}
|
|
187
190
|
//#endregion
|
|
188
|
-
//#region frontend/src/RabbitmqListBadge.tsx
|
|
191
|
+
//#region frontend/src/users/RabbitmqListBadge.tsx
|
|
189
192
|
var { Chip: Chip$2 } = await importShared("@heroui/react");
|
|
190
193
|
var { RabbitIcon: RabbitIcon$1 } = await importShared("lucide-react");
|
|
191
194
|
function RabbitmqListBadge({ mqttServerId }) {
|
|
@@ -347,8 +350,8 @@ var useRabbitmqTranslations = () => useTranslations({
|
|
|
347
350
|
de: de_default
|
|
348
351
|
}, { escapeValues: false });
|
|
349
352
|
//#endregion
|
|
350
|
-
//#region frontend/src/RabbitmqStatusPanel.tsx
|
|
351
|
-
var { Alert: Alert$
|
|
353
|
+
//#region frontend/src/detection/RabbitmqStatusPanel.tsx
|
|
354
|
+
var { Alert: Alert$4, AlertContent: AlertContent$4, AlertDescription: AlertDescription$4, Button: Button$5, Card: Card$2, Chip: Chip$1, Spinner: Spinner$2 } = await importShared("@heroui/react");
|
|
352
355
|
var { CheckCircle2Icon, RabbitIcon, RefreshCwIcon: RefreshCwIcon$1, XCircleIcon } = await importShared("lucide-react");
|
|
353
356
|
function StatusRow({ ok, label, value }) {
|
|
354
357
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -369,10 +372,10 @@ function RabbitmqStatusPanel({ mqttServerId }) {
|
|
|
369
372
|
const { t } = useRabbitmqTranslations();
|
|
370
373
|
const { result, loading, refresh } = useDetection(mqttServerId);
|
|
371
374
|
if (!result?.isRabbitMQ) return null;
|
|
372
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card$
|
|
375
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card$2, {
|
|
373
376
|
"data-cy": `rabbitmq-status-panel-${mqttServerId}`,
|
|
374
377
|
className: "rmq:w-full rmq:border rmq:border-default-200 rmq:dark:border-default-100",
|
|
375
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card$
|
|
378
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card$2.Header, {
|
|
376
379
|
className: "rmq:flex rmq:flex-row rmq:items-center rmq:justify-between rmq:gap-2",
|
|
377
380
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
378
381
|
className: "rmq:flex rmq:items-center rmq:gap-2",
|
|
@@ -389,7 +392,7 @@ function RabbitmqStatusPanel({ mqttServerId }) {
|
|
|
389
392
|
children: t("status.detected")
|
|
390
393
|
})
|
|
391
394
|
]
|
|
392
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$
|
|
395
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$5, {
|
|
393
396
|
isIconOnly: true,
|
|
394
397
|
size: "sm",
|
|
395
398
|
variant: "ghost",
|
|
@@ -397,9 +400,9 @@ function RabbitmqStatusPanel({ mqttServerId }) {
|
|
|
397
400
|
"data-cy": `rabbitmq-status-refresh-${mqttServerId}`,
|
|
398
401
|
onPress: refresh,
|
|
399
402
|
isDisabled: loading,
|
|
400
|
-
children: loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner$
|
|
403
|
+
children: loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner$2, { size: "sm" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCwIcon$1, { className: "rmq:w-4 rmq:h-4" })
|
|
401
404
|
})]
|
|
402
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card$
|
|
405
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card$2.Content, {
|
|
403
406
|
className: "rmq:flex rmq:flex-col rmq:gap-1",
|
|
404
407
|
children: [
|
|
405
408
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusRow, {
|
|
@@ -442,17 +445,17 @@ function RabbitmqStatusPanel({ mqttServerId }) {
|
|
|
442
445
|
children: result.managementApi || "—"
|
|
443
446
|
})]
|
|
444
447
|
}),
|
|
445
|
-
result.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert$
|
|
448
|
+
result.error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert$4, {
|
|
446
449
|
status: result.reachable ? "warning" : "danger",
|
|
447
450
|
className: "rmq:mt-2",
|
|
448
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent$
|
|
451
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent$4, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription$4, { children: result.error }) })
|
|
449
452
|
})
|
|
450
453
|
]
|
|
451
454
|
})]
|
|
452
455
|
});
|
|
453
456
|
}
|
|
454
457
|
//#endregion
|
|
455
|
-
//#region frontend/src/users-api.ts
|
|
458
|
+
//#region frontend/src/users/users-api.ts
|
|
456
459
|
var DEFAULT_MQTT_PERMISSIONS = {
|
|
457
460
|
configure: "^mqtt-subscription-.*$",
|
|
458
461
|
write: "^(amq\\.topic|mqtt-subscription-.*)$",
|
|
@@ -484,8 +487,8 @@ function clearPermissions(mqttServerId, username, vhost) {
|
|
|
484
487
|
});
|
|
485
488
|
}
|
|
486
489
|
//#endregion
|
|
487
|
-
//#region frontend/src/RabbitmqPermissionsModal.tsx
|
|
488
|
-
var { Alert: Alert$
|
|
490
|
+
//#region frontend/src/users/permissions/RabbitmqPermissionsModal.tsx
|
|
491
|
+
var { Alert: Alert$3, AlertContent: AlertContent$3, AlertDescription: AlertDescription$3, Button: Button$4, Input: Input$1, Label: Label$1, Modal: Modal$2, ModalBackdrop: ModalBackdrop$2, ModalBody: ModalBody$2, ModalContainer: ModalContainer$2, ModalDialog: ModalDialog$2, ModalFooter: ModalFooter$2, ModalHeader: ModalHeader$2, ModalHeading: ModalHeading$2, TextField: TextField$1 } = await importShared("@heroui/react");
|
|
489
492
|
var { PlusIcon: PlusIcon$1, Trash2Icon: Trash2Icon$1 } = await importShared("lucide-react");
|
|
490
493
|
var { useEffect: useEffect$2, useState: useState$2 } = await importShared("react");
|
|
491
494
|
function PermissionEditor({ row, busy, onChange, onSave, onRemove }) {
|
|
@@ -503,7 +506,7 @@ function PermissionEditor({ row, busy, onChange, onSave, onRemove }) {
|
|
|
503
506
|
" ",
|
|
504
507
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: row.vhost })
|
|
505
508
|
]
|
|
506
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$
|
|
509
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$4, {
|
|
507
510
|
isIconOnly: true,
|
|
508
511
|
size: "sm",
|
|
509
512
|
variant: "ghost",
|
|
@@ -554,7 +557,7 @@ function PermissionEditor({ row, busy, onChange, onSave, onRemove }) {
|
|
|
554
557
|
}),
|
|
555
558
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
556
559
|
className: "rmq:flex rmq:flex-wrap rmq:justify-end rmq:gap-2",
|
|
557
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$
|
|
560
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$4, {
|
|
558
561
|
size: "sm",
|
|
559
562
|
variant: "ghost",
|
|
560
563
|
onPress: () => onChange({
|
|
@@ -564,7 +567,7 @@ function PermissionEditor({ row, busy, onChange, onSave, onRemove }) {
|
|
|
564
567
|
isDisabled: busy,
|
|
565
568
|
"data-cy": `rabbitmq-permissions-mqtt-defaults-button-${row.vhost}`,
|
|
566
569
|
children: t("permissions.defaults")
|
|
567
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$
|
|
570
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$4, {
|
|
568
571
|
size: "sm",
|
|
569
572
|
variant: "primary",
|
|
570
573
|
onPress: onSave,
|
|
@@ -691,7 +694,7 @@ function RabbitmqPermissionsModal({ mqttServerId, isOpen, user, vhosts, onClose,
|
|
|
691
694
|
autoComplete: "off",
|
|
692
695
|
"data-cy": "rabbitmq-permissions-add-vhost-input"
|
|
693
696
|
})]
|
|
694
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$
|
|
697
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$4, {
|
|
695
698
|
variant: "secondary",
|
|
696
699
|
onPress: addVhost,
|
|
697
700
|
isDisabled: newVhost.trim().length === 0,
|
|
@@ -699,14 +702,14 @@ function RabbitmqPermissionsModal({ mqttServerId, isOpen, user, vhosts, onClose,
|
|
|
699
702
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon$1, { className: "rmq:w-4 rmq:h-4" }), t("permissions.add")]
|
|
700
703
|
})]
|
|
701
704
|
}),
|
|
702
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert$
|
|
705
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert$3, {
|
|
703
706
|
status: "danger",
|
|
704
707
|
"data-cy": "rabbitmq-permissions-error-alert",
|
|
705
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent$
|
|
708
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent$3, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription$3, { children: tMessage(error) }) })
|
|
706
709
|
})
|
|
707
710
|
]
|
|
708
711
|
}),
|
|
709
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalFooter$2, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$
|
|
712
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalFooter$2, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$4, {
|
|
710
713
|
variant: "secondary",
|
|
711
714
|
onPress: onClose,
|
|
712
715
|
"data-cy": "rabbitmq-permissions-close-button",
|
|
@@ -717,13 +720,9 @@ function RabbitmqPermissionsModal({ mqttServerId, isOpen, user, vhosts, onClose,
|
|
|
717
720
|
});
|
|
718
721
|
}
|
|
719
722
|
//#endregion
|
|
720
|
-
//#region frontend/src/
|
|
721
|
-
var { Alert: Alert$1, AlertContent: AlertContent$1, AlertDescription: AlertDescription$1, Button: Button$1, Checkbox, Form, Input, Label, Modal: Modal$1, ModalBackdrop: ModalBackdrop$1, ModalBody: ModalBody$1, ModalContainer: ModalContainer$1, ModalDialog: ModalDialog$1, ModalFooter: ModalFooter$1, ModalHeader: ModalHeader$1, ModalHeading: ModalHeading$1, TextField } = await importShared("@heroui/react");
|
|
723
|
+
//#region frontend/src/users/useRabbitmqUserFormModalState.tsx
|
|
722
724
|
var { useEffect: useEffect$1, useState: useState$1 } = await importShared("react");
|
|
723
|
-
function
|
|
724
|
-
return value.split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0);
|
|
725
|
-
}
|
|
726
|
-
function RabbitmqUserFormModal({ mqttServerId, isOpen, user, vhosts, onClose, onSaved }) {
|
|
725
|
+
function useRabbitmqUserFormModalState({ mqttServerId, isOpen, user, vhosts, onClose, onSaved }) {
|
|
727
726
|
const { t, tMessage } = useRabbitmqTranslations();
|
|
728
727
|
const isEdit = user !== null;
|
|
729
728
|
const [username, setUsername] = useState$1("");
|
|
@@ -775,6 +774,42 @@ function RabbitmqUserFormModal({ mqttServerId, isOpen, user, vhosts, onClose, on
|
|
|
775
774
|
setSaving(false);
|
|
776
775
|
}
|
|
777
776
|
};
|
|
777
|
+
return {
|
|
778
|
+
t,
|
|
779
|
+
tMessage,
|
|
780
|
+
isEdit,
|
|
781
|
+
username,
|
|
782
|
+
setUsername,
|
|
783
|
+
password,
|
|
784
|
+
setPassword,
|
|
785
|
+
tags,
|
|
786
|
+
setTags,
|
|
787
|
+
grantMqttDefaults,
|
|
788
|
+
setGrantMqttDefaults,
|
|
789
|
+
vhost,
|
|
790
|
+
setVhost,
|
|
791
|
+
saving,
|
|
792
|
+
error,
|
|
793
|
+
handleSubmit,
|
|
794
|
+
mqttServerId,
|
|
795
|
+
isOpen,
|
|
796
|
+
user,
|
|
797
|
+
vhosts,
|
|
798
|
+
onClose
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
//#endregion
|
|
802
|
+
//#region frontend/src/users/RabbitmqUserFormModal.tsx
|
|
803
|
+
var { Alert: Alert$2, AlertContent: AlertContent$2, AlertDescription: AlertDescription$2, Button: Button$3, Checkbox, Form, Input, Label, Modal: Modal$1, ModalBackdrop: ModalBackdrop$1, ModalBody: ModalBody$1, ModalContainer: ModalContainer$1, ModalDialog: ModalDialog$1, ModalFooter: ModalFooter$1, ModalHeader: ModalHeader$1, ModalHeading: ModalHeading$1, TextField } = await importShared("@heroui/react");
|
|
804
|
+
function RabbitmqUserFormModal({ mqttServerId, isOpen, user, vhosts, onClose, onSaved }) {
|
|
805
|
+
const { t, tMessage, isEdit, username, setUsername, password, setPassword, tags, setTags, grantMqttDefaults, setGrantMqttDefaults, vhost, setVhost, saving, error, handleSubmit } = useRabbitmqUserFormModalState({
|
|
806
|
+
mqttServerId,
|
|
807
|
+
isOpen,
|
|
808
|
+
user,
|
|
809
|
+
vhosts,
|
|
810
|
+
onClose,
|
|
811
|
+
onSaved
|
|
812
|
+
});
|
|
778
813
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Modal$1, {
|
|
779
814
|
isOpen,
|
|
780
815
|
onOpenChange: (open) => {
|
|
@@ -854,18 +889,18 @@ function RabbitmqUserFormModal({ mqttServerId, isOpen, user, vhosts, onClose, on
|
|
|
854
889
|
})
|
|
855
890
|
]
|
|
856
891
|
}),
|
|
857
|
-
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert$
|
|
892
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert$2, {
|
|
858
893
|
status: "danger",
|
|
859
894
|
"data-cy": "rabbitmq-user-form-error-alert",
|
|
860
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent$
|
|
895
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent$2, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription$2, { children: tMessage(error) }) })
|
|
861
896
|
})
|
|
862
897
|
]
|
|
863
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ModalFooter$1, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$
|
|
898
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ModalFooter$1, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$3, {
|
|
864
899
|
variant: "secondary",
|
|
865
900
|
onPress: onClose,
|
|
866
901
|
"data-cy": "rabbitmq-user-form-cancel-button",
|
|
867
902
|
children: t("common.cancel")
|
|
868
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$
|
|
903
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$3, {
|
|
869
904
|
variant: "primary",
|
|
870
905
|
type: "submit",
|
|
871
906
|
isPending: saving,
|
|
@@ -876,28 +911,13 @@ function RabbitmqUserFormModal({ mqttServerId, isOpen, user, vhosts, onClose, on
|
|
|
876
911
|
}) })
|
|
877
912
|
});
|
|
878
913
|
}
|
|
914
|
+
function parseTags(value) {
|
|
915
|
+
return value.split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0);
|
|
916
|
+
}
|
|
879
917
|
//#endregion
|
|
880
|
-
//#region frontend/src/
|
|
881
|
-
var { Alert, AlertContent, AlertDescription, Button, Card, Chip, Modal, ModalBackdrop, ModalBody, ModalContainer, ModalDialog, ModalFooter, ModalHeader, ModalHeading, Spinner, Table, TableBody, TableCell, TableColumn, TableContent, TableHeader, TableRow, TableScrollContainer } = await importShared("@heroui/react");
|
|
882
|
-
var { KeyRoundIcon, PencilIcon, PlusIcon, RefreshCwIcon, Trash2Icon, UsersIcon } = await importShared("lucide-react");
|
|
918
|
+
//#region frontend/src/users/useRabbitmqUserPanelState.tsx
|
|
883
919
|
var { useCallback, useEffect, useRef, useState } = await importShared("react");
|
|
884
|
-
function
|
|
885
|
-
const { t } = useRabbitmqTranslations();
|
|
886
|
-
if (user.permissions.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
887
|
-
className: "rmq:text-xs rmq:text-default-400",
|
|
888
|
-
children: t("users.none")
|
|
889
|
-
});
|
|
890
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
891
|
-
className: "rmq:flex rmq:flex-wrap rmq:gap-1",
|
|
892
|
-
children: user.permissions.map((permission) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
893
|
-
size: "sm",
|
|
894
|
-
variant: "soft",
|
|
895
|
-
title: t("permissions.summary", { ...permission }),
|
|
896
|
-
children: permission.vhost
|
|
897
|
-
}, permission.vhost))
|
|
898
|
-
});
|
|
899
|
-
}
|
|
900
|
-
function RabbitmqUserPanel({ mqttServerId }) {
|
|
920
|
+
function useRabbitmqUserPanelState({ mqttServerId }) {
|
|
901
921
|
const { t, tMessage, language } = useRabbitmqTranslations();
|
|
902
922
|
const { result } = useDetection(mqttServerId);
|
|
903
923
|
const [data, setData] = useState(null);
|
|
@@ -916,6 +936,20 @@ function RabbitmqUserPanel({ mqttServerId }) {
|
|
|
916
936
|
mounted.current = false;
|
|
917
937
|
};
|
|
918
938
|
}, []);
|
|
939
|
+
const confirmDelete = async () => {
|
|
940
|
+
if (!userToDelete) return;
|
|
941
|
+
setDeleting(true);
|
|
942
|
+
setDeleteError(null);
|
|
943
|
+
try {
|
|
944
|
+
await deleteUser(mqttServerId, userToDelete.name);
|
|
945
|
+
setUserToDelete(null);
|
|
946
|
+
reload();
|
|
947
|
+
} catch (err) {
|
|
948
|
+
setDeleteError(err instanceof Error ? err.message : { key: "users.deleteError" });
|
|
949
|
+
} finally {
|
|
950
|
+
setDeleting(false);
|
|
951
|
+
}
|
|
952
|
+
};
|
|
919
953
|
const reload = useCallback(async () => {
|
|
920
954
|
setLoading(true);
|
|
921
955
|
setLoadError(null);
|
|
@@ -935,83 +969,161 @@ function RabbitmqUserPanel({ mqttServerId }) {
|
|
|
935
969
|
useEffect(() => {
|
|
936
970
|
if (manageable) reload();
|
|
937
971
|
}, [manageable, reload]);
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
972
|
+
return {
|
|
973
|
+
t,
|
|
974
|
+
tMessage,
|
|
975
|
+
language,
|
|
976
|
+
data,
|
|
977
|
+
loading,
|
|
978
|
+
loadError,
|
|
979
|
+
formOpen,
|
|
980
|
+
setFormOpen,
|
|
981
|
+
formUser,
|
|
982
|
+
setFormUser,
|
|
983
|
+
permissionsUser,
|
|
984
|
+
setPermissionsUser,
|
|
985
|
+
userToDelete,
|
|
986
|
+
setUserToDelete,
|
|
987
|
+
deleting,
|
|
988
|
+
setDeleting,
|
|
989
|
+
deleteError,
|
|
990
|
+
setDeleteError,
|
|
991
|
+
reload,
|
|
992
|
+
manageable,
|
|
993
|
+
mqttServerId,
|
|
994
|
+
confirmDelete
|
|
952
995
|
};
|
|
996
|
+
}
|
|
997
|
+
//#endregion
|
|
998
|
+
//#region frontend/src/users/RabbitmqUserPanelCardHeader.tsx
|
|
999
|
+
var { Button: Button$2, Card: Card$1, Spinner: Spinner$1 } = await importShared("@heroui/react");
|
|
1000
|
+
var { PlusIcon, RefreshCwIcon, UsersIcon } = await importShared("lucide-react");
|
|
1001
|
+
function RabbitmqUserPanelCardHeader({ t, reload, loading, mqttServerId, setFormUser, setFormOpen }) {
|
|
1002
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card$1.Header, {
|
|
1003
|
+
className: "rmq:flex rmq:flex-row rmq:items-center rmq:justify-between rmq:gap-2",
|
|
1004
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1005
|
+
className: "rmq:flex rmq:items-center rmq:gap-2",
|
|
1006
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(UsersIcon, { className: "rmq:w-5 rmq:h-5 rmq:text-accent-soft-foreground" }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
|
|
1007
|
+
className: "rmq:text-base rmq:font-semibold rmq:text-default-700",
|
|
1008
|
+
children: t("users.title")
|
|
1009
|
+
})]
|
|
1010
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
1011
|
+
className: "rmq:flex rmq:items-center rmq:gap-2",
|
|
1012
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$2, {
|
|
1013
|
+
isIconOnly: true,
|
|
1014
|
+
size: "sm",
|
|
1015
|
+
variant: "ghost",
|
|
1016
|
+
"aria-label": t("users.reload"),
|
|
1017
|
+
onPress: () => void reload(),
|
|
1018
|
+
isDisabled: loading,
|
|
1019
|
+
"data-cy": `rabbitmq-user-panel-reload-${mqttServerId}`,
|
|
1020
|
+
children: loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner$1, { size: "sm" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCwIcon, { className: "rmq:w-4 rmq:h-4" })
|
|
1021
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$2, {
|
|
1022
|
+
size: "sm",
|
|
1023
|
+
variant: "primary",
|
|
1024
|
+
onPress: () => {
|
|
1025
|
+
setFormUser(null);
|
|
1026
|
+
setFormOpen(true);
|
|
1027
|
+
},
|
|
1028
|
+
"data-cy": `rabbitmq-user-panel-create-button-${mqttServerId}`,
|
|
1029
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, { className: "rmq:w-4 rmq:h-4" }), t("users.add")]
|
|
1030
|
+
})]
|
|
1031
|
+
})]
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
//#endregion
|
|
1035
|
+
//#region frontend/src/users/RabbitmqUserPanelModalBackdrop.tsx
|
|
1036
|
+
var { Alert: Alert$1, AlertContent: AlertContent$1, AlertDescription: AlertDescription$1, Button: Button$1, ModalBackdrop, ModalBody, ModalContainer, ModalDialog, ModalFooter, ModalHeader, ModalHeading } = await importShared("@heroui/react");
|
|
1037
|
+
function RabbitmqUserPanelModalBackdrop({ t, userToDelete, deleteError, tMessage, confirmDelete, deleting }) {
|
|
1038
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalBackdrop, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalContainer, {
|
|
1039
|
+
size: "sm",
|
|
1040
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalDialog, { children: ({ close }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1041
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalHeading, { children: t("users.deleteTitle") }) }),
|
|
1042
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ModalBody, {
|
|
1043
|
+
className: "rmq:flex rmq:flex-col rmq:gap-3",
|
|
1044
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: t("users.deleteDescription", { name: userToDelete?.name }) }), deleteError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert$1, {
|
|
1045
|
+
status: "danger",
|
|
1046
|
+
"data-cy": "rabbitmq-user-delete-error-alert",
|
|
1047
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent$1, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription$1, { children: tMessage(deleteError) }) })
|
|
1048
|
+
})]
|
|
1049
|
+
}),
|
|
1050
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ModalFooter, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
1051
|
+
variant: "secondary",
|
|
1052
|
+
onPress: close,
|
|
1053
|
+
"data-cy": "rabbitmq-user-delete-cancel-button",
|
|
1054
|
+
children: t("common.cancel")
|
|
1055
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
1056
|
+
variant: "danger",
|
|
1057
|
+
onPress: () => void confirmDelete(),
|
|
1058
|
+
isPending: deleting,
|
|
1059
|
+
"data-cy": "rabbitmq-user-delete-confirm-button",
|
|
1060
|
+
children: t("common.delete")
|
|
1061
|
+
})] })
|
|
1062
|
+
] }) })
|
|
1063
|
+
}) });
|
|
1064
|
+
}
|
|
1065
|
+
//#endregion
|
|
1066
|
+
//#region frontend/src/users/RabbitmqUserPanel.tsx
|
|
1067
|
+
var { Alert, AlertContent, AlertDescription, Button, Card, Chip, Modal, Spinner, Table, TableBody, TableCell, TableColumn, TableContent, TableHeader, TableRow, TableScrollContainer } = await importShared("@heroui/react");
|
|
1068
|
+
var { KeyRoundIcon, PencilIcon, Trash2Icon } = await importShared("lucide-react");
|
|
1069
|
+
function PermissionChips({ user }) {
|
|
1070
|
+
const { t } = useRabbitmqTranslations();
|
|
1071
|
+
if (user.permissions.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1072
|
+
className: "rmq:text-xs rmq:text-default-400",
|
|
1073
|
+
children: t("users.none")
|
|
1074
|
+
});
|
|
1075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1076
|
+
className: "rmq:flex rmq:flex-wrap rmq:gap-1",
|
|
1077
|
+
children: user.permissions.map((permission) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
1078
|
+
size: "sm",
|
|
1079
|
+
variant: "soft",
|
|
1080
|
+
title: t("permissions.summary", { ...permission }),
|
|
1081
|
+
children: permission.vhost
|
|
1082
|
+
}, permission.vhost))
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
function RabbitmqUserPanel({ mqttServerId }) {
|
|
1086
|
+
const model = useRabbitmqUserPanelState({ mqttServerId });
|
|
1087
|
+
if (!model.manageable) return null;
|
|
953
1088
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card, {
|
|
954
1089
|
"data-cy": `rabbitmq-user-panel-${mqttServerId}`,
|
|
955
1090
|
className: "rmq:w-full rmq:border rmq:border-default-200 rmq:dark:border-default-100",
|
|
956
1091
|
children: [
|
|
957
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
})]
|
|
965
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
966
|
-
className: "rmq:flex rmq:items-center rmq:gap-2",
|
|
967
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
968
|
-
isIconOnly: true,
|
|
969
|
-
size: "sm",
|
|
970
|
-
variant: "ghost",
|
|
971
|
-
"aria-label": t("users.reload"),
|
|
972
|
-
onPress: () => void reload(),
|
|
973
|
-
isDisabled: loading,
|
|
974
|
-
"data-cy": `rabbitmq-user-panel-reload-${mqttServerId}`,
|
|
975
|
-
children: loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { size: "sm" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RefreshCwIcon, { className: "rmq:w-4 rmq:h-4" })
|
|
976
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button, {
|
|
977
|
-
size: "sm",
|
|
978
|
-
variant: "primary",
|
|
979
|
-
onPress: () => {
|
|
980
|
-
setFormUser(null);
|
|
981
|
-
setFormOpen(true);
|
|
982
|
-
},
|
|
983
|
-
"data-cy": `rabbitmq-user-panel-create-button-${mqttServerId}`,
|
|
984
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PlusIcon, { className: "rmq:w-4 rmq:h-4" }), t("users.add")]
|
|
985
|
-
})]
|
|
986
|
-
})]
|
|
1092
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RabbitmqUserPanelCardHeader, {
|
|
1093
|
+
t: model.t,
|
|
1094
|
+
reload: model.reload,
|
|
1095
|
+
loading: model.loading,
|
|
1096
|
+
mqttServerId,
|
|
1097
|
+
setFormUser: model.setFormUser,
|
|
1098
|
+
setFormOpen: model.setFormOpen
|
|
987
1099
|
}),
|
|
988
1100
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Card.Content, {
|
|
989
1101
|
className: "rmq:flex rmq:flex-col rmq:gap-3",
|
|
990
1102
|
children: [
|
|
991
|
-
loadError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert, {
|
|
1103
|
+
model.loadError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert, {
|
|
992
1104
|
status: "danger",
|
|
993
1105
|
"data-cy": "rabbitmq-user-panel-error-alert",
|
|
994
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription, { children: tMessage(loadError) }) })
|
|
1106
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription, { children: model.tMessage(model.loadError) }) })
|
|
995
1107
|
}),
|
|
996
|
-
!data && !loadError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1108
|
+
!model.data && !model.loadError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
997
1109
|
className: "rmq:flex rmq:items-center rmq:justify-center rmq:p-4",
|
|
998
1110
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { "data-cy": "rabbitmq-user-panel-loading-spinner" })
|
|
999
1111
|
}),
|
|
1000
|
-
data && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Table, {
|
|
1112
|
+
model.data && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Table, {
|
|
1001
1113
|
"data-cy": "rabbitmq-user-panel-table",
|
|
1002
1114
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableScrollContainer, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableContent, {
|
|
1003
|
-
"aria-label": t("users.title"),
|
|
1115
|
+
"aria-label": model.t("users.title"),
|
|
1004
1116
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableHeader, { children: [
|
|
1005
1117
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableColumn, {
|
|
1006
1118
|
isRowHeader: true,
|
|
1007
|
-
children: t("users.username")
|
|
1119
|
+
children: model.t("users.username")
|
|
1008
1120
|
}),
|
|
1009
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableColumn, { children: t("users.tags") }),
|
|
1010
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableColumn, { children: t("users.access") }),
|
|
1011
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableColumn, { children: t("users.actions") })
|
|
1121
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableColumn, { children: model.t("users.tags") }),
|
|
1122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableColumn, { children: model.t("users.access") }),
|
|
1123
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableColumn, { children: model.t("users.actions") })
|
|
1012
1124
|
] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableBody, {
|
|
1013
|
-
items: data.users,
|
|
1014
|
-
dependencies: [language],
|
|
1125
|
+
items: model.data.users,
|
|
1126
|
+
dependencies: [model.language],
|
|
1015
1127
|
children: (user) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TableRow, {
|
|
1016
1128
|
id: user.name,
|
|
1017
1129
|
children: [
|
|
@@ -1021,7 +1133,7 @@ function RabbitmqUserPanel({ mqttServerId }) {
|
|
|
1021
1133
|
}),
|
|
1022
1134
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TableCell, { children: user.tags.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
1023
1135
|
className: "rmq:text-xs rmq:text-default-400",
|
|
1024
|
-
children: t("users.none")
|
|
1136
|
+
children: model.t("users.none")
|
|
1025
1137
|
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
1026
1138
|
className: "rmq:flex rmq:flex-wrap rmq:gap-1",
|
|
1027
1139
|
children: user.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Chip, {
|
|
@@ -1039,10 +1151,10 @@ function RabbitmqUserPanel({ mqttServerId }) {
|
|
|
1039
1151
|
isIconOnly: true,
|
|
1040
1152
|
size: "sm",
|
|
1041
1153
|
variant: "ghost",
|
|
1042
|
-
"aria-label": t("users.edit", { name: user.name }),
|
|
1154
|
+
"aria-label": model.t("users.edit", { name: user.name }),
|
|
1043
1155
|
onPress: () => {
|
|
1044
|
-
setFormUser(user);
|
|
1045
|
-
setFormOpen(true);
|
|
1156
|
+
model.setFormUser(user);
|
|
1157
|
+
model.setFormOpen(true);
|
|
1046
1158
|
},
|
|
1047
1159
|
"data-cy": `rabbitmq-user-edit-button-${user.name}`,
|
|
1048
1160
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PencilIcon, { className: "rmq:w-4 rmq:h-4" })
|
|
@@ -1051,8 +1163,8 @@ function RabbitmqUserPanel({ mqttServerId }) {
|
|
|
1051
1163
|
isIconOnly: true,
|
|
1052
1164
|
size: "sm",
|
|
1053
1165
|
variant: "ghost",
|
|
1054
|
-
"aria-label": t("users.permissions", { name: user.name }),
|
|
1055
|
-
onPress: () => setPermissionsUser(user),
|
|
1166
|
+
"aria-label": model.t("users.permissions", { name: user.name }),
|
|
1167
|
+
onPress: () => model.setPermissionsUser(user),
|
|
1056
1168
|
"data-cy": `rabbitmq-user-permissions-button-${user.name}`,
|
|
1057
1169
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(KeyRoundIcon, { className: "rmq:w-4 rmq:h-4" })
|
|
1058
1170
|
}),
|
|
@@ -1060,10 +1172,10 @@ function RabbitmqUserPanel({ mqttServerId }) {
|
|
|
1060
1172
|
isIconOnly: true,
|
|
1061
1173
|
size: "sm",
|
|
1062
1174
|
variant: "ghost",
|
|
1063
|
-
"aria-label": t("users.delete", { name: user.name }),
|
|
1175
|
+
"aria-label": model.t("users.delete", { name: user.name }),
|
|
1064
1176
|
onPress: () => {
|
|
1065
|
-
setDeleteError(null);
|
|
1066
|
-
setUserToDelete(user);
|
|
1177
|
+
model.setDeleteError(null);
|
|
1178
|
+
model.setUserToDelete(user);
|
|
1067
1179
|
},
|
|
1068
1180
|
"data-cy": `rabbitmq-user-delete-button-${user.name}`,
|
|
1069
1181
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Trash2Icon, { className: "rmq:w-4 rmq:h-4 rmq:text-danger" })
|
|
@@ -1079,52 +1191,27 @@ function RabbitmqUserPanel({ mqttServerId }) {
|
|
|
1079
1191
|
}),
|
|
1080
1192
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RabbitmqUserFormModal, {
|
|
1081
1193
|
mqttServerId,
|
|
1082
|
-
isOpen: formOpen,
|
|
1083
|
-
user: formUser,
|
|
1084
|
-
vhosts: data?.vhosts ?? [],
|
|
1085
|
-
onClose: () => setFormOpen(false),
|
|
1086
|
-
onSaved: () => void reload()
|
|
1194
|
+
isOpen: model.formOpen,
|
|
1195
|
+
user: model.formUser,
|
|
1196
|
+
vhosts: model.data?.vhosts ?? [],
|
|
1197
|
+
onClose: () => model.setFormOpen(false),
|
|
1198
|
+
onSaved: () => void model.reload()
|
|
1087
1199
|
}),
|
|
1088
1200
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(RabbitmqPermissionsModal, {
|
|
1089
1201
|
mqttServerId,
|
|
1090
|
-
isOpen: permissionsUser !== null,
|
|
1091
|
-
user: permissionsUser,
|
|
1092
|
-
vhosts: data?.vhosts ?? [],
|
|
1093
|
-
onClose: () => setPermissionsUser(null),
|
|
1094
|
-
onSaved: () => void reload()
|
|
1202
|
+
isOpen: model.permissionsUser !== null,
|
|
1203
|
+
user: model.permissionsUser,
|
|
1204
|
+
vhosts: model.data?.vhosts ?? [],
|
|
1205
|
+
onClose: () => model.setPermissionsUser(null),
|
|
1206
|
+
onSaved: () => void model.reload()
|
|
1095
1207
|
}),
|
|
1096
1208
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Modal, {
|
|
1097
|
-
isOpen: userToDelete !== null,
|
|
1209
|
+
isOpen: model.userToDelete !== null,
|
|
1098
1210
|
onOpenChange: (open) => {
|
|
1099
|
-
if (!open) setUserToDelete(null);
|
|
1211
|
+
if (!open) model.setUserToDelete(null);
|
|
1100
1212
|
},
|
|
1101
1213
|
"data-cy": `rabbitmq-user-delete-modal-${mqttServerId}`,
|
|
1102
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1103
|
-
size: "sm",
|
|
1104
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalDialog, { children: ({ close }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1105
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ModalHeading, { children: t("users.deleteTitle") }) }),
|
|
1106
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ModalBody, {
|
|
1107
|
-
className: "rmq:flex rmq:flex-col rmq:gap-3",
|
|
1108
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: t("users.deleteDescription", { name: userToDelete?.name }) }), deleteError && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Alert, {
|
|
1109
|
-
status: "danger",
|
|
1110
|
-
"data-cy": "rabbitmq-user-delete-error-alert",
|
|
1111
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AlertDescription, { children: tMessage(deleteError) }) })
|
|
1112
|
-
})]
|
|
1113
|
-
}),
|
|
1114
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ModalFooter, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
1115
|
-
variant: "secondary",
|
|
1116
|
-
onPress: close,
|
|
1117
|
-
"data-cy": "rabbitmq-user-delete-cancel-button",
|
|
1118
|
-
children: t("common.cancel")
|
|
1119
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, {
|
|
1120
|
-
variant: "danger",
|
|
1121
|
-
onPress: () => void confirmDelete(),
|
|
1122
|
-
isPending: deleting,
|
|
1123
|
-
"data-cy": "rabbitmq-user-delete-confirm-button",
|
|
1124
|
-
children: t("common.delete")
|
|
1125
|
-
})] })
|
|
1126
|
-
] }) })
|
|
1127
|
-
}) })
|
|
1214
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RabbitmqUserPanelModalBackdrop, { ...model })
|
|
1128
1215
|
})
|
|
1129
1216
|
]
|
|
1130
1217
|
});
|
package/frontend/remoteEntry.js
CHANGED
|
@@ -75,7 +75,7 @@ var exportSet = /* @__PURE__ */ new Set([
|
|
|
75
75
|
]);
|
|
76
76
|
var moduleMap = { "./plugin": () => {
|
|
77
77
|
dynamicLoadingCss(["style.css"], false, "./plugin");
|
|
78
|
-
return __federation_import("./__federation_expose_Plugin-
|
|
78
|
+
return __federation_import("./__federation_expose_Plugin-5jDTnovW.js").then((module) => Object.keys(module).every((item) => exportSet.has(item)) ? () => module.default : () => module);
|
|
79
79
|
} };
|
|
80
80
|
var seen = {};
|
|
81
81
|
var dynamicLoadingCss = (cssFilePaths, dontAppendStylesToHead, exposeItemName) => {
|