mirror of
https://github.com/stoatchat/for-legacy-web.git
synced 2026-03-08 09:55:28 +00:00
@@ -2,7 +2,7 @@ import { XCircle } from "@styled-icons/boxicons-regular";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { API } from "revolt.js";
|
||||
import { Server } from "revolt.js/dist/maps/Servers";
|
||||
import { Server } from "revolt.js/esm/maps/Servers";
|
||||
|
||||
import styles from "./Panes.module.scss";
|
||||
import { Text } from "preact-i18n";
|
||||
|
||||
@@ -2,8 +2,8 @@ import { ChevronDown } from "@styled-icons/boxicons-regular";
|
||||
import { isEqual } from "lodash";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Virtuoso } from "react-virtuoso";
|
||||
import { Member } from "revolt.js/dist/maps/Members";
|
||||
import { Server } from "revolt.js/dist/maps/Servers";
|
||||
import { Member } from "revolt.js/esm/maps/Members";
|
||||
import { Server } from "revolt.js/esm/maps/Servers";
|
||||
|
||||
import styles from "./Panes.module.scss";
|
||||
import { Text } from "preact-i18n";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Markdown } from "@styled-icons/boxicons-logos";
|
||||
import isEqual from "lodash.isequal";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Server } from "revolt.js/dist/maps/Servers";
|
||||
import { Server } from "revolt.js/esm/maps/Servers";
|
||||
|
||||
import styles from "./Panes.module.scss";
|
||||
import { Text } from "preact-i18n";
|
||||
|
||||
@@ -116,48 +116,3 @@
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.roles {
|
||||
gap: 12px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
|
||||
.list {
|
||||
width: 160px;
|
||||
flex-shrink: 0;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.permissions {
|
||||
flex-grow: 1;
|
||||
padding: 0 8px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.title {
|
||||
gap: 8px;
|
||||
display: flex;
|
||||
margin-bottom: 1em;
|
||||
align-items: center;
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
svg {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
gap: 8px;
|
||||
display: flex;
|
||||
padding: 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
import isEqual from "lodash.isequal";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Server } from "revolt.js/dist/maps/Servers";
|
||||
import { Server } from "revolt.js/esm/maps/Servers";
|
||||
|
||||
import { useLayoutEffect, useMemo, useState } from "preact/hooks";
|
||||
import { useMemo, useState } from "preact/hooks";
|
||||
|
||||
import { useIntermediate } from "../../../context/intermediate/Intermediate";
|
||||
|
||||
import Button from "../../../components/ui/Button";
|
||||
import Checkbox from "../../../components/ui/Checkbox";
|
||||
import ColourSwatches from "../../../components/ui/ColourSwatches";
|
||||
import InputBox from "../../../components/ui/InputBox";
|
||||
import Overline from "../../../components/ui/Overline";
|
||||
import { Button, PermissionsLayout, SpaceBetween, H1 } from "@revoltchat/ui";
|
||||
|
||||
import { PermissionList } from "../../../components/settings/roles/PermissionList";
|
||||
import {
|
||||
RoleOrDefault,
|
||||
RoleSelection,
|
||||
} from "../../../components/settings/roles/RoleSelection";
|
||||
import { UnsavedChanges } from "../../../components/settings/roles/UnsavedChanges";
|
||||
import { RoleOrDefault } from "../../../components/settings/roles/RoleSelection";
|
||||
|
||||
interface Props {
|
||||
server: Server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to memo-ize role information.
|
||||
* @param server Target server
|
||||
* @returns Role array
|
||||
*/
|
||||
export function useRoles(server: Server) {
|
||||
return useMemo(
|
||||
() =>
|
||||
@@ -38,151 +41,183 @@ export function useRoles(server: Server) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Roles settings menu
|
||||
*/
|
||||
export const Roles = observer(({ server }: Props) => {
|
||||
// Consolidate all permissions that we can change right now.
|
||||
const currentRoles = useRoles(server);
|
||||
|
||||
// Keep track of whatever role we're editing right now.
|
||||
const [selected, setSelected] = useState("default");
|
||||
const [value, setValue] = useState<Partial<RoleOrDefault>>({});
|
||||
const currentRole = currentRoles.find((x) => x.id === selected)!;
|
||||
const currentRoleValue = { ...currentRole, ...value };
|
||||
|
||||
// If a role gets deleted, unselect it immediately.
|
||||
useLayoutEffect(() => {
|
||||
if (!server.roles) return;
|
||||
if (!server.roles[selected]) {
|
||||
setSelected("default");
|
||||
}
|
||||
}, [server.roles]);
|
||||
|
||||
// Calculate permissions we have access to on this server.
|
||||
const current = server.permission;
|
||||
|
||||
// Upload new role information to server.
|
||||
function save() {
|
||||
const { permissions: permsCurrent, ...current } = currentRole;
|
||||
const { permissions: permsValue, ...value } = currentRoleValue;
|
||||
|
||||
if (!isEqual(permsCurrent, permsValue)) {
|
||||
server.setPermissions(
|
||||
selected,
|
||||
typeof permsValue === "number"
|
||||
? permsValue
|
||||
: {
|
||||
allow: permsValue.a,
|
||||
deny: permsValue.d,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (!isEqual(current, value)) {
|
||||
server.editRole(selected, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the role from this server.
|
||||
function deleteRole() {
|
||||
setSelected("default");
|
||||
server.deleteRole(selected);
|
||||
}
|
||||
// Pull in modal context.
|
||||
const { openScreen } = useIntermediate();
|
||||
|
||||
return (
|
||||
<div style={{ height: "100%", overflowY: "scroll" }}>
|
||||
<h1>Select Role</h1>
|
||||
<RoleSelection
|
||||
selected={selected}
|
||||
onSelect={(id) => {
|
||||
setValue({});
|
||||
setSelected(id);
|
||||
}}
|
||||
roles={currentRoles}
|
||||
/>
|
||||
{selected !== "default" && (
|
||||
<>
|
||||
<hr />
|
||||
<h1>Edit Role</h1>
|
||||
<section>
|
||||
<Overline type="subtle">Role Name</Overline>
|
||||
<p>
|
||||
<InputBox
|
||||
value={currentRoleValue.name}
|
||||
onChange={(e) =>
|
||||
setValue({
|
||||
...value,
|
||||
name: e.currentTarget.value,
|
||||
})
|
||||
}
|
||||
contrast
|
||||
/>
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<Overline type="subtle">Role Colour</Overline>
|
||||
<p>
|
||||
<ColourSwatches
|
||||
value={currentRoleValue.colour ?? "gray"}
|
||||
onChange={(colour) =>
|
||||
setValue({ ...value, colour })
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<Overline type="subtle">Role Options</Overline>
|
||||
<p>
|
||||
<Checkbox
|
||||
checked={currentRoleValue.hoist ?? false}
|
||||
onChange={(hoist) =>
|
||||
setValue({ ...value, hoist })
|
||||
}
|
||||
description="Display this role above others.">
|
||||
Hoist Role
|
||||
</Checkbox>
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<Overline type="subtle">
|
||||
Experimental Role Ranking
|
||||
</Overline>
|
||||
<p>
|
||||
<InputBox
|
||||
value={currentRoleValue.rank ?? 0}
|
||||
onChange={(e) =>
|
||||
setValue({
|
||||
...value,
|
||||
rank: parseInt(e.currentTarget.value),
|
||||
})
|
||||
}
|
||||
contrast
|
||||
/>
|
||||
</p>
|
||||
</section>
|
||||
</>
|
||||
)}
|
||||
{!isEqual(currentRole, currentRoleValue) && (
|
||||
<>
|
||||
<hr />
|
||||
<UnsavedChanges save={save} />
|
||||
</>
|
||||
)}
|
||||
<hr />
|
||||
<h1>Edit Permissions</h1>
|
||||
<PermissionList
|
||||
value={currentRoleValue.permissions}
|
||||
onChange={(permissions) =>
|
||||
setValue({ ...value, permissions } as RoleOrDefault)
|
||||
<PermissionsLayout
|
||||
server={server}
|
||||
onCreateRole={(callback) =>
|
||||
openScreen({
|
||||
id: "special_input",
|
||||
type: "create_role",
|
||||
server: server as any,
|
||||
callback,
|
||||
})
|
||||
}
|
||||
editor={({ selected }) => {
|
||||
const currentRole = currentRoles.find(
|
||||
(x) => x.id === selected,
|
||||
)!;
|
||||
|
||||
if (!currentRole) return null;
|
||||
|
||||
// Keep track of whatever role we're editing right now.
|
||||
const [value, setValue] = useState<Partial<RoleOrDefault>>({});
|
||||
|
||||
const currentRoleValue = { ...currentRole, ...value };
|
||||
|
||||
// Calculate permissions we have access to on this server.
|
||||
const current = server.permission;
|
||||
|
||||
// Upload new role information to server.
|
||||
function save() {
|
||||
const { permissions: permsCurrent, ...current } =
|
||||
currentRole;
|
||||
const { permissions: permsValue, ...value } =
|
||||
currentRoleValue;
|
||||
|
||||
if (!isEqual(permsCurrent, permsValue)) {
|
||||
server.setPermissions(
|
||||
selected,
|
||||
typeof permsValue === "number"
|
||||
? permsValue
|
||||
: {
|
||||
allow: permsValue.a,
|
||||
deny: permsValue.d,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (!isEqual(current, value)) {
|
||||
server.editRole(selected, value);
|
||||
}
|
||||
}
|
||||
/>
|
||||
{selected !== "default" && (
|
||||
<>
|
||||
<hr />
|
||||
<h1>Danger Zone</h1>
|
||||
<Button contrast error onClick={deleteRole}>
|
||||
Delete Role
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
// Delete the role from this server.
|
||||
function deleteRole() {
|
||||
server.deleteRole(selected);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SpaceBetween>
|
||||
<H1>Edit {currentRole.name}</H1>
|
||||
<Button
|
||||
palette="secondary"
|
||||
disabled={isEqual(
|
||||
currentRole,
|
||||
currentRoleValue,
|
||||
)}
|
||||
onClick={save}>
|
||||
Save
|
||||
</Button>
|
||||
</SpaceBetween>
|
||||
<hr />
|
||||
{selected !== "default" && (
|
||||
<>
|
||||
<section>
|
||||
<Overline type="subtle">Role Name</Overline>
|
||||
<p>
|
||||
<InputBox
|
||||
value={currentRoleValue.name}
|
||||
onChange={(e) =>
|
||||
setValue({
|
||||
...value,
|
||||
name: e.currentTarget.value,
|
||||
})
|
||||
}
|
||||
contrast
|
||||
/>
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<Overline type="subtle">
|
||||
Role Colour
|
||||
</Overline>
|
||||
<p>
|
||||
<ColourSwatches
|
||||
value={
|
||||
currentRoleValue.colour ??
|
||||
"gray"
|
||||
}
|
||||
onChange={(colour) =>
|
||||
setValue({ ...value, colour })
|
||||
}
|
||||
/>
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<Overline type="subtle">
|
||||
Role Options
|
||||
</Overline>
|
||||
<p>
|
||||
<Checkbox
|
||||
checked={
|
||||
currentRoleValue.hoist ?? false
|
||||
}
|
||||
onChange={(hoist) =>
|
||||
setValue({ ...value, hoist })
|
||||
}
|
||||
description="Display this role above others.">
|
||||
Hoist Role
|
||||
</Checkbox>
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<Overline type="subtle">
|
||||
Role Ranking
|
||||
</Overline>
|
||||
<p>
|
||||
<InputBox
|
||||
type="number"
|
||||
value={currentRoleValue.rank ?? 0}
|
||||
onChange={(e) =>
|
||||
setValue({
|
||||
...value,
|
||||
rank: parseInt(
|
||||
e.currentTarget.value,
|
||||
),
|
||||
})
|
||||
}
|
||||
contrast
|
||||
/>
|
||||
</p>
|
||||
</section>
|
||||
</>
|
||||
)}
|
||||
<h1>Edit Permissions</h1>
|
||||
<PermissionList
|
||||
value={currentRoleValue.permissions}
|
||||
onChange={(permissions) =>
|
||||
setValue({
|
||||
...value,
|
||||
permissions,
|
||||
} as RoleOrDefault)
|
||||
}
|
||||
/>
|
||||
{selected !== "default" && (
|
||||
<>
|
||||
<hr />
|
||||
<h1>Danger Zone</h1>
|
||||
<Button
|
||||
palette="error"
|
||||
compact
|
||||
onClick={deleteRole}>
|
||||
Delete Role
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user