mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-12 15:04:52 +09:00
Add a permission group list to the role page
A sticky list of permission groups sits left of the permissions. Clicking an entry scrolls to that group, and its dot is blue when any permission in the group is granted, grey otherwise. Same layout as the ExpCluster scenario features page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7b2f7064b9
commit
2b272d230c
1 file changed
+60
-15
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useContext, useState, useMemo } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { Button, Checkbox, Input, Popconfirm, Space, Spin, Tooltip } from "antd";
|
||||
import { Button, Checkbox, Col, Input, Popconfirm, Row, Space, Spin, Tooltip } from "antd";
|
||||
import { ExclamationCircleOutlined, StarOutlined, DeleteOutlined} from "@ant-design/icons";
|
||||
|
||||
import * as lib from "@clusterio/lib";
|
||||
@@ -109,7 +109,9 @@ function PermissionGroup({
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ border: "1px solid #424242", padding: 12, borderRadius: 6 }}>
|
||||
<div id={`permission-group-${groupName}`} style={{
|
||||
border: "1px solid #424242", padding: 12, borderRadius: 6, scrollMarginTop: 80,
|
||||
}}>
|
||||
<Space style={{ width: "100%", justifyContent: "space-between" }}>
|
||||
<strong>{formatGroupTitle(groupName)}</strong>
|
||||
<Space>
|
||||
@@ -134,6 +136,30 @@ function PermissionGroup({
|
||||
);
|
||||
}
|
||||
|
||||
/** An entry in the group list; the dot is blue when any permission in the group is granted */
|
||||
function PermissionGroupNav({ groupName, granted }: { groupName: string; granted: boolean }) {
|
||||
function scrollToGroup() {
|
||||
document.getElementById(`permission-group-${groupName}`)?.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
role="button"
|
||||
onClick={scrollToGroup}
|
||||
style={{ display: "flex", alignItems: "center", gap: 8, padding: "4px 8px", cursor: "pointer" }}
|
||||
>
|
||||
<span style={{
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: "50%",
|
||||
flexShrink: 0,
|
||||
background: granted ? "#1677ff" : "#595959",
|
||||
}} />
|
||||
{formatGroupTitle(groupName)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** The role page view */
|
||||
export default function RoleViewPage() {
|
||||
const params = useParams();
|
||||
@@ -209,6 +235,9 @@ export default function RoleViewPage() {
|
||||
permissions.sort((a, b) => a.title.localeCompare(b.title));
|
||||
}
|
||||
|
||||
// Groups with at least one granted permission, including those hidden by the search
|
||||
const grantedGroups = new Set(allPermissions.filter(p => permissionState[p.name]).map(p => getGroupName(p.name)));
|
||||
|
||||
// Check if any changes have been made to the permissions or role metadata
|
||||
const permissionChanged = Object.keys(permissionState).some(k => permissionState[k] !== baselineState[k]);
|
||||
const metaChanged = name !== role.name || description !== role.description;
|
||||
@@ -302,19 +331,35 @@ export default function RoleViewPage() {
|
||||
<Input.Search placeholder="Search permissions" allowClear
|
||||
onChange={e => setSearch(e.target.value)} style={{ marginBottom: 16 }} />
|
||||
|
||||
<Space direction="vertical" style={{ width: "100%" }}>
|
||||
{sortedGroups.map(([groupName, permissions]) => (
|
||||
<PermissionGroup
|
||||
key={groupName}
|
||||
groupName={groupName}
|
||||
permissions={permissions}
|
||||
permissionState={permissionState}
|
||||
baselineState={baselineState}
|
||||
setPermissionState={setPermissionState}
|
||||
canUpdate={canUpdate}
|
||||
/>
|
||||
))}
|
||||
</Space>
|
||||
<Row gutter={16} wrap={false}>
|
||||
<Col flex="200px">
|
||||
{/* Clear of the fixed page header */}
|
||||
<div style={{ position: "sticky", top: 80 }}>
|
||||
{sortedGroups.map(([groupName]) => (
|
||||
<PermissionGroupNav
|
||||
key={groupName}
|
||||
groupName={groupName}
|
||||
granted={grantedGroups.has(groupName)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Col>
|
||||
<Col flex="auto" style={{ minWidth: 0 }}>
|
||||
<Space direction="vertical" style={{ width: "100%" }}>
|
||||
{sortedGroups.map(([groupName, permissions]) => (
|
||||
<PermissionGroup
|
||||
key={groupName}
|
||||
groupName={groupName}
|
||||
permissions={permissions}
|
||||
permissionState={permissionState}
|
||||
baselineState={baselineState}
|
||||
setPermissionState={setPermissionState}
|
||||
canUpdate={canUpdate}
|
||||
/>
|
||||
))}
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<PluginExtra component="RoleViewPage" role={role} search={search}/>
|
||||
</PageLayout>
|
||||
|
||||
Reference in new issue
Block a user