mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-06 08:50:50 +08:00
@@ -18,6 +18,7 @@ import {
|
||||
} from '../../../components/ui/popover';
|
||||
import { useDebouncedValue } from '../../../hooks/use-debounced-value';
|
||||
import { useServerConfig } from '../../common';
|
||||
import type { WorkspaceFlagFilter } from '../schema';
|
||||
|
||||
interface DataTableToolbarProps<TData> {
|
||||
table?: Table<TData>;
|
||||
@@ -25,19 +26,21 @@ interface DataTableToolbarProps<TData> {
|
||||
onKeywordChange: (keyword: string) => void;
|
||||
selectedFeatures: FeatureType[];
|
||||
onFeaturesChange: (features: FeatureType[]) => void;
|
||||
flags: WorkspaceFlagFilter;
|
||||
onFlagsChange: (flags: WorkspaceFlagFilter) => void;
|
||||
sort: AdminWorkspaceSort | undefined;
|
||||
onSortChange: (sort: AdminWorkspaceSort | undefined) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const sortOptions: { value: AdminWorkspaceSort; label: string }[] = [
|
||||
{ value: AdminWorkspaceSort.SnapshotSize, label: 'Snapshot size' },
|
||||
{ value: AdminWorkspaceSort.CreatedAt, label: 'Created time' },
|
||||
{ value: AdminWorkspaceSort.BlobCount, label: 'Blob count' },
|
||||
{ value: AdminWorkspaceSort.BlobSize, label: 'Blob size' },
|
||||
{ value: AdminWorkspaceSort.SnapshotCount, label: 'Snapshot count' },
|
||||
{ value: AdminWorkspaceSort.SnapshotSize, label: 'Snapshot size' },
|
||||
{ value: AdminWorkspaceSort.MemberCount, label: 'Member count' },
|
||||
{ value: AdminWorkspaceSort.PublicPageCount, label: 'Public pages' },
|
||||
{ value: AdminWorkspaceSort.CreatedAt, label: 'Created time' },
|
||||
];
|
||||
|
||||
export function DataTableToolbar<TData>({
|
||||
@@ -45,6 +48,8 @@ export function DataTableToolbar<TData>({
|
||||
onKeywordChange,
|
||||
selectedFeatures,
|
||||
onFeaturesChange,
|
||||
flags,
|
||||
onFlagsChange,
|
||||
sort,
|
||||
onSortChange,
|
||||
disabled = false,
|
||||
@@ -80,6 +85,35 @@ export function DataTableToolbar<TData>({
|
||||
[sort]
|
||||
);
|
||||
|
||||
const flagOptions: { key: keyof WorkspaceFlagFilter; label: string }[] = [
|
||||
{ key: 'public', label: 'Public' },
|
||||
{ key: 'enableSharing', label: 'Enable sharing' },
|
||||
{ key: 'enableAi', label: 'Enable AI' },
|
||||
{ key: 'enableUrlPreview', label: 'Enable URL preview' },
|
||||
{ key: 'enableDocEmbedding', label: 'Enable doc embedding' },
|
||||
];
|
||||
|
||||
const flagLabel = (value: boolean | undefined) => {
|
||||
if (value === true) return 'On';
|
||||
if (value === false) return 'Off';
|
||||
return 'Any';
|
||||
};
|
||||
|
||||
const handleFlagToggle = useCallback(
|
||||
(key: keyof WorkspaceFlagFilter) => {
|
||||
const current = flags[key];
|
||||
const next =
|
||||
current === undefined ? true : current === true ? false : undefined;
|
||||
onFlagsChange({ ...flags, [key]: next });
|
||||
},
|
||||
[flags, onFlagsChange]
|
||||
);
|
||||
|
||||
const hasFlagFilter = useMemo(
|
||||
() => Object.values(flags).some(v => v !== undefined),
|
||||
[flags]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-y-2 gap-x-4 flex-wrap">
|
||||
<FeatureFilterPopover
|
||||
@@ -119,6 +153,37 @@ export function DataTableToolbar<TData>({
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<Popover open={disabled ? false : undefined}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant={hasFlagFilter ? 'secondary' : 'outline'}
|
||||
size="sm"
|
||||
className="h-8 px-2 lg:px-3"
|
||||
disabled={disabled}
|
||||
>
|
||||
Flags
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[260px] p-2">
|
||||
<div className="flex flex-col gap-1">
|
||||
{flagOptions.map(option => (
|
||||
<Button
|
||||
key={option.key}
|
||||
variant="ghost"
|
||||
className="justify-between"
|
||||
size="sm"
|
||||
disabled={disabled}
|
||||
onClick={() => handleFlagToggle(option.key)}
|
||||
>
|
||||
<span>{option.label}</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{flagLabel(flags[option.key])}
|
||||
</span>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<div className="flex">
|
||||
<Input
|
||||
placeholder="Search Workspace / Owner"
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { ColumnDef, PaginationState } from '@tanstack/react-table';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
import { SharedDataTable } from '../../../components/shared/data-table';
|
||||
import type { WorkspaceFlagFilter } from '../schema';
|
||||
import { DataTableToolbar } from './data-table-toolbar';
|
||||
|
||||
interface DataTableProps<TData, TValue> {
|
||||
@@ -14,6 +15,8 @@ interface DataTableProps<TData, TValue> {
|
||||
onKeywordChange: (value: string) => void;
|
||||
selectedFeatures: FeatureType[];
|
||||
onFeaturesChange: (features: FeatureType[]) => void;
|
||||
flags: WorkspaceFlagFilter;
|
||||
onFlagsChange: Dispatch<SetStateAction<WorkspaceFlagFilter>>;
|
||||
sort: AdminWorkspaceSort | undefined;
|
||||
onSortChange: (sort: AdminWorkspaceSort | undefined) => void;
|
||||
loading?: boolean;
|
||||
@@ -34,6 +37,8 @@ export function DataTable<TData extends { id: string }, TValue>({
|
||||
onKeywordChange,
|
||||
selectedFeatures,
|
||||
onFeaturesChange,
|
||||
flags,
|
||||
onFlagsChange,
|
||||
sort,
|
||||
onSortChange,
|
||||
onPaginationChange,
|
||||
@@ -46,7 +51,7 @@ export function DataTable<TData extends { id: string }, TValue>({
|
||||
totalCount={workspacesCount}
|
||||
pagination={pagination}
|
||||
onPaginationChange={onPaginationChange}
|
||||
resetFiltersDeps={[keyword, selectedFeatures, sort]}
|
||||
resetFiltersDeps={[keyword, selectedFeatures, sort, flags]}
|
||||
renderToolbar={table => (
|
||||
<DataTableToolbar
|
||||
table={table}
|
||||
@@ -54,6 +59,8 @@ export function DataTable<TData extends { id: string }, TValue>({
|
||||
onKeywordChange={onKeywordChange}
|
||||
selectedFeatures={selectedFeatures}
|
||||
onFeaturesChange={onFeaturesChange}
|
||||
flags={flags}
|
||||
onFlagsChange={onFlagsChange}
|
||||
sort={sort}
|
||||
onSortChange={onSortChange}
|
||||
disabled={loading}
|
||||
|
||||
@@ -86,6 +86,7 @@ function WorkspacePanelContent({
|
||||
flags: {
|
||||
public: workspace.public,
|
||||
enableAi: workspace.enableAi,
|
||||
enableSharing: workspace.enableSharing,
|
||||
enableUrlPreview: workspace.enableUrlPreview,
|
||||
enableDocEmbedding: workspace.enableDocEmbedding,
|
||||
name: workspace.name ?? '',
|
||||
@@ -110,6 +111,7 @@ function WorkspacePanelContent({
|
||||
return (
|
||||
flags.public !== baseline.flags.public ||
|
||||
flags.enableAi !== baseline.flags.enableAi ||
|
||||
flags.enableSharing !== baseline.flags.enableSharing ||
|
||||
flags.enableUrlPreview !== baseline.flags.enableUrlPreview ||
|
||||
flags.enableDocEmbedding !== baseline.flags.enableDocEmbedding ||
|
||||
flags.name !== baseline.flags.name ||
|
||||
@@ -134,6 +136,7 @@ function WorkspacePanelContent({
|
||||
id: workspace.id,
|
||||
public: flags.public,
|
||||
enableAi: flags.enableAi,
|
||||
enableSharing: flags.enableSharing,
|
||||
enableUrlPreview: flags.enableUrlPreview,
|
||||
enableDocEmbedding: flags.enableDocEmbedding,
|
||||
name: flags.name || null,
|
||||
@@ -231,6 +234,15 @@ function WorkspacePanelContent({
|
||||
}
|
||||
/>
|
||||
<Separator />
|
||||
<FlagItem
|
||||
label="Allow Workspace Sharing"
|
||||
description="Allow pages in this workspace to be shared publicly"
|
||||
checked={flags.enableSharing}
|
||||
onCheckedChange={value =>
|
||||
setFlags(prev => ({ ...prev, enableSharing: value }))
|
||||
}
|
||||
/>
|
||||
<Separator />
|
||||
<FlagItem
|
||||
label="Enable Doc Embedding"
|
||||
description="Allow document embedding for search"
|
||||
|
||||
Reference in New Issue
Block a user