feat(beta): public spaces (#2473)

This commit is contained in:
Philip Okugbe
2026-09-05 11:52:10 +01:00
committed by GitHub
parent f4796c982e
commit 876f3da1b2
117 changed files with 7592 additions and 715 deletions
@@ -4,6 +4,8 @@ import AddSpaceMembersModal from "@/features/space/components/add-space-members-
import React from "react";
import SpaceDetails from "@/features/space/components/space-details.tsx";
import SpaceSecuritySettings from "@/features/space/components/space-security-settings.tsx";
import PublishSpaceSettings from "@/features/public-space/components/publish-space-settings.tsx";
import { isPublicSpacesAllowed } from "@/features/public-space/utils/public-space-access.ts";
import { useSpaceQuery } from "@/features/space/queries/space-query.ts";
import { useSpaceAbility } from "@/features/space/permissions/use-space-ability.ts";
import {
@@ -11,6 +13,8 @@ import {
SpaceCaslSubject,
} from "@/features/space/permissions/permissions.type.ts";
import { useTranslation } from "react-i18next";
import { useAtom } from "jotai";
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
interface SpaceSettingsModalProps {
spaceId: string;
@@ -29,6 +33,13 @@ export default function SpaceSettingsModal({
const spaceRules = space?.membership?.permissions;
const spaceAbility = useSpaceAbility(spaceRules);
const [workspace] = useAtom(workspaceAtom);
const allowPublicSpaces = isPublicSpacesAllowed(workspace);
const canManageSettings = spaceAbility.can(
SpaceCaslAction.Manage,
SpaceCaslSubject.Settings,
);
return (
<>
<Modal.Root
@@ -60,10 +71,12 @@ export default function SpaceSettingsModal({
<Tabs.Tab fw={500} value="members">
{t("Members")}
</Tabs.Tab>
{spaceAbility.can(
SpaceCaslAction.Manage,
SpaceCaslSubject.Settings,
) && (
{canManageSettings && allowPublicSpaces && (
<Tabs.Tab fw={500} value="publish">
{t("Publish")}
</Tabs.Tab>
)}
{canManageSettings && (
<Tabs.Tab fw={500} value="security">
{t("Security")}
</Tabs.Tab>
@@ -114,6 +127,16 @@ export default function SpaceSettingsModal({
</div>
</ScrollArea>
</Tabs.Panel>
<Tabs.Panel value="publish">
<ScrollArea h={580} scrollbarSize={5} pr={8}>
<div style={{ paddingBottom: "100px" }}>
{canManageSettings && allowPublicSpaces && (
<PublishSpaceSettings space={space} />
)}
</div>
</ScrollArea>
</Tabs.Panel>
</Tabs>
</div>
</Modal.Body>
@@ -35,7 +35,7 @@ import clsx from "clsx";
import { useDisclosure } from "@mantine/hooks";
import SpaceSettingsModal from "@/features/space/components/settings-modal.tsx";
import { useGetSpaceBySlugQuery } from "@/features/space/queries/space-query.ts";
import { getSpaceUrl } from "@/lib/config.ts";
import { getSpaceUrl, isBetaPublicSpaces } from "@/lib/config.ts";
import SpaceTree from "@/features/page/tree/components/space-tree.tsx";
import { useSpaceAbility } from "@/features/space/permissions/use-space-ability.ts";
import {
@@ -106,6 +106,7 @@ export function SpaceSidebar() {
spaceName={space?.name}
spaceSlug={space?.slug}
spaceIcon={space?.logo}
isPublished={isBetaPublicSpaces() && space?.isPublished}
/>
</Group>
</div>
@@ -2,24 +2,32 @@ import classes from "./switch-space.module.css";
import { useNavigate } from "react-router-dom";
import { SpaceSelect } from "./space-select";
import { getSpaceUrl } from "@/lib/config";
import { Button, Popover, Text } from "@mantine/core";
import { IconChevronDown, IconChevronUp } from "@tabler/icons-react";
import { Button, Popover, Text, Tooltip } from "@mantine/core";
import {
IconChevronDown,
IconChevronUp,
IconWorld,
} from "@tabler/icons-react";
import { useDisclosure } from "@mantine/hooks";
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
import { AvatarIconType } from "@/features/attachments/types/attachment.types.ts";
import React from "react";
import { useTranslation } from "react-i18next";
interface SwitchSpaceProps {
spaceName: string;
spaceSlug: string;
spaceIcon?: string;
isPublished?: boolean;
}
export function SwitchSpace({
spaceName,
spaceSlug,
spaceIcon,
isPublished,
}: SwitchSpaceProps) {
const { t } = useTranslation();
const navigate = useNavigate();
const [opened, { close, toggle }] = useDisclosure(false);
@@ -61,6 +69,16 @@ export function SwitchSpace({
<Text className={classes.spaceName} size="md" fw={500} lineClamp={1}>
{spaceName}
</Text>
{isPublished && (
<Tooltip label={t("This space is public")}>
<IconWorld
size={14}
aria-label={t("This space is public")}
style={{ flexShrink: 0 }}
/>
</Tooltip>
)}
</Button>
</Popover.Target>
<Popover.Dropdown>
@@ -30,6 +30,7 @@ export interface ISpace {
createdAt: Date;
updatedAt: Date;
memberCount?: number;
isPublished?: boolean;
spaceId?: string;
membership?: IMembership;
settings?: ISpaceSettings;