diff --git a/src/main/environment/service/environment-service.ts b/src/main/environment/service/environment-service.ts index f58a51da..42337a2e 100644 --- a/src/main/environment/service/environment-service.ts +++ b/src/main/environment/service/environment-service.ts @@ -51,6 +51,15 @@ export class EnvironmentService implements Initializable { } } + /** + * Sets and saves all variables in the current collection. + * @param variables + */ + public setAndSaveAllVariables(variables: VariableObject[]) { + this.currentCollection.variables = {}; + variables.forEach((variable) => (this.currentCollection.variables[variable.key] = variable)); + } + /** * Enables or disables a variable in the current collection. * @@ -96,4 +105,8 @@ export class EnvironmentService implements Initializable { private getVariableValue(key: string) { return this.getVariable(key)?.value; } + + public setVariable(variable: VariableObject) { + return (this.currentCollection.variables[variable.key] = variable); + } } diff --git a/src/main/event/main-event-service.ts b/src/main/event/main-event-service.ts index 5e21b0af..aa80ff3f 100644 --- a/src/main/event/main-event-service.ts +++ b/src/main/event/main-event-service.ts @@ -6,6 +6,7 @@ import { PersistenceService } from '../persistence/service/persistence-service'; import { TrufosObject } from 'shim/objects'; import { EnvironmentService } from 'main/environment/service/environment-service'; import './stream-events'; +import { VariableObject } from '../../shim/variables'; const persistenceService = PersistenceService.instance; const environmentService = EnvironmentService.instance; @@ -100,4 +101,9 @@ export class MainEventService implements IEventService { async getVariable(key: string) { return environmentService.getVariable(key); } + + async setAndSaveAllVariables(variables: VariableObject[]) { + environmentService.setAndSaveAllVariables(variables); + await persistenceService.saveCollection(environmentService.currentCollection); + } } diff --git a/src/renderer/components/shared/settings/SettingsModal.tsx b/src/renderer/components/shared/settings/SettingsModal.tsx index db17924a..5f1a4a6b 100644 --- a/src/renderer/components/shared/settings/SettingsModal.tsx +++ b/src/renderer/components/shared/settings/SettingsModal.tsx @@ -1,26 +1,53 @@ import { Dialog, DialogContent, - DialogDescription, + DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; import { FiSettings } from 'react-icons/fi'; +import { VariableTab } from '@/components/shared/settings/VariableTab/VariableTab'; +import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'; +import { useSettingsStore } from '@/state/settingsStore'; +import { Button } from '@/components/ui/button'; +import * as React from 'react'; export const SettingsModal = () => { + const { save, cancel, openModal } = useSettingsStore.getState(); + const isOpen = useSettingsStore((state) => state.isOpen); + const allDoubleKeys = useSettingsStore((state) => state.allDoubleKeys); + return ( - - + + - - - Lorem ipsusm? - - Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur - + + + Settings + + + Variables + + + + + + + + + ); diff --git a/src/renderer/components/shared/settings/VariableTab/VariableTab.tsx b/src/renderer/components/shared/settings/VariableTab/VariableTab.tsx new file mode 100644 index 00000000..0a9e65f4 --- /dev/null +++ b/src/renderer/components/shared/settings/VariableTab/VariableTab.tsx @@ -0,0 +1,116 @@ +import { Divider } from '@/components/shared/Divider'; +import { Button } from '@/components/ui/button'; +import { AddIcon, CheckedIcon, DeleteIcon } from '@/components/icons'; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from '@/components/ui/table'; +import { cn } from '@/lib/utils'; +import { useSettingsStore } from '@/state/settingsStore'; + +export const VariableTab = () => { + const { addNewVariable, deleteVariable, update, checkDuplicate } = useSettingsStore(); + const allVariables = useSettingsStore((state) => state.variables); + const allDoubleKeys = useSettingsStore((state) => state.allDoubleKeys); + + return ( +
+
+
+ +
+ +
+ +
+ + + + Key + Value + Description + {/* Action Column */} + + + + {allVariables.map((variable, index) => ( + + + { + update(index, e.target.value, 'key'); + checkDuplicate(e.target.value); + }} + /> + + + update(index, e.target.value, 'value')} + /> + + + update(index, e.target.value, 'description')} + /> + + +
+
+ update(index, e.target.checked, 'isActive')} + className={cn( + 'form-checkbox h-4 w-4 appearance-none border rounded-[2px]', + variable.isActive + ? 'border-[rgba(107,194,224,1)] bg-[rgba(25,54,65,1)]' + : 'border-[rgba(238,238,238,1)] bg-transparent' + )} + /> + {variable.isActive && ( +
+ +
+ )} +
+ +
+
+
+ ))} +
+
+
+
+ ); +}; diff --git a/src/renderer/components/sidebar/FooterBar.tsx b/src/renderer/components/sidebar/FooterBar.tsx index e178ab35..6ff5057c 100644 --- a/src/renderer/components/sidebar/FooterBar.tsx +++ b/src/renderer/components/sidebar/FooterBar.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'; import { RendererEventService } from '@/services/event/renderer-event-service'; import { GithubIcon } from '@/components/icons'; +import { SettingsModal } from '@/components/shared/settings/SettingsModal'; export function FooterBar() { const [appVersion, setAppVersion] = useState(undefined); @@ -25,7 +26,7 @@ export function FooterBar() { > {/* Adjust the size as needed */} - {/**/} + ); } diff --git a/src/renderer/components/ui/button.tsx b/src/renderer/components/ui/button.tsx index 2023ef08..23678952 100644 --- a/src/renderer/components/ui/button.tsx +++ b/src/renderer/components/ui/button.tsx @@ -10,6 +10,7 @@ const buttonVariants = cva( variants: { variant: { default: 'bg-accent-primary text-accent-tertiary hover:bg-accent-primary/90', + defaultDisable: 'border border-primary text-accent-tertiary hover:bg-accent-primary/90', destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', outline: 'border border-primary bg-background hover:bg-accent hover:text-accent-foreground', secondary: diff --git a/src/renderer/components/ui/dialog.tsx b/src/renderer/components/ui/dialog.tsx index 6f1ab0e7..56fc3e64 100644 --- a/src/renderer/components/ui/dialog.tsx +++ b/src/renderer/components/ui/dialog.tsx @@ -32,21 +32,22 @@ const DialogContent = React.forwardRef< React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - - {children} - - - Close - - + + + {children} + + + Close + + + )); DialogContent.displayName = DialogPrimitive.Content.displayName; diff --git a/src/renderer/components/ui/tabs.tsx b/src/renderer/components/ui/tabs.tsx index fd67be27..1a4202ff 100644 --- a/src/renderer/components/ui/tabs.tsx +++ b/src/renderer/components/ui/tabs.tsx @@ -9,7 +9,7 @@ const Tabs = React.forwardRef< >(({ className, ...props }, ref) => ( )); diff --git a/src/renderer/services/event/renderer-event-service.ts b/src/renderer/services/event/renderer-event-service.ts index d2bece78..57d5a814 100644 --- a/src/renderer/services/event/renderer-event-service.ts +++ b/src/renderer/services/event/renderer-event-service.ts @@ -11,6 +11,7 @@ const METHOD_NAMES = new Set([ 'deleteObject', 'getActiveEnvironmentVariables', 'getVariable', + 'setAndSaveAllVariables', ]); const INSTANCE = {} as IEventService; diff --git a/src/renderer/state/settingsStore.ts b/src/renderer/state/settingsStore.ts new file mode 100644 index 00000000..7ba1fc6a --- /dev/null +++ b/src/renderer/state/settingsStore.ts @@ -0,0 +1,85 @@ +import { create } from 'zustand'; +import { immer } from 'zustand/middleware/immer'; +import { VariableObject } from 'shim/variables'; +import { RendererEventService } from '@/services/event/renderer-event-service'; + +interface VariableState { + variables: VariableObject[]; + collectionId: string; + isOpen: boolean; + allDoubleKeys: string[]; + lastInput: string | null; +} + +interface VariableStateAction { + openModal: () => void; + addNewVariable: () => void; + deleteVariable: (index: number) => void; + update: (index: number, changeValue: string | boolean, key: keyof VariableObject) => void; + save: () => void; + cancel: () => void; + checkDuplicate: (key: string) => void; +} + +export const useSettingsStore = create()( + immer((set, get) => ({ + variables: [], + collectionId: '', + isOpen: false, + allDoubleKeys: [], + lastInput: null, + openModal: () => { + RendererEventService.instance.loadCollection().then((collection) => { + set({ + variables: Object.values(collection.variables), + collectionId: collection.id, + isOpen: true, + }); + }); + }, + addNewVariable: () => { + set((state) => { + state.variables.push({ key: '', value: '', description: '', isActive: false }); + }); + }, + deleteVariable: (index: number) => { + set((state) => { + state.variables.splice(index, 1); + }); + }, + update: (index: number, changeValue: string | boolean, key: keyof VariableObject) => { + set((state) => { + state.variables[index] = { ...state.variables[index], [key]: changeValue }; + }); + }, + save: () => { + RendererEventService.instance.setAndSaveAllVariables(get().variables); + set((state) => { + state.variables = []; + state.isOpen = false; + state.lastInput = null; + }); + }, + cancel: () => { + set((state) => { + state.variables = []; + state.isOpen = false; + state.allDoubleKeys = []; + state.lastInput = null; + }); + }, + checkDuplicate: (key: string) => { + const isDuplicate = get().variables.filter((variable) => variable.key === key).length > 1; + set((state) => { + if (isDuplicate && !state.allDoubleKeys.includes(key)) { + state.allDoubleKeys.push(key); + } else { + state.allDoubleKeys = state.allDoubleKeys.filter( + (doubleKey) => doubleKey !== get().lastInput + ); + } + state.lastInput = key; + }); + }, + })) +); diff --git a/src/shim/event-service.ts b/src/shim/event-service.ts index 4fcd9b41..f6cfb964 100644 --- a/src/shim/event-service.ts +++ b/src/shim/event-service.ts @@ -63,4 +63,10 @@ export interface IEventService { * @param key The key of the variable. */ getVariable(key: string): Promise; + + /** + * Set a variable. + * @param variables + */ + setAndSaveAllVariables(variables: VariableObject[]): void; }