@expcluster/permission-groups 7.0.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.
Files changed (91) hide show
  1. package/LICENSE.md +21 -0
  2. package/controller.ts +434 -0
  3. package/dist/browser/messages.d.ts +527 -0
  4. package/dist/browser/messages.d.ts.map +1 -0
  5. package/dist/browser/messages.js +561 -0
  6. package/dist/browser/messages.js.map +1 -0
  7. package/dist/browser/package.json +49 -0
  8. package/dist/browser/tsconfig.browser.tsbuildinfo +1 -0
  9. package/dist/browser/web/components/AssignmentForm.d.ts +7 -0
  10. package/dist/browser/web/components/AssignmentForm.d.ts.map +1 -0
  11. package/dist/browser/web/components/AssignmentForm.js +29 -0
  12. package/dist/browser/web/components/AssignmentForm.js.map +1 -0
  13. package/dist/browser/web/components/AssignmentsTable.d.ts +2 -0
  14. package/dist/browser/web/components/AssignmentsTable.d.ts.map +1 -0
  15. package/dist/browser/web/components/AssignmentsTable.js +61 -0
  16. package/dist/browser/web/components/AssignmentsTable.js.map +1 -0
  17. package/dist/browser/web/components/DeleteConfirm.d.ts +6 -0
  18. package/dist/browser/web/components/DeleteConfirm.d.ts.map +1 -0
  19. package/dist/browser/web/components/DeleteConfirm.js +7 -0
  20. package/dist/browser/web/components/DeleteConfirm.js.map +1 -0
  21. package/dist/browser/web/components/GroupForm.d.ts +5 -0
  22. package/dist/browser/web/components/GroupForm.d.ts.map +1 -0
  23. package/dist/browser/web/components/GroupForm.js +22 -0
  24. package/dist/browser/web/components/GroupForm.js.map +1 -0
  25. package/dist/browser/web/components/GroupViewPage.d.ts +2 -0
  26. package/dist/browser/web/components/GroupViewPage.d.ts.map +1 -0
  27. package/dist/browser/web/components/GroupViewPage.js +161 -0
  28. package/dist/browser/web/components/GroupViewPage.js.map +1 -0
  29. package/dist/browser/web/components/GroupsTable.d.ts +2 -0
  30. package/dist/browser/web/components/GroupsTable.d.ts.map +1 -0
  31. package/dist/browser/web/components/GroupsTable.js +29 -0
  32. package/dist/browser/web/components/GroupsTable.js.map +1 -0
  33. package/dist/browser/web/components/RoleMappingForm.d.ts +7 -0
  34. package/dist/browser/web/components/RoleMappingForm.d.ts.map +1 -0
  35. package/dist/browser/web/components/RoleMappingForm.js +32 -0
  36. package/dist/browser/web/components/RoleMappingForm.js.map +1 -0
  37. package/dist/browser/web/components/RoleMappingsTable.d.ts +2 -0
  38. package/dist/browser/web/components/RoleMappingsTable.d.ts.map +1 -0
  39. package/dist/browser/web/components/RoleMappingsTable.js +64 -0
  40. package/dist/browser/web/components/RoleMappingsTable.js.map +1 -0
  41. package/dist/browser/web/index.d.ts +13 -0
  42. package/dist/browser/web/index.d.ts.map +1 -0
  43. package/dist/browser/web/index.js +60 -0
  44. package/dist/browser/web/index.js.map +1 -0
  45. package/dist/node/controller.d.ts +37 -0
  46. package/dist/node/controller.d.ts.map +1 -0
  47. package/dist/node/controller.js +372 -0
  48. package/dist/node/controller.js.map +1 -0
  49. package/dist/node/index.d.ts +10 -0
  50. package/dist/node/index.d.ts.map +1 -0
  51. package/dist/node/index.js +196 -0
  52. package/dist/node/index.js.map +1 -0
  53. package/dist/node/instance.d.ts +40 -0
  54. package/dist/node/instance.d.ts.map +1 -0
  55. package/dist/node/instance.js +155 -0
  56. package/dist/node/instance.js.map +1 -0
  57. package/dist/node/messages.d.ts +527 -0
  58. package/dist/node/messages.d.ts.map +1 -0
  59. package/dist/node/messages.js +620 -0
  60. package/dist/node/messages.js.map +1 -0
  61. package/dist/node/tsconfig.node.tsbuildinfo +1 -0
  62. package/dist/web/manifest.json +10 -0
  63. package/dist/web/static/exp_groups.afefd90b210f7c8e0df2.js +543 -0
  64. package/dist/web/static/index_ts.f7d30aa0c13ff0be393a.js +22 -0
  65. package/dist/web/static/main.c2178975889c1c720e80.js +653 -0
  66. package/dist/web/static/messages_ts.65a81c17fb37953c5d68.js +22 -0
  67. package/dist/web/static/package_json.aab0d3f37da0567c250c.js +22 -0
  68. package/dist/web/static/vendors-node_modules_pnpm_ant-design_icons_6_2_3_rea_94b50600dfe79448cabf92d130d83059_node_mo-c79f54.cf768c64b40c811ce6c9.js +273 -0
  69. package/dist/web/static/vendors-node_modules_pnpm_sinclair_typebox_0_30_4_node_modules_sinclair_typebox_typebox_js.7fa46fac84f2e9324e54.js +22 -0
  70. package/dist/web/static/web_index_tsx-webpack_sharing_consume_default_react.b4766180f4d467b7b24f.js +102 -0
  71. package/index.ts +183 -0
  72. package/instance.ts +171 -0
  73. package/messages.ts +692 -0
  74. package/module/control.lua +438 -0
  75. package/module/globals.lua +11 -0
  76. package/module/module.json +12 -0
  77. package/module/module_exports.lua +3 -0
  78. package/package.json +47 -0
  79. package/tsconfig.browser.json +4 -0
  80. package/tsconfig.json +7 -0
  81. package/tsconfig.node.json +5 -0
  82. package/web/components/AssignmentForm.tsx +74 -0
  83. package/web/components/AssignmentsTable.tsx +111 -0
  84. package/web/components/DeleteConfirm.tsx +16 -0
  85. package/web/components/GroupForm.tsx +45 -0
  86. package/web/components/GroupViewPage.tsx +287 -0
  87. package/web/components/GroupsTable.tsx +49 -0
  88. package/web/components/RoleMappingForm.tsx +106 -0
  89. package/web/components/RoleMappingsTable.tsx +107 -0
  90. package/web/index.tsx +108 -0
  91. package/webpack.config.js +34 -0
