mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 23:44:22 +00:00
Migrate workspace settings to ts
This commit is contained in:
@@ -1,7 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Accordion, Title } from '@mantine/core';
|
import { Accordion, Title } from '@mantine/core';
|
||||||
|
|
||||||
const AccordionControl = ({ children }) => (
|
interface AccordionControlProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AccordionControl: React.FC<AccordionControlProps> = ({ children }) => (
|
||||||
<Accordion.Control>
|
<Accordion.Control>
|
||||||
<Title order={4}>{children}</Title>
|
<Title order={4}>{children}</Title>
|
||||||
</Accordion.Control>
|
</Accordion.Control>
|
||||||
@@ -1,12 +1,21 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text, Switch, Group, Box, Title } from '@mantine/core';
|
import { Text, Switch, Group, Box } from '@mantine/core';
|
||||||
import { useWorkspace } from '../../../contexts/WorkspaceContext';
|
import { useWorkspace } from '../../../contexts/WorkspaceContext';
|
||||||
|
import { Theme } from '@/types/theme';
|
||||||
|
|
||||||
const AppearanceSettings = ({ themeSettings, onThemeChange }) => {
|
interface AppearanceSettingsProps {
|
||||||
|
themeSettings?: Theme;
|
||||||
|
onThemeChange: (newTheme: Theme) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AppearanceSettings: React.FC<AppearanceSettingsProps> = ({
|
||||||
|
themeSettings,
|
||||||
|
onThemeChange,
|
||||||
|
}) => {
|
||||||
const { colorScheme, updateColorScheme } = useWorkspace();
|
const { colorScheme, updateColorScheme } = useWorkspace();
|
||||||
|
|
||||||
const handleThemeChange = () => {
|
const handleThemeChange = (): void => {
|
||||||
const newTheme = colorScheme === 'dark' ? 'light' : 'dark';
|
const newTheme = colorScheme === 'dark' ? Theme.Light : Theme.Dark;
|
||||||
updateColorScheme(newTheme);
|
updateColorScheme(newTheme);
|
||||||
onThemeChange(newTheme);
|
onThemeChange(newTheme);
|
||||||
};
|
};
|
||||||
@@ -4,13 +4,13 @@ import DeleteWorkspaceModal from '../../modals/workspace/DeleteWorkspaceModal';
|
|||||||
import { useWorkspace } from '../../../contexts/WorkspaceContext';
|
import { useWorkspace } from '../../../contexts/WorkspaceContext';
|
||||||
import { useModalContext } from '../../../contexts/ModalContext';
|
import { useModalContext } from '../../../contexts/ModalContext';
|
||||||
|
|
||||||
const DangerZoneSettings = () => {
|
const DangerZoneSettings: React.FC = () => {
|
||||||
const { currentWorkspace, workspaces, deleteCurrentWorkspace } =
|
const { currentWorkspace, workspaces, deleteCurrentWorkspace } =
|
||||||
useWorkspace();
|
useWorkspace();
|
||||||
const { setSettingsModalVisible } = useModalContext();
|
const { setSettingsModalVisible } = useModalContext();
|
||||||
const [deleteModalOpened, setDeleteModalOpened] = useState(false);
|
const [deleteModalOpened, setDeleteModalOpened] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleDelete = async () => {
|
const handleDelete = async (): Promise<void> => {
|
||||||
await deleteCurrentWorkspace();
|
await deleteCurrentWorkspace();
|
||||||
setDeleteModalOpened(false);
|
setDeleteModalOpened(false);
|
||||||
setSettingsModalVisible(false);
|
setSettingsModalVisible(false);
|
||||||
@@ -1,7 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text, Switch, Tooltip, Group, Box } from '@mantine/core';
|
import { Text, Switch, Tooltip, Group, Box } from '@mantine/core';
|
||||||
|
|
||||||
const EditorSettings = ({
|
interface EditorSettingsProps {
|
||||||
|
autoSave: boolean;
|
||||||
|
showHiddenFiles: boolean;
|
||||||
|
onAutoSaveChange: (value: boolean) => void;
|
||||||
|
onShowHiddenFilesChange: (value: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EditorSettings: React.FC<EditorSettingsProps> = ({
|
||||||
autoSave,
|
autoSave,
|
||||||
showHiddenFiles,
|
showHiddenFiles,
|
||||||
onAutoSaveChange,
|
onAutoSaveChange,
|
||||||
@@ -1,7 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Title, Box, TextInput, Text, Grid } from '@mantine/core';
|
import { Box, TextInput, Text, Grid } from '@mantine/core';
|
||||||
|
import { Workspace } from '@/types/workspace';
|
||||||
|
|
||||||
const GeneralSettings = ({ name, onInputChange }) => {
|
interface GeneralSettingsProps {
|
||||||
|
name: string;
|
||||||
|
onInputChange: (key: keyof Workspace, value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GeneralSettings: React.FC<GeneralSettingsProps> = ({
|
||||||
|
name,
|
||||||
|
onInputChange,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Box mb="md">
|
<Box mb="md">
|
||||||
<Grid gutter="md" align="center">
|
<Grid gutter="md" align="center">
|
||||||
@@ -10,7 +19,7 @@ const GeneralSettings = ({ name, onInputChange }) => {
|
|||||||
</Grid.Col>
|
</Grid.Col>
|
||||||
<Grid.Col span={6}>
|
<Grid.Col span={6}>
|
||||||
<TextInput
|
<TextInput
|
||||||
value={name || ''}
|
value={name}
|
||||||
onChange={(event) =>
|
onChange={(event) =>
|
||||||
onInputChange('name', event.currentTarget.value)
|
onInputChange('name', event.currentTarget.value)
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,21 @@ import {
|
|||||||
Group,
|
Group,
|
||||||
Grid,
|
Grid,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
|
import { Workspace } from '@/types/workspace';
|
||||||
|
|
||||||
const GitSettings = ({
|
interface GitSettingsProps {
|
||||||
|
gitEnabled: boolean;
|
||||||
|
gitUrl: string;
|
||||||
|
gitUser: string;
|
||||||
|
gitToken: string;
|
||||||
|
gitAutoCommit: boolean;
|
||||||
|
gitCommitMsgTemplate: string;
|
||||||
|
gitCommitName: string;
|
||||||
|
gitCommitEmail: string;
|
||||||
|
onInputChange: (key: keyof Workspace, value: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GitSettings: React.FC<GitSettingsProps> = ({
|
||||||
gitEnabled,
|
gitEnabled,
|
||||||
gitUrl,
|
gitUrl,
|
||||||
gitUser,
|
gitUser,
|
||||||
@@ -21,7 +34,7 @@ const GitSettings = ({
|
|||||||
onInputChange,
|
onInputChange,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Stack spacing="md">
|
<Stack gap="md">
|
||||||
<Grid gutter="md" align="center">
|
<Grid gutter="md" align="center">
|
||||||
<Grid.Col span={6}>
|
<Grid.Col span={6}>
|
||||||
<Text size="sm">Enable Git Repository</Text>
|
<Text size="sm">Enable Git Repository</Text>
|
||||||
@@ -17,23 +17,35 @@ import GeneralSettings from './GeneralSettings';
|
|||||||
import { useModalContext } from '../../../contexts/ModalContext';
|
import { useModalContext } from '../../../contexts/ModalContext';
|
||||||
import DangerZoneSettings from './DangerZoneSettings';
|
import DangerZoneSettings from './DangerZoneSettings';
|
||||||
import AccordionControl from '../AccordionControl';
|
import AccordionControl from '../AccordionControl';
|
||||||
|
import { SettingsActionType, SettingsAction } from '../../../types/settings';
|
||||||
|
import { Workspace } from '../../../types/workspace';
|
||||||
|
|
||||||
const initialState = {
|
// State and reducer for workspace settings
|
||||||
|
interface WorkspaceSettingsState {
|
||||||
|
localSettings: Partial<Workspace>;
|
||||||
|
initialSettings: Partial<Workspace>;
|
||||||
|
hasUnsavedChanges: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: WorkspaceSettingsState = {
|
||||||
localSettings: {},
|
localSettings: {},
|
||||||
initialSettings: {},
|
initialSettings: {},
|
||||||
hasUnsavedChanges: false,
|
hasUnsavedChanges: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
function settingsReducer(state, action) {
|
function settingsReducer(
|
||||||
|
state: WorkspaceSettingsState,
|
||||||
|
action: SettingsAction<Partial<Workspace>>
|
||||||
|
): WorkspaceSettingsState {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'INIT_SETTINGS':
|
case SettingsActionType.INIT_SETTINGS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
localSettings: action.payload,
|
localSettings: action.payload || {},
|
||||||
initialSettings: action.payload,
|
initialSettings: action.payload || {},
|
||||||
hasUnsavedChanges: false,
|
hasUnsavedChanges: false,
|
||||||
};
|
};
|
||||||
case 'UPDATE_LOCAL_SETTINGS':
|
case SettingsActionType.UPDATE_LOCAL_SETTINGS:
|
||||||
const newLocalSettings = { ...state.localSettings, ...action.payload };
|
const newLocalSettings = { ...state.localSettings, ...action.payload };
|
||||||
const hasChanges =
|
const hasChanges =
|
||||||
JSON.stringify(newLocalSettings) !==
|
JSON.stringify(newLocalSettings) !==
|
||||||
@@ -43,7 +55,7 @@ function settingsReducer(state, action) {
|
|||||||
localSettings: newLocalSettings,
|
localSettings: newLocalSettings,
|
||||||
hasUnsavedChanges: hasChanges,
|
hasUnsavedChanges: hasChanges,
|
||||||
};
|
};
|
||||||
case 'MARK_SAVED':
|
case SettingsActionType.MARK_SAVED:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
initialSettings: state.localSettings,
|
initialSettings: state.localSettings,
|
||||||
@@ -54,16 +66,16 @@ function settingsReducer(state, action) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const WorkspaceSettings = () => {
|
const WorkspaceSettings: React.FC = () => {
|
||||||
const { currentWorkspace, updateSettings } = useWorkspace();
|
const { currentWorkspace, updateSettings } = useWorkspace();
|
||||||
const { settingsModalVisible, setSettingsModalVisible } = useModalContext();
|
const { settingsModalVisible, setSettingsModalVisible } = useModalContext();
|
||||||
const [state, dispatch] = useReducer(settingsReducer, initialState);
|
const [state, dispatch] = useReducer(settingsReducer, initialState);
|
||||||
const isInitialMount = useRef(true);
|
const isInitialMount = useRef<boolean>(true);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInitialMount.current) {
|
if (isInitialMount.current && currentWorkspace) {
|
||||||
isInitialMount.current = false;
|
isInitialMount.current = false;
|
||||||
const settings = {
|
const settings: Partial<Workspace> = {
|
||||||
name: currentWorkspace.name,
|
name: currentWorkspace.name,
|
||||||
theme: currentWorkspace.theme,
|
theme: currentWorkspace.theme,
|
||||||
autoSave: currentWorkspace.autoSave,
|
autoSave: currentWorkspace.autoSave,
|
||||||
@@ -77,15 +89,21 @@ const WorkspaceSettings = () => {
|
|||||||
gitCommitName: currentWorkspace.gitCommitName,
|
gitCommitName: currentWorkspace.gitCommitName,
|
||||||
gitCommitEmail: currentWorkspace.gitCommitEmail,
|
gitCommitEmail: currentWorkspace.gitCommitEmail,
|
||||||
};
|
};
|
||||||
dispatch({ type: 'INIT_SETTINGS', payload: settings });
|
dispatch({ type: SettingsActionType.INIT_SETTINGS, payload: settings });
|
||||||
}
|
}
|
||||||
}, [currentWorkspace]);
|
}, [currentWorkspace]);
|
||||||
|
|
||||||
const handleInputChange = useCallback((key, value) => {
|
const handleInputChange = useCallback(
|
||||||
dispatch({ type: 'UPDATE_LOCAL_SETTINGS', payload: { [key]: value } });
|
(key: keyof Workspace, value: any): void => {
|
||||||
}, []);
|
dispatch({
|
||||||
|
type: SettingsActionType.UPDATE_LOCAL_SETTINGS,
|
||||||
|
payload: { [key]: value } as Partial<Workspace>,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
if (!state.localSettings.name?.trim()) {
|
if (!state.localSettings.name?.trim()) {
|
||||||
notifications.show({
|
notifications.show({
|
||||||
@@ -96,7 +114,7 @@ const WorkspaceSettings = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await updateSettings(state.localSettings);
|
await updateSettings(state.localSettings);
|
||||||
dispatch({ type: 'MARK_SAVED' });
|
dispatch({ type: SettingsActionType.MARK_SAVED });
|
||||||
notifications.show({
|
notifications.show({
|
||||||
message: 'Settings saved successfully',
|
message: 'Settings saved successfully',
|
||||||
color: 'green',
|
color: 'green',
|
||||||
@@ -105,7 +123,9 @@ const WorkspaceSettings = () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to save settings:', error);
|
console.error('Failed to save settings:', error);
|
||||||
notifications.show({
|
notifications.show({
|
||||||
message: 'Failed to save settings: ' + error.message,
|
message:
|
||||||
|
'Failed to save settings: ' +
|
||||||
|
(error instanceof Error ? error.message : String(error)),
|
||||||
color: 'red',
|
color: 'red',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -123,7 +143,7 @@ const WorkspaceSettings = () => {
|
|||||||
centered
|
centered
|
||||||
size="lg"
|
size="lg"
|
||||||
>
|
>
|
||||||
<Stack spacing="xl">
|
<Stack gap="xl">
|
||||||
{state.hasUnsavedChanges && (
|
{state.hasUnsavedChanges && (
|
||||||
<Badge color="yellow" variant="light">
|
<Badge color="yellow" variant="light">
|
||||||
Unsaved Changes
|
Unsaved Changes
|
||||||
@@ -133,7 +153,7 @@ const WorkspaceSettings = () => {
|
|||||||
<Accordion
|
<Accordion
|
||||||
defaultValue={['general', 'appearance', 'editor', 'git', 'danger']}
|
defaultValue={['general', 'appearance', 'editor', 'git', 'danger']}
|
||||||
multiple
|
multiple
|
||||||
styles={(theme) => ({
|
styles={(theme: any) => ({
|
||||||
control: {
|
control: {
|
||||||
paddingTop: theme.spacing.md,
|
paddingTop: theme.spacing.md,
|
||||||
paddingBottom: theme.spacing.md,
|
paddingBottom: theme.spacing.md,
|
||||||
@@ -162,7 +182,7 @@ const WorkspaceSettings = () => {
|
|||||||
<AccordionControl>General</AccordionControl>
|
<AccordionControl>General</AccordionControl>
|
||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
<GeneralSettings
|
<GeneralSettings
|
||||||
name={state.localSettings.name}
|
name={state.localSettings.name || ''}
|
||||||
onInputChange={handleInputChange}
|
onInputChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</Accordion.Panel>
|
</Accordion.Panel>
|
||||||
@@ -173,7 +193,7 @@ const WorkspaceSettings = () => {
|
|||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
<AppearanceSettings
|
<AppearanceSettings
|
||||||
themeSettings={state.localSettings.theme}
|
themeSettings={state.localSettings.theme}
|
||||||
onThemeChange={(newTheme) =>
|
onThemeChange={(newTheme: string) =>
|
||||||
handleInputChange('theme', newTheme)
|
handleInputChange('theme', newTheme)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -184,12 +204,12 @@ const WorkspaceSettings = () => {
|
|||||||
<AccordionControl>Editor</AccordionControl>
|
<AccordionControl>Editor</AccordionControl>
|
||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
<EditorSettings
|
<EditorSettings
|
||||||
autoSave={state.localSettings.autoSave}
|
autoSave={state.localSettings.autoSave || false}
|
||||||
onAutoSaveChange={(value) =>
|
onAutoSaveChange={(value: boolean) =>
|
||||||
handleInputChange('autoSave', value)
|
handleInputChange('autoSave', value)
|
||||||
}
|
}
|
||||||
showHiddenFiles={state.localSettings.showHiddenFiles}
|
showHiddenFiles={state.localSettings.showHiddenFiles || false}
|
||||||
onShowHiddenFilesChange={(value) =>
|
onShowHiddenFilesChange={(value: boolean) =>
|
||||||
handleInputChange('showHiddenFiles', value)
|
handleInputChange('showHiddenFiles', value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@@ -200,14 +220,16 @@ const WorkspaceSettings = () => {
|
|||||||
<AccordionControl>Git Integration</AccordionControl>
|
<AccordionControl>Git Integration</AccordionControl>
|
||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
<GitSettings
|
<GitSettings
|
||||||
gitEnabled={state.localSettings.gitEnabled}
|
gitEnabled={state.localSettings.gitEnabled || false}
|
||||||
gitUrl={state.localSettings.gitUrl}
|
gitUrl={state.localSettings.gitUrl || ''}
|
||||||
gitUser={state.localSettings.gitUser}
|
gitUser={state.localSettings.gitUser || ''}
|
||||||
gitToken={state.localSettings.gitToken}
|
gitToken={state.localSettings.gitToken || ''}
|
||||||
gitAutoCommit={state.localSettings.gitAutoCommit}
|
gitAutoCommit={state.localSettings.gitAutoCommit || false}
|
||||||
gitCommitMsgTemplate={state.localSettings.gitCommitMsgTemplate}
|
gitCommitMsgTemplate={
|
||||||
gitCommitName={state.localSettings.gitCommitName}
|
state.localSettings.gitCommitMsgTemplate || ''
|
||||||
gitCommitEmail={state.localSettings.gitCommitEmail}
|
}
|
||||||
|
gitCommitName={state.localSettings.gitCommitName || ''}
|
||||||
|
gitCommitEmail={state.localSettings.gitCommitEmail || ''}
|
||||||
onInputChange={handleInputChange}
|
onInputChange={handleInputChange}
|
||||||
/>
|
/>
|
||||||
</Accordion.Panel>
|
</Accordion.Panel>
|
||||||
@@ -3,23 +3,29 @@ import { Theme } from './theme';
|
|||||||
export interface WorkspaceSettings {
|
export interface WorkspaceSettings {
|
||||||
theme: Theme;
|
theme: Theme;
|
||||||
autoSave: boolean;
|
autoSave: boolean;
|
||||||
|
showHiddenFiles: boolean;
|
||||||
gitEnabled: boolean;
|
gitEnabled: boolean;
|
||||||
gitUrl: string;
|
gitUrl: string;
|
||||||
gitUser: string;
|
gitUser: string;
|
||||||
gitToken: string;
|
gitToken: string;
|
||||||
gitAutoCommit: boolean;
|
gitAutoCommit: boolean;
|
||||||
gitCommitMsgTemplate: string;
|
gitCommitMsgTemplate: string;
|
||||||
|
gitCommitName: string;
|
||||||
|
gitCommitEmail: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_WORKSPACE_SETTINGS: WorkspaceSettings = {
|
export const DEFAULT_WORKSPACE_SETTINGS: WorkspaceSettings = {
|
||||||
theme: Theme.Light,
|
theme: Theme.Light,
|
||||||
autoSave: false,
|
autoSave: false,
|
||||||
|
showHiddenFiles: false,
|
||||||
gitEnabled: false,
|
gitEnabled: false,
|
||||||
gitUrl: '',
|
gitUrl: '',
|
||||||
gitUser: '',
|
gitUser: '',
|
||||||
gitToken: '',
|
gitToken: '',
|
||||||
gitAutoCommit: false,
|
gitAutoCommit: false,
|
||||||
gitCommitMsgTemplate: '${action} ${filename}',
|
gitCommitMsgTemplate: '${action} ${filename}',
|
||||||
|
gitCommitName: '',
|
||||||
|
gitCommitEmail: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Workspace extends WorkspaceSettings {
|
export interface Workspace extends WorkspaceSettings {
|
||||||
|
|||||||
Reference in New Issue
Block a user