snapshot of https://github.com/makeplane/plane.git @ d868349a55de79979eb8b98701bf1702c67ad634 (2026-09-15)
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
This commit is contained in:
177
apps/admin/app/(all)/(dashboard)/workspace/page.tsx
Normal file
177
apps/admin/app/(all)/(dashboard)/workspace/page.tsx
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Link from "next/link";
|
||||
import useSWR from "swr";
|
||||
import { LoadingOutline as LoaderIcon } from "@makeplane/propel/icons";
|
||||
// types
|
||||
import { AnchorButton } from "@makeplane/propel/components/anchor-button";
|
||||
import { Button } from "@makeplane/propel/components/button";
|
||||
import { Switch } from "@makeplane/propel/components/switch";
|
||||
import type { TInstanceConfigurationKeys } from "@plane/types";
|
||||
import { cn } from "@plane/utils";
|
||||
// components
|
||||
import { PageWrapper } from "@/components/common/page-wrapper";
|
||||
import { Skeleton } from "@/components/common/skeleton";
|
||||
import { WorkspaceListItem } from "@/components/workspace/list-item";
|
||||
import { setPromiseToast } from "@/providers/toast";
|
||||
// hooks
|
||||
import { useInstance, useWorkspace } from "@/hooks/store";
|
||||
// types
|
||||
import type { Route } from "./+types/page";
|
||||
|
||||
const WorkspaceManagementPage = observer(function WorkspaceManagementPage(_props: Route.ComponentProps) {
|
||||
// states
|
||||
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
||||
// store
|
||||
const { formattedConfig, fetchInstanceConfigurations, updateInstanceConfigurations } = useInstance();
|
||||
const {
|
||||
workspaceIds,
|
||||
loader: workspaceLoader,
|
||||
paginationInfo,
|
||||
fetchWorkspaces,
|
||||
fetchNextWorkspaces,
|
||||
} = useWorkspace();
|
||||
// derived values
|
||||
const disableWorkspaceCreation = formattedConfig?.DISABLE_WORKSPACE_CREATION ?? "";
|
||||
const hasNextPage = paginationInfo?.next_page_results && paginationInfo?.next_cursor !== undefined;
|
||||
|
||||
// fetch data
|
||||
useSWR("INSTANCE_CONFIGURATIONS", () => fetchInstanceConfigurations());
|
||||
useSWR("INSTANCE_WORKSPACES", () => fetchWorkspaces());
|
||||
|
||||
const updateConfig = async (key: TInstanceConfigurationKeys, value: string) => {
|
||||
setIsSubmitting(true);
|
||||
|
||||
const payload = {
|
||||
[key]: value,
|
||||
};
|
||||
|
||||
const updateConfigPromise = updateInstanceConfigurations(payload);
|
||||
|
||||
setPromiseToast(updateConfigPromise, {
|
||||
loading: "Saving configuration",
|
||||
success: {
|
||||
title: "Success",
|
||||
message: () => "Configuration saved successfully",
|
||||
},
|
||||
error: {
|
||||
title: "Error",
|
||||
message: () => "Failed to save configuration",
|
||||
},
|
||||
});
|
||||
|
||||
await updateConfigPromise
|
||||
.then(() => {
|
||||
setIsSubmitting(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
setIsSubmitting(false);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<PageWrapper
|
||||
header={{
|
||||
title: "Workspaces on this instance",
|
||||
description: "See all workspaces and control who can create them.",
|
||||
}}
|
||||
>
|
||||
<div className="space-y-3">
|
||||
{formattedConfig ? (
|
||||
<div className={cn("flex w-full items-center gap-14 rounded-sm")}>
|
||||
<div className="flex grow items-center gap-4">
|
||||
<div className="grow">
|
||||
<div className="pb-1 text-16 font-medium">Prevent anyone else from creating a workspace.</div>
|
||||
<div className={cn("text-11 leading-5 font-regular text-tertiary")}>
|
||||
Toggling this on will let only you create workspaces. You will have to invite users to new workspaces.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`shrink-0 pr-4 ${isSubmitting && "opacity-70"}`}>
|
||||
<div className="flex items-center gap-4">
|
||||
<Switch
|
||||
checked={Boolean(parseInt(disableWorkspaceCreation))}
|
||||
onCheckedChange={() => {
|
||||
if (Boolean(parseInt(disableWorkspaceCreation)) === true) {
|
||||
updateConfig("DISABLE_WORKSPACE_CREATION", "0");
|
||||
} else {
|
||||
updateConfig("DISABLE_WORKSPACE_CREATION", "1");
|
||||
}
|
||||
}}
|
||||
size="sm"
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<Skeleton>
|
||||
<Skeleton.Item height="50px" width="100%" />
|
||||
</Skeleton>
|
||||
)}
|
||||
{workspaceLoader !== "init-loader" ? (
|
||||
<>
|
||||
<div className="flex items-center justify-between gap-2 pt-6">
|
||||
<div className="flex flex-col items-start gap-x-2">
|
||||
<div className="flex items-center gap-2 text-16 font-medium">
|
||||
All workspaces on this instance <span className="text-tertiary">• {workspaceIds.length}</span>
|
||||
{workspaceLoader && ["mutation", "pagination"].includes(workspaceLoader) && (
|
||||
<LoaderIcon className="h-4 w-4 animate-spin" />
|
||||
)}
|
||||
</div>
|
||||
<div className={cn("text-11 leading-5 font-regular text-tertiary")}>
|
||||
You can't yet delete workspaces and you can only go to the workspace if you are an Admin or a
|
||||
Member.
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
stretch="auto"
|
||||
nativeButton={false}
|
||||
render={<Link href="/workspace/create" />}
|
||||
label="Create workspace"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 py-2">
|
||||
{workspaceIds.map((workspaceId) => (
|
||||
<WorkspaceListItem key={workspaceId} workspaceId={workspaceId} />
|
||||
))}
|
||||
</div>
|
||||
{hasNextPage && (
|
||||
<div className="flex justify-center">
|
||||
<AnchorButton
|
||||
variant="primary"
|
||||
size="md"
|
||||
onClick={() => fetchNextWorkspaces()}
|
||||
loading={workspaceLoader === "pagination"}
|
||||
label="Load more"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<Skeleton className="space-y-10 py-8">
|
||||
<Skeleton.Item height="24px" width="20%" />
|
||||
<Skeleton.Item height="92px" width="100%" />
|
||||
<Skeleton.Item height="92px" width="100%" />
|
||||
<Skeleton.Item height="92px" width="100%" />
|
||||
</Skeleton>
|
||||
)}
|
||||
</div>
|
||||
</PageWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
export const meta: Route.MetaFunction = () => [{ title: "Workspace Management - God Mode" }];
|
||||
|
||||
export default WorkspaceManagementPage;
|
||||
Reference in New Issue
Block a user