feat(git-sync): per-space 'Enable Git sync' toggle (Phase C, §7.1)
UI opt-in for git-sync, mirroring the existing sharing/comments settings pattern (no new endpoint, no new mechanism; orchestrator read query untouched): - UpdateSpaceDto.gitSyncEnabled?: boolean. - SpaceRepo.updateGitSyncSettings: jsonb-merge into settings.gitSync.<key> (COALESCE || jsonb_build_object — never clobbers sibling sharing/comments); stored as a real jsonb boolean so the orchestrator's settings->'gitSync'->>'enabled' = 'true' matches. - SpaceService.updateSpace handles the flag (audit diff) via the existing CASL-guarded space update path (Manage/Settings). - client: Switch in edit-space-form (optimistic mutate + revert-on-error, readOnly-aware) + space types + 2 i18n keys. - space.service.spec extended (calls updateGitSyncSettings; no-op when undefined). tsc clean (server+client); jest src/core/space 4 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
import { Group, Box, Button, TextInput, Stack, Textarea } from "@mantine/core";
|
||||
import React from "react";
|
||||
import {
|
||||
Group,
|
||||
Box,
|
||||
Button,
|
||||
TextInput,
|
||||
Stack,
|
||||
Textarea,
|
||||
Divider,
|
||||
Switch,
|
||||
} from "@mantine/core";
|
||||
import React, { useState } from "react";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { zod4Resolver } from "mantine-form-zod-resolver";
|
||||
import { z } from "zod/v4";
|
||||
@@ -29,6 +38,23 @@ export function EditSpaceForm({ space, readOnly }: EditSpaceFormProps) {
|
||||
const { t } = useTranslation();
|
||||
const updateSpaceMutation = useUpdateSpaceMutation();
|
||||
|
||||
const [gitSyncEnabled, setGitSyncEnabled] = useState<boolean>(
|
||||
space?.settings?.gitSync?.enabled ?? false,
|
||||
);
|
||||
|
||||
const handleGitSyncToggle = async (value: boolean) => {
|
||||
const previous = gitSyncEnabled;
|
||||
setGitSyncEnabled(value); // optimistic update
|
||||
try {
|
||||
await updateSpaceMutation.mutateAsync({
|
||||
spaceId: space.id,
|
||||
gitSyncEnabled: value,
|
||||
});
|
||||
} catch (err) {
|
||||
setGitSyncEnabled(previous); // revert on failure
|
||||
}
|
||||
};
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
validate: zod4Resolver(formSchema),
|
||||
initialValues: {
|
||||
@@ -104,6 +130,18 @@ export function EditSpaceForm({ space, readOnly }: EditSpaceFormProps) {
|
||||
</Group>
|
||||
)}
|
||||
</form>
|
||||
|
||||
<Divider my="lg" />
|
||||
|
||||
<Switch
|
||||
label={t("Enable Git sync")}
|
||||
description={t("Sync this space's pages to a Git repository.")}
|
||||
checked={gitSyncEnabled}
|
||||
disabled={readOnly || updateSpaceMutation.isPending}
|
||||
onChange={(event) =>
|
||||
handleGitSyncToggle(event.currentTarget.checked)
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -13,9 +13,14 @@ export interface ISpaceCommentsSettings {
|
||||
allowViewerComments?: boolean;
|
||||
}
|
||||
|
||||
export interface ISpaceGitSyncSettings {
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ISpaceSettings {
|
||||
sharing?: ISpaceSharingSettings;
|
||||
comments?: ISpaceCommentsSettings;
|
||||
gitSync?: ISpaceGitSyncSettings;
|
||||
}
|
||||
|
||||
export interface ISpace {
|
||||
@@ -35,6 +40,7 @@ export interface ISpace {
|
||||
// for updates
|
||||
disablePublicSharing?: boolean;
|
||||
allowViewerComments?: boolean;
|
||||
gitSyncEnabled?: boolean;
|
||||
}
|
||||
|
||||
interface IMembership {
|
||||
|
||||
Reference in New Issue
Block a user