@@ -0,0 +1,107 @@
1
+ import React, { useContext, useState } from "react";
2
+ import { Table, Button, Space, Tag } from "antd";
3
+ import { EditOutlined } from "@ant-design/icons";
4
+
5
+ import { ControlContext, useAccount, useRoles } from "@clusterio/web_ui";
6
+ import { RoleMappingRecord, RoleMappingDeleteRequest } from "../../messages";
7
+ import type { WebPlugin } from "..";
8
+
9
+ import RoleMappingForm from "./RoleMappingForm";
10
+ import DeletedConfirm from "./DeleteConfirm";
11
+
12
+ export default function RoleMappingsTable() {
13
+ const control = useContext(ControlContext);
14
+ const plugin = control.plugins.get("exp_groups") as WebPlugin;
15
+ const account = useAccount();
16
+
17
+ const [roleMappings, roleMappingsSynced] = plugin.useRoleMappings();
18
+ const [groups, groupsSynced] = plugin.useGroups();
19
+ const [roles, rolesSynced] = useRoles();
20
+
21
+ const [editing, setEditing] = useState<RoleMappingRecord | undefined>();
22
+ const [open, setOpen] = useState(false);
23
+
24
+ const roleMappingArray = [...roleMappings.values()];
25
+
26
+ const roleFilters = [...roles.values()]
27
+ .filter(role => roleMappingArray.some(mapping => mapping.roleIds.has(role.id)))
28
+ .map(role => ({ text: role.name, value: role.id }));
29
+
30
+ const groupFilters = [...groups.values()]
31
+ .filter(group => roleMappingArray.some(mapping => mapping.groupId === group.id))
32
+ .map(group => ({ text: group.name, value: group.id }))
33
+
34
+ return <>
35
+ <Table
36
+ columns={[
37
+ {
38
+ title: "Priority",
39
+ dataIndex: "priority",
40
+ width: "10%",
41
+ },
42
+ {
43
+ title: "Roles",
44
+ filters: roleFilters,
45
+ onFilter: (value, record: RoleMappingRecord) => (
46
+ record.roleIds.has(value as number)
47
+ ),
48
+ render: (_: any, record: RoleMappingRecord) => (
49
+ [...record.roleIds].map(id => <Tag key={id}>{roles.get(id)?.name ?? id}</Tag>)
50
+ ),
51
+ },
52
+ {
53
+ title: "Group",
54
+ width: "30%",
55
+ filters: groupFilters,
56
+ onFilter: (value, record: RoleMappingRecord) => (
57
+ record.groupId === value
58
+ ),
59
+ render: (_: any, record: RoleMappingRecord) => (
60
+ groups.get(record.groupId)?.name ?? record.groupId
61
+ ),
62
+ },
63
+ {
64
+ title: "Enabled",
65
+ width: "10%",
66
+ filters: [
67
+ { text: "Enabled", value: true },
68
+ { text: "Disabled", value: false },
69
+ ],
70
+ onFilter: (value, record: RoleMappingRecord) => (
71
+ record.enabled === value
72
+ ),
73
+ render: (_: any, record: RoleMappingRecord) => (
74
+ record.enabled ? "Yes" : "No"
75
+ ),
76
+ },
77
+ ...(account.hasAnyPermission(
78
+ "exp_groups.role_mapping.update",
79
+ "exp_groups.role_mapping.delete",
80
+ ) ? [{
81
+ title: "Actions",
82
+ width: "10%",
83
+ render: (_: any, record: any) => (
84
+ <Space>
85
+ {account.hasPermission("exp_groups.role_mapping.update") && <Button
86
+ icon={<EditOutlined />}
87
+ onClick={() => {
88
+ setEditing(record);
89
+ setOpen(true);
90
+ }}
91
+ />}
92
+ {account.hasPermission("exp_groups.role_mapping.delete") && <DeletedConfirm
93
+ onConfirm={() => control.send(new RoleMappingDeleteRequest(record.id))}
94
+ />}
95
+ </Space>
96
+ ),
97
+ }] : []),
98
+ ]}
99
+ dataSource={roleMappingArray.sort((a, b) => b.priority - a.priority)}
100
+ loading={!roleMappingsSynced || !groupsSynced || !rolesSynced}
101
+ rowKey={(m) => m.id}
102
+ pagination={false}
103
+ />
104
+
105
+ <RoleMappingForm open={open} setOpen={setOpen} initial={editing} />
106
+ </>;
107
+ }
package/web/index.tsx ADDED
@@ -0,0 +1,108 @@
1
+ import React, { useState, useCallback, useSyncExternalStore } from "react";
2
+ import { BaseWebPlugin, PageLayout, PageHeader, useAccount, SectionHeader } from "@clusterio/web_ui";
3
+ import { Button } from "antd";
4
+
5
+ import * as messages from "../messages";
6
+ import * as lib from "@clusterio/lib";
7
+
8
+ import GroupsTable from "./components/GroupsTable";
9
+ import AssignmentsTable from "./components/AssignmentsTable";
10
+ import RoleMappingsTable from "./components/RoleMappingsTable";
11
+ import GroupViewPage from "./components/GroupViewPage";
12
+ import GroupForm from "./components/GroupForm";
13
+ import RoleMappingForm from "./components/RoleMappingForm";
14
+ import AssignmentForm from "./components/AssignmentForm";
15
+
16
+
17
+ function ExpGroupsPage() {
18
+ const account = useAccount();
19
+
20
+ const [groupOpen, setGroupOpen] = useState(false);
21
+ const [assignmentOpen, setAssignmentOpen] = useState(false);
22
+ const [roleMappingOpen, setRoleMappingOpen] = useState(false);
23
+
24
+ return <PageLayout nav={[{ name: "Permission Groups" }]}>
25
+ <PageHeader title="Permission Groups" />
26
+
27
+ {account.hasPermission("exp_groups.group.list") && <>
28
+ <SectionHeader
29
+ title="Groups"
30
+ extra={
31
+ account.hasPermission("exp_groups.group.create")
32
+ ? <Button type="primary" onClick={() => setGroupOpen(true)}>Create</Button>
33
+ : undefined
34
+ }
35
+ />
36
+ <GroupsTable />
37
+ <GroupForm open={groupOpen} setOpen={setGroupOpen} />
38
+ </>}
39
+
40
+ {account.hasPermission("exp_groups.role_mapping.list") && <>
41
+ <SectionHeader
42
+ title="Role Mappings"
43
+ extra={
44
+ account.hasPermission("exp_groups.role_mapping.create")
45
+ ? <Button type="primary" onClick={() => setRoleMappingOpen(true)}>Create</Button>
46
+ : undefined
47
+ }
48
+ />
49
+ <RoleMappingsTable />
50
+ <RoleMappingForm open={roleMappingOpen} setOpen={setRoleMappingOpen} />
51
+ </>}
52
+
53
+ {account.hasPermission("exp_groups.assignment.list") && <>
54
+ <SectionHeader
55
+ title="Assignments"
56
+ extra={
57
+ account.hasPermission("exp_groups.assignment.create")
58
+ ? <Button type="primary" onClick={() => setAssignmentOpen(true)}>Create</Button>
59
+ : undefined
60
+ }
61
+ />
62
+ <AssignmentsTable />
63
+ <AssignmentForm open={assignmentOpen} setOpen={setAssignmentOpen} />
64
+ </>}
65
+ </PageLayout>;
66
+ }
67
+
68
+ export class WebPlugin extends BaseWebPlugin {
69
+ groups = new lib.MapSubscriber(messages.GroupUpdatedEvent, this.control);
70
+ assignments = new lib.MapSubscriber(messages.ManualAssignmentUpdatedEvent, this.control);
71
+ roleMappings = new lib.MapSubscriber(messages.RoleMappingUpdatedEvent, this.control);
72
+
73
+ async init() {
74
+ this.pages = [
75
+ {
76
+ path: "/permission_groups",
77
+ sidebarName: "Permission Groups",
78
+ permission: (account => account.hasAnyPermission(
79
+ "exp_groups.group.list",
80
+ "exp_groups.assignment.list",
81
+ "exp_groups.role_mapping.list",
82
+ )),
83
+ content: <ExpGroupsPage />,
84
+ },
85
+ {
86
+ path: "/permission_groups/:id/view",
87
+ sidebarPath: "/permission_groups",
88
+ permission: "exp_groups.group.get",
89
+ content: <GroupViewPage />,
90
+ },
91
+ ];
92
+ }
93
+
94
+ useGroups() {
95
+ const subscribe = useCallback((cb: () => void) => this.groups.subscribe(cb), []);
96
+ return useSyncExternalStore(subscribe, () => this.groups.getSnapshot());
97
+ }
98
+
99
+ useAssignments() {
100
+ const subscribe = useCallback((cb: () => void) => this.assignments.subscribe(cb), []);
101
+ return useSyncExternalStore(subscribe, () => this.assignments.getSnapshot());
102
+ }
103
+
104
+ useRoleMappings() {
105
+ const subscribe = useCallback((cb: () => void) => this.roleMappings.subscribe(cb), []);
106
+ return useSyncExternalStore(subscribe, () => this.roleMappings.getSnapshot());
107
+ }
108
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ const path = require("path");
3
+ const webpack = require("webpack");
4
+ const { merge } = require("webpack-merge");
5
+
6
+ const common = require("@clusterio/web_ui/webpack.common");
7
+
8
+ module.exports = (env = {}) => merge(common(env), {
9
+ context: __dirname,
10
+ entry: "./web/index.tsx",
11
+ output: {
12
+ path: path.resolve(__dirname, "dist", "web"),
13
+ },
14
+ plugins: [
15
+ new webpack.container.ModuleFederationPlugin({
16
+ name: "exp_groups",
17
+ library: { type: "window", name: "plugin_exp_groups" },
18
+ exposes: {
19
+ "./": "./index.ts",
20
+ "./package.json": "./package.json",
21
+ "./web": "./web/index.tsx",
22
+ },
23
+ shared: {
24
+ "@clusterio/lib": { import: false },
25
+ "@clusterio/web_ui": { import: false },
26
+ "antd": { import: false },
27
+ "react": { import: false },
28
+ "react-dom": { import: false },
29
+ "react-router": { import: false },
30
+ "react-router-dom": { import: false },
31
+ },
32
+ }),
33
+ ],
34
+ });