From 233a16c905261531a99eaced0e190ed2da1fbf7d Mon Sep 17 00:00:00 2001
From: Tristan Chin <23557893+maxijonson@users.noreply.github.com>
Date: Sun, 16 Jul 2023 01:47:39 -0400
Subject: [PATCH] [web] improve performance (#38)
---
package-lock.json | 1418 ++++++++++++++---
package.json | 3 +-
packages/web/package.json | 48 +-
packages/web/src/changelog/index.ts | 5 +-
packages/web/src/changelog/v4-4-1.ts | 21 +
.../web/src/components/{ => About}/About.tsx | 2 +-
.../web/src/components/About/AboutButton.tsx | 32 +
.../web/src/components/AddConversation.tsx | 36 +-
.../src/components/AddConversationForm.tsx | 38 -
.../{ => AppSettings}/AppSettings.tsx | 4 +-
.../AppSettingsDangerZone.tsx | 14 +-
.../{ => AppSettings}/AppStorageUsage.tsx | 2 +-
.../src/components/CallableFunctionCard.tsx | 215 ---
.../CallableFunctionCard.tsx | 64 +
.../CallableFunctionCardMenu.tsx | 86 +
.../CallableFunctionImport.tsx | 10 +-
.../CallableFunctionImportButton.tsx | 56 +-
.../CallableFunctionImportDropzone.tsx | 19 +-
packages/web/src/components/Changelog.tsx | 46 -
.../src/components/Changelog/Changelog.tsx | 90 ++
.../{ => Changelog}/ChangelogButton.tsx | 8 +-
.../web/src/components/ConversationNavbar.tsx | 173 --
.../ConversationNavbar/ConversationNavbar.tsx | 53 +
.../ConversationNavbarBurger.tsx | 35 +
.../ConversationNavbarFooter.tsx | 42 +
.../ConversationNavbarHeader.tsx | 42 +
.../SettingsButton.tsx | 27 +
.../NavbarConverationInfoIcon.tsx | 0
.../NavbarConversation.tsx | 24 +-
.../NavbarConversationInfo.tsx | 2 +-
.../NavbarConversations.tsx | 31 +-
.../src/components/ConversationPageShell.tsx | 31 +-
.../components/{ => Messages}/CodeBlock.tsx | 2 +-
.../src/components/{ => Messages}/Message.tsx | 14 +-
.../components/{ => Messages}/Messages.tsx | 8 +-
.../NavbarConversation.tsx | 232 +++
.../web/src/components/{ => Usage}/Usage.tsx | 10 +-
.../components/{ => Usage}/UsageMetric.tsx | 0
.../components/{ => common}/ContentLoader.tsx | 0
.../{ => common}/InlineConfirmButton.tsx | 0
.../{ => common}/TippedActionIcon.tsx | 0
.../{ => error-handling}/AppCatcher.tsx | 0
.../{ => error-handling}/StorageLoadError.tsx | 6 +-
.../CallableFunctionForm.tsx | 46 +-
.../CallableFunctionFormCode.tsx | 4 +-
.../CallableFunctionFormParameters.tsx | 8 +-
.../CallableFunctionForm}/CodeEditor.tsx | 2 +-
.../CallableFunctionParameterForm.tsx | 6 +-
.../ConversationForm}/ConversationForm.tsx | 6 +-
.../ConversationFormConversationTab.tsx | 22 +-
.../ConversationFormFunctionsTab.tsx | 13 +-
.../ConversationFormRequestTab.tsx | 6 +-
.../components/{ => inputs}/ApiKeyInput.tsx | 0
.../components/{ => inputs}/ContextInput.tsx | 8 +-
.../{ => inputs}/DisableModerationInput.tsx | 0
.../src/components/{ => inputs}/DryInput.tsx | 0
.../components/{ => inputs}/HeadersInput.tsx | 11 +-
.../{ => inputs}/LogitBiasInput.tsx | 11 +-
.../ModelSelectInput}/ModelSelectInput.tsx | 0
.../ModelSelectInput}/ModelSelectItem.tsx | 0
.../{ => inputs}/OptionalBooleanInput.tsx | 0
.../{ => inputs}/OptionalNumberInput.tsx | 0
.../{ => inputs}/OptionalTextInput.tsx | 0
.../components/{ => inputs/Prompt}/Prompt.tsx | 14 +-
.../{ => inputs/Prompt}/PromptUsage.tsx | 2 +-
.../components/{ => inputs}/ProxyInput.tsx | 0
.../src/components/{ => inputs}/SaveInput.tsx | 0
.../src/components/{ => inputs}/StopInput.tsx | 0
.../components/{ => inputs}/StreamInput.tsx | 0
.../{ => modals}/SavePromptModalBody.tsx | 10 +-
.../{ => modals}/SavedPromptsModalBody.tsx | 8 +-
.../{ => modals}/SettingsFormModal.tsx | 8 +-
.../{ => warnings}/FunctionsImportWarning.tsx | 4 +-
.../{ => warnings}/FunctionsWarning.tsx | 4 +-
packages/web/src/config/constants.ts | 2 +
.../src/contexts/CallableFunctionsContext.ts | 22 -
.../contexts/ConversationManagerContext.ts | 17 -
.../src/contexts/ConversationNavbarContext.ts | 18 +
.../contexts/hooks/useCallableFunctionForm.ts | 3 +
.../src/contexts/hooks/useConversationForm.ts | 3 +
.../contexts/hooks/useConversationNavbar.ts | 4 +
.../CallableFunctionFormProvider.tsx | 21 +-
.../providers/CallableFunctionsProvider.tsx | 163 --
.../providers/ConversationManagerProvider.tsx | 90 --
.../providers/ConversationNavbarProvider.tsx | 37 +
packages/web/src/contexts/providers/index.tsx | 12 +-
.../web/src/hooks/useCallableFunctionForm.ts | 3 -
.../web/src/hooks/useCallableFunctions.ts | 4 -
packages/web/src/hooks/useConversationForm.ts | 3 -
.../web/src/hooks/useConversationManager.ts | 4 -
packages/web/src/index.tsx | 2 +-
packages/web/src/pages/ConversationPage.tsx | 35 +-
packages/web/src/pages/FunctionEditorPage.tsx | 4 +-
packages/web/src/pages/FunctionsPage.tsx | 19 +-
packages/web/src/routers/AppRouter.tsx | 2 +-
packages/web/src/routers/FunctionsRouter.tsx | 2 +-
.../actions/appSettings/setLastChangelog.ts | 8 +-
.../actions/appSettings/toggleColorScheme.ts | 16 +-
.../actions/appSettings/toggleShowUsage.ts | 8 +-
.../callableFunctions/addCallableFunction.ts | 51 +-
.../callableFunctions/callFunction.tsx | 86 -
.../deleteCallableFunction.ts | 11 -
.../deleteCallableFunction.tsx | 50 +
.../dismissFunctionsImportWarning.ts | 8 +-
.../dismissFunctionsWarning.ts | 8 +-
.../duplicateCallableFunction.tsx | 68 +
.../removeAllCallableFunctions.ts | 8 +-
.../resetCallableFunctionWarnings.ts | 8 +-
.../actions/conversations/addConversation.ts | 34 +-
.../conversations/removeAllConversations.ts | 8 +-
.../conversations/removeConversation.ts | 8 +-
.../conversations/setActiveConversation.ts | 39 +-
.../conversations/setConversationLastEdit.ts | 15 +-
.../conversations/setConversationName.ts | 15 +-
.../web/src/store/actions/createAction.ts | 49 +
.../resetDefaultSettings.ts | 8 +-
.../setDefaultSettings.ts | 15 +-
.../persistence/addPersistedConversationId.ts | 15 +-
.../savedContexts/removeAllSavedContexts.ts | 8 +-
.../savedContexts/removeSavedContext.ts | 19 +-
.../actions/savedContexts/saveContext.ts | 15 +-
.../savedPrompts/removeAllSavedPrompts.ts | 8 +-
.../actions/savedPrompts/removeSavedPrompt.ts | 8 +-
.../store/actions/savedPrompts/savePrompt.ts | 15 +-
.../callableFunctions/useCallFunction.tsx | 89 ++
.../hooks/callableFunctions/useGetFunction.ts | 14 +
.../callableFunctions/useGetFunctionCode.ts | 13 +
.../useGetFunctionDisplayName.ts | 16 +
.../useGetUniqueFunctionDisplayName.ts | 24 +
.../useGetUniqueFunctionName.ts | 20 +
.../conversations/useActiveConversation.ts | 16 +
.../useGetConversationLastEdit.ts | 13 +
.../conversations/useGetConversationName.ts | 11 +
packages/web/src/store/index.ts | 2 +-
.../web/src/store/persist/migrateOldData.ts | 33 +-
.../src/store/persist/onStoreRehydrate.tsx | 2 +-
.../web/src/store/persist/partializeStore.ts | 5 +-
.../web/src/store/persist/triggerPersist.ts | 8 +-
packages/web/src/utils/getUniqueString.ts | 12 +
packages/web/vite.config.ts | 35 +
140 files changed, 2967 insertions(+), 1567 deletions(-)
create mode 100644 packages/web/src/changelog/v4-4-1.ts
rename packages/web/src/components/{ => About}/About.tsx (97%)
create mode 100644 packages/web/src/components/About/AboutButton.tsx
delete mode 100644 packages/web/src/components/AddConversationForm.tsx
rename packages/web/src/components/{ => AppSettings}/AppSettings.tsx (91%)
rename packages/web/src/components/{ => AppSettings}/AppSettingsDangerZone.tsx (73%)
rename packages/web/src/components/{ => AppSettings}/AppStorageUsage.tsx (98%)
delete mode 100644 packages/web/src/components/CallableFunctionCard.tsx
create mode 100644 packages/web/src/components/CallableFunctionCard/CallableFunctionCard.tsx
create mode 100644 packages/web/src/components/CallableFunctionCard/CallableFunctionCardMenu.tsx
rename packages/web/src/components/{ => CallableFunctionImport}/CallableFunctionImport.tsx (93%)
rename packages/web/src/components/{ => CallableFunctionImport}/CallableFunctionImportButton.tsx (56%)
rename packages/web/src/components/{ => CallableFunctionImport}/CallableFunctionImportDropzone.tsx (86%)
delete mode 100644 packages/web/src/components/Changelog.tsx
create mode 100644 packages/web/src/components/Changelog/Changelog.tsx
rename packages/web/src/components/{ => Changelog}/ChangelogButton.tsx (87%)
delete mode 100644 packages/web/src/components/ConversationNavbar.tsx
create mode 100644 packages/web/src/components/ConversationNavbar/ConversationNavbar.tsx
create mode 100644 packages/web/src/components/ConversationNavbar/ConversationNavbarBurger.tsx
create mode 100644 packages/web/src/components/ConversationNavbar/ConversationNavbarFooter/ConversationNavbarFooter.tsx
create mode 100644 packages/web/src/components/ConversationNavbar/ConversationNavbarHeader/ConversationNavbarHeader.tsx
create mode 100644 packages/web/src/components/ConversationNavbar/ConversationNavbarHeader/SettingsButton.tsx
rename packages/web/src/components/{ => ConversationNavbar/NavbarConversations}/NavbarConverationInfoIcon.tsx (100%)
rename packages/web/src/components/{ => ConversationNavbar/NavbarConversations}/NavbarConversation.tsx (86%)
rename packages/web/src/components/{ => ConversationNavbar/NavbarConversations}/NavbarConversationInfo.tsx (98%)
rename packages/web/src/components/{ => ConversationNavbar/NavbarConversations}/NavbarConversations.tsx (86%)
rename packages/web/src/components/{ => Messages}/CodeBlock.tsx (97%)
rename packages/web/src/components/{ => Messages}/Message.tsx (95%)
rename packages/web/src/components/{ => Messages}/Messages.tsx (94%)
create mode 100644 packages/web/src/components/NavbarConversations/NavbarConversation.tsx
rename packages/web/src/components/{ => Usage}/Usage.tsx (81%)
rename packages/web/src/components/{ => Usage}/UsageMetric.tsx (100%)
rename packages/web/src/components/{ => common}/ContentLoader.tsx (100%)
rename packages/web/src/components/{ => common}/InlineConfirmButton.tsx (100%)
rename packages/web/src/components/{ => common}/TippedActionIcon.tsx (100%)
rename packages/web/src/components/{ => error-handling}/AppCatcher.tsx (100%)
rename packages/web/src/components/{ => error-handling}/StorageLoadError.tsx (96%)
rename packages/web/src/components/{ => forms/CallableFunctionForm}/CallableFunctionForm.tsx (69%)
rename packages/web/src/components/{ => forms/CallableFunctionForm}/CallableFunctionFormCode.tsx (95%)
rename packages/web/src/components/{ => forms/CallableFunctionForm}/CallableFunctionFormParameters.tsx (95%)
rename packages/web/src/components/{ => forms/CallableFunctionForm}/CodeEditor.tsx (98%)
rename packages/web/src/components/{ => forms/CallableFunctionParameterForm}/CallableFunctionParameterForm.tsx (98%)
rename packages/web/src/components/{ => forms/ConversationForm}/ConversationForm.tsx (94%)
rename packages/web/src/components/{ => forms/ConversationForm}/ConversationFormConversationTab.tsx (85%)
rename packages/web/src/components/{ => forms/ConversationForm}/ConversationFormFunctionsTab.tsx (77%)
rename packages/web/src/components/{ => forms/ConversationForm}/ConversationFormRequestTab.tsx (65%)
rename packages/web/src/components/{ => inputs}/ApiKeyInput.tsx (100%)
rename packages/web/src/components/{ => inputs}/ContextInput.tsx (91%)
rename packages/web/src/components/{ => inputs}/DisableModerationInput.tsx (100%)
rename packages/web/src/components/{ => inputs}/DryInput.tsx (100%)
rename packages/web/src/components/{ => inputs}/HeadersInput.tsx (95%)
rename packages/web/src/components/{ => inputs}/LogitBiasInput.tsx (96%)
rename packages/web/src/components/{ => inputs/ModelSelectInput}/ModelSelectInput.tsx (100%)
rename packages/web/src/components/{ => inputs/ModelSelectInput}/ModelSelectItem.tsx (100%)
rename packages/web/src/components/{ => inputs}/OptionalBooleanInput.tsx (100%)
rename packages/web/src/components/{ => inputs}/OptionalNumberInput.tsx (100%)
rename packages/web/src/components/{ => inputs}/OptionalTextInput.tsx (100%)
rename packages/web/src/components/{ => inputs/Prompt}/Prompt.tsx (92%)
rename packages/web/src/components/{ => inputs/Prompt}/PromptUsage.tsx (96%)
rename packages/web/src/components/{ => inputs}/ProxyInput.tsx (100%)
rename packages/web/src/components/{ => inputs}/SaveInput.tsx (100%)
rename packages/web/src/components/{ => inputs}/StopInput.tsx (100%)
rename packages/web/src/components/{ => inputs}/StreamInput.tsx (100%)
rename packages/web/src/components/{ => modals}/SavePromptModalBody.tsx (86%)
rename packages/web/src/components/{ => modals}/SavedPromptsModalBody.tsx (89%)
rename packages/web/src/components/{ => modals}/SettingsFormModal.tsx (78%)
rename packages/web/src/components/{ => warnings}/FunctionsImportWarning.tsx (93%)
rename packages/web/src/components/{ => warnings}/FunctionsWarning.tsx (93%)
delete mode 100644 packages/web/src/contexts/CallableFunctionsContext.ts
delete mode 100644 packages/web/src/contexts/ConversationManagerContext.ts
create mode 100644 packages/web/src/contexts/ConversationNavbarContext.ts
create mode 100644 packages/web/src/contexts/hooks/useCallableFunctionForm.ts
create mode 100644 packages/web/src/contexts/hooks/useConversationForm.ts
create mode 100644 packages/web/src/contexts/hooks/useConversationNavbar.ts
delete mode 100644 packages/web/src/contexts/providers/CallableFunctionsProvider.tsx
delete mode 100644 packages/web/src/contexts/providers/ConversationManagerProvider.tsx
create mode 100644 packages/web/src/contexts/providers/ConversationNavbarProvider.tsx
delete mode 100644 packages/web/src/hooks/useCallableFunctionForm.ts
delete mode 100644 packages/web/src/hooks/useCallableFunctions.ts
delete mode 100644 packages/web/src/hooks/useConversationForm.ts
delete mode 100644 packages/web/src/hooks/useConversationManager.ts
delete mode 100644 packages/web/src/store/actions/callableFunctions/callFunction.tsx
delete mode 100644 packages/web/src/store/actions/callableFunctions/deleteCallableFunction.ts
create mode 100644 packages/web/src/store/actions/callableFunctions/deleteCallableFunction.tsx
create mode 100644 packages/web/src/store/actions/callableFunctions/duplicateCallableFunction.tsx
create mode 100644 packages/web/src/store/actions/createAction.ts
create mode 100644 packages/web/src/store/hooks/callableFunctions/useCallFunction.tsx
create mode 100644 packages/web/src/store/hooks/callableFunctions/useGetFunction.ts
create mode 100644 packages/web/src/store/hooks/callableFunctions/useGetFunctionCode.ts
create mode 100644 packages/web/src/store/hooks/callableFunctions/useGetFunctionDisplayName.ts
create mode 100644 packages/web/src/store/hooks/callableFunctions/useGetUniqueFunctionDisplayName.ts
create mode 100644 packages/web/src/store/hooks/callableFunctions/useGetUniqueFunctionName.ts
create mode 100644 packages/web/src/store/hooks/conversations/useActiveConversation.ts
create mode 100644 packages/web/src/store/hooks/conversations/useGetConversationLastEdit.ts
create mode 100644 packages/web/src/store/hooks/conversations/useGetConversationName.ts
create mode 100644 packages/web/src/utils/getUniqueString.ts
diff --git a/package-lock.json b/package-lock.json
index ddda2d4..781ddc4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,7 +13,8 @@
"immer": "^10.0.2"
},
"devDependencies": {
- "lerna": "^7.0.2"
+ "lerna": "^7.0.2",
+ "typescript": "^5.1.6"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -3727,14 +3728,14 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
- "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz",
+ "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
- "espree": "^9.5.2",
+ "espree": "^9.6.0",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
@@ -3784,9 +3785,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "8.43.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz",
- "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==",
+ "version": "8.44.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz",
+ "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -4138,43 +4139,10 @@
"node": ">=8"
}
},
- "node_modules/@mantine/core": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/core/-/core-6.0.14.tgz",
- "integrity": "sha512-O916itwsB5XtEStVZRqp3SlB4aLM0sSgOFYYCVnLJ3E9O9E8h1xhaNEml1FJbMtrlNaXYUd6sy/OSRqNl9DyKA==",
- "dependencies": {
- "@floating-ui/react": "^0.19.1",
- "@mantine/styles": "6.0.14",
- "@mantine/utils": "6.0.14",
- "@radix-ui/react-scroll-area": "1.0.2",
- "react-remove-scroll": "^2.5.5",
- "react-textarea-autosize": "8.3.4"
- },
- "peerDependencies": {
- "@mantine/hooks": "6.0.14",
- "react": ">=16.8.0",
- "react-dom": ">=16.8.0"
- }
- },
- "node_modules/@mantine/dropzone": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/dropzone/-/dropzone-6.0.14.tgz",
- "integrity": "sha512-rurn7wfqMx4vuU3glS2UpwbKId+TB7H1mY4s5Z2YExMb5ffty58G+io10ACKIhQ7iTgcvxpK9fyFVLsnRHT64A==",
- "dependencies": {
- "@mantine/utils": "6.0.14",
- "react-dropzone": "14.2.3"
- },
- "peerDependencies": {
- "@mantine/core": "6.0.14",
- "@mantine/hooks": "6.0.14",
- "react": ">=16.8.0",
- "react-dom": ">=16.8.0"
- }
- },
"node_modules/@mantine/form": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/form/-/form-6.0.14.tgz",
- "integrity": "sha512-2QlDN3PBMxHUxtoBy0ycc3InpATGje5sJXmw/Co9qiVtKUHe5pxcVl341CnA+MCI91uC2Ycucf20n/8GTLezrw==",
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/form/-/form-6.0.16.tgz",
+ "integrity": "sha512-4TwxJKGQQRx7rj5yb9WgS0z/Ud8ckg0mMCiD3grKTxDCp0g8Tvk2Df7ptWFx2n+hxhBYVwMQSKggWuuDMFWBNA==",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"klona": "^2.0.5"
@@ -4183,41 +4151,6 @@
"react": ">=16.8.0"
}
},
- "node_modules/@mantine/hooks": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-6.0.14.tgz",
- "integrity": "sha512-cBGdTSdBDLcPScoeI12DCWFVzmT4tX+DmI9s+MOBm4IdhF4ogkLbbRgKosFbaBWNKx9WzYAUiQR/tUI5dTkJPQ==",
- "peerDependencies": {
- "react": ">=16.8.0"
- }
- },
- "node_modules/@mantine/styles": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/styles/-/styles-6.0.14.tgz",
- "integrity": "sha512-qkqUodvVPzthmVzWQHYe/yWrc8UZcz8A5KfegK2Ps67bZzfoZs/NBVcEx6REq8HTsISjYw3jJyMRxAE3G7Ms4Q==",
- "dependencies": {
- "clsx": "1.1.1",
- "csstype": "3.0.9"
- },
- "peerDependencies": {
- "@emotion/react": ">=11.9.0",
- "react": ">=16.8.0",
- "react-dom": ">=16.8.0"
- }
- },
- "node_modules/@mantine/styles/node_modules/csstype": {
- "version": "3.0.9",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz",
- "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw=="
- },
- "node_modules/@mantine/utils": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/utils/-/utils-6.0.14.tgz",
- "integrity": "sha512-se+3IXJsNj4wnLMlqc7LiBe74m+JLQJ5o3wEcDtFzaJEtEt1rtw/1q3xKuROkH3xEiauhxQgzsc4gj/AslHy2A==",
- "peerDependencies": {
- "react": ">=16.8.0"
- }
- },
"node_modules/@nestjs/cli": {
"version": "9.5.0",
"resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-9.5.0.tgz",
@@ -5126,6 +5059,62 @@
"node": ">=14"
}
},
+ "node_modules/@pkgr/utils": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz",
+ "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "fast-glob": "^3.3.0",
+ "is-glob": "^4.0.3",
+ "open": "^9.1.0",
+ "picocolors": "^1.0.0",
+ "tslib": "^2.6.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/unts"
+ }
+ },
+ "node_modules/@pkgr/utils/node_modules/define-lazy-prop": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+ "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@pkgr/utils/node_modules/open": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz",
+ "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==",
+ "dev": true,
+ "dependencies": {
+ "default-browser": "^4.0.0",
+ "define-lazy-prop": "^3.0.0",
+ "is-inside-container": "^1.0.0",
+ "is-wsl": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@pkgr/utils/node_modules/tslib": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz",
+ "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==",
+ "dev": true
+ },
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
@@ -5316,9 +5305,9 @@
}
},
"node_modules/@remix-run/router": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.6.3.tgz",
- "integrity": "sha512-EXJysQ7J3veRECd0kZFQwYYd5sJMcq2O/m60zu1W2l3oVQ9xtub8jTOtYRE0+M2iomyG/W3Ps7+vp2kna0C27Q==",
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.1.tgz",
+ "integrity": "sha512-bgVQM4ZJ2u2CM8k1ey70o1ePFXsEzYVZoWghh6WjM8p59jQ7HxzbHW4SbnWFG7V9ig9chLawQxDTZ3xzOF8MkQ==",
"engines": {
"node": ">=14"
}
@@ -5647,20 +5636,20 @@
}
},
"node_modules/@tabler/icons": {
- "version": "2.22.0",
- "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-2.22.0.tgz",
- "integrity": "sha512-lOsGHqRPIKNARMWHHFkUUJH78C8ptQmUcDnumFBUI4YLRKFouKa7uAZL3ZfuH0HjDpOhsnWqUYZ7FhMCLcGpAQ==",
+ "version": "2.25.0",
+ "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-2.25.0.tgz",
+ "integrity": "sha512-Z+FtSZoG/CM1TMCgg7elUew2m0+qMdh5gutMhvxiIY77KIIsE6L/6fUBy+rPXWE9v7MV296fsnCvbpfgwpXupQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/codecalm"
}
},
"node_modules/@tabler/icons-react": {
- "version": "2.22.0",
- "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-2.22.0.tgz",
- "integrity": "sha512-9udRxrbsbWzUETur4jmbZQIZkH7jVA2GU7YnKYS7ZCUjdOHZZEhmsfJ/Gdbzz0gSRC3mU7SDMsKejun/IBjvpQ==",
+ "version": "2.25.0",
+ "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-2.25.0.tgz",
+ "integrity": "sha512-so/amZZcvuZBBTMinReI219ek1MwlZfccGfRu7IwXEhgHftFTfyBOvTK9Kgf4vM+9+i0CcuVRoxyfQiuUwYUWg==",
"dependencies": {
- "@tabler/icons": "2.22.0",
+ "@tabler/icons": "2.25.0",
"prop-types": "^15.7.2"
},
"funding": {
@@ -6283,9 +6272,9 @@
"dev": true
},
"node_modules/@types/react": {
- "version": "18.2.12",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.12.tgz",
- "integrity": "sha512-ndmBMLCgn38v3SntMeoJaIrO6tGHYKMEBohCUmw8HoLLQdRMOIGXfeYaBTLe2lsFaSB3MOK1VXscYFnmLtTSmw==",
+ "version": "18.2.15",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.15.tgz",
+ "integrity": "sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==",
"devOptional": true,
"dependencies": {
"@types/prop-types": "*",
@@ -6294,9 +6283,9 @@
}
},
"node_modules/@types/react-dom": {
- "version": "18.2.5",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.5.tgz",
- "integrity": "sha512-sRQsOS/sCLnpQhR4DSKGTtWFE3FZjpQa86KPVbhUqdYMRZ9FEFcfAytKhR/vUG2rH1oFbOOej6cuD7MFSobDRQ==",
+ "version": "18.2.7",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz",
+ "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==",
"dev": true,
"dependencies": {
"@types/react": "*"
@@ -7347,6 +7336,15 @@
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
"dev": true
},
+ "node_modules/big-integer": {
+ "version": "1.6.51",
+ "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
+ "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -7409,6 +7407,18 @@
"integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==",
"optional": true
},
+ "node_modules/bplist-parser": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
+ "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==",
+ "dev": true,
+ "dependencies": {
+ "big-integer": "^1.6.44"
+ },
+ "engines": {
+ "node": ">= 5.10.0"
+ }
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -7530,6 +7540,21 @@
"semver": "^7.0.0"
}
},
+ "node_modules/bundle-name": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
+ "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==",
+ "dev": true,
+ "dependencies": {
+ "run-applescript": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
@@ -8563,6 +8588,162 @@
"node": ">=0.10.0"
}
},
+ "node_modules/default-browser": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz",
+ "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==",
+ "dev": true,
+ "dependencies": {
+ "bundle-name": "^3.0.0",
+ "default-browser-id": "^3.0.0",
+ "execa": "^7.1.1",
+ "titleize": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser-id": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz",
+ "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==",
+ "dev": true,
+ "dependencies": {
+ "bplist-parser": "^0.2.0",
+ "untildify": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser/node_modules/execa": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz",
+ "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.1",
+ "human-signals": "^4.3.0",
+ "is-stream": "^3.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^5.1.0",
+ "onetime": "^6.0.0",
+ "signal-exit": "^3.0.7",
+ "strip-final-newline": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || ^16.14.0 || >=18.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/default-browser/node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser/node_modules/human-signals": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
+ "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.18.0"
+ }
+ },
+ "node_modules/default-browser/node_modules/is-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+ "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser/node_modules/mimic-fn": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
+ "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser/node_modules/npm-run-path": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
+ "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^4.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser/node_modules/onetime": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
+ "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser/node_modules/strip-final-newline": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
+ "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/defaults": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
@@ -9060,15 +9241,15 @@
}
},
"node_modules/eslint": {
- "version": "8.43.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz",
- "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==",
+ "version": "8.45.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz",
+ "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
- "@eslint/eslintrc": "^2.0.3",
- "@eslint/js": "8.43.0",
+ "@eslint/eslintrc": "^2.1.0",
+ "@eslint/js": "8.44.0",
"@humanwhocodes/config-array": "^0.11.10",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -9080,7 +9261,7 @@
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.0",
"eslint-visitor-keys": "^3.4.1",
- "espree": "^9.5.2",
+ "espree": "^9.6.0",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
@@ -9090,7 +9271,6 @@
"globals": "^13.19.0",
"graphemer": "^1.4.0",
"ignore": "^5.2.0",
- "import-fresh": "^3.0.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
@@ -9100,9 +9280,8 @@
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
+ "optionator": "^0.9.3",
"strip-ansi": "^6.0.1",
- "strip-json-comments": "^3.1.0",
"text-table": "^0.2.0"
},
"bin": {
@@ -9161,9 +9340,9 @@
}
},
"node_modules/eslint-plugin-react-refresh": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.1.tgz",
- "integrity": "sha512-QgrvtRJkmV+m4w953LS146+6RwEe5waouubFVNLBfOjXJf6MLczjymO8fOcKj9jMS8aKkTCMJqiPu2WEeFI99A==",
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.3.tgz",
+ "integrity": "sha512-Hh0wv8bUNY877+sI0BlCUlsS0TYYQqvzEwJsJJPM2WF4RnTStSnSR3zdJYa2nPOJgg3UghXi54lVyMSmpCalzA==",
"dev": true,
"peerDependencies": {
"eslint": ">=7"
@@ -9266,12 +9445,12 @@
}
},
"node_modules/espree": {
- "version": "9.5.2",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz",
- "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==",
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
"dev": true,
"dependencies": {
- "acorn": "^8.8.0",
+ "acorn": "^8.9.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^3.4.1"
},
@@ -9547,9 +9726,9 @@
"dev": true
},
"node_modules/fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
+ "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==",
"dev": true,
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
@@ -11424,6 +11603,39 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-inside-container": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+ "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+ "dev": true,
+ "dependencies": {
+ "is-docker": "^3.0.0"
+ },
+ "bin": {
+ "is-inside-container": "cli.js"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-inside-container/node_modules/is-docker": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+ "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+ "dev": true,
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-interactive": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
@@ -15055,9 +15267,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.24",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
- "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
+ "version": "8.4.26",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz",
+ "integrity": "sha512-jrXHFF8iTloAenySjM/ob3gSj7pCu0Ji49hnjqzsgSRa50hkWCKD0HQ+gMNJkW38jBI68MpAAg7ZWwHwX8NMMw==",
"dev": true,
"funding": [
{
@@ -15600,9 +15812,9 @@
}
},
"node_modules/react-icons": {
- "version": "4.9.0",
- "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.9.0.tgz",
- "integrity": "sha512-ijUnFr//ycebOqujtqtV9PFS7JjhWg0QU6ykURVHuL4cbofvRCf3f6GMn9+fBktEFQOIVZnuAYLZdiyadRQRFg==",
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.10.1.tgz",
+ "integrity": "sha512-/ngzDP/77tlCfqthiiGNZeYFACw85fUjZtLbedmJ5DTlNDIwETxhwBzdOJ21zj4iJdvc0J3y7yOsX3PpxAJzrw==",
"peerDependencies": {
"react": "*"
}
@@ -15673,11 +15885,11 @@
}
},
"node_modules/react-router": {
- "version": "6.13.0",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.13.0.tgz",
- "integrity": "sha512-Si6KnfEnJw7gUQkNa70dlpI1bul46FuSxX5t5WwlUBxE25DAz2BjVkwaK8Y2s242bQrZPXCpmwLPtIO5pv4tXg==",
+ "version": "6.14.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.1.tgz",
+ "integrity": "sha512-U4PfgvG55LdvbQjg5Y9QRWyVxIdO1LlpYT7x+tMAxd9/vmiPuJhIwdxZuIQLN/9e3O4KFDHYfR9gzGeYMasW8g==",
"dependencies": {
- "@remix-run/router": "1.6.3"
+ "@remix-run/router": "1.7.1"
},
"engines": {
"node": ">=14"
@@ -15687,12 +15899,12 @@
}
},
"node_modules/react-router-dom": {
- "version": "6.13.0",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.13.0.tgz",
- "integrity": "sha512-6Nqoqd7fgwxxVGdbiMHTpDHCYPq62d7Wk1Of7B82vH7ZPwwsRaIa22zRZKPPg413R5REVNiyuQPKDG1bubcOFA==",
+ "version": "6.14.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.1.tgz",
+ "integrity": "sha512-ssF6M5UkQjHK70fgukCJyjlda0Dgono2QGwqGvuk7D+EDGHdacEN3Yke2LTMjkrpHuFwBfDFsEjGVXBDmL+bWw==",
"dependencies": {
- "@remix-run/router": "1.6.3",
- "react-router": "6.13.0"
+ "@remix-run/router": "1.7.1",
+ "react-router": "6.14.1"
},
"engines": {
"node": ">=14"
@@ -16443,9 +16655,9 @@
}
},
"node_modules/rollup": {
- "version": "3.25.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz",
- "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==",
+ "version": "3.26.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.2.tgz",
+ "integrity": "sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
@@ -16463,6 +16675,21 @@
"resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
"integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ=="
},
+ "node_modules/run-applescript": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz",
+ "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==",
+ "dev": true,
+ "dependencies": {
+ "execa": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@@ -17391,13 +17618,29 @@
"node": ">=0.10"
}
},
- "node_modules/tabbable": {
- "version": "6.1.2",
- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.1.2.tgz",
- "integrity": "sha512-qCN98uP7i9z0fIS4amQ5zbGBOq+OSigYeGvPy7NDk8Y9yncqDZ9pRPgfsc2PJIVM9RrJj7GIfuRgmjoUU9zTHQ=="
- },
- "node_modules/tapable": {
- "version": "2.2.1",
+ "node_modules/synckit": {
+ "version": "0.8.5",
+ "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
+ "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==",
+ "dev": true,
+ "dependencies": {
+ "@pkgr/utils": "^2.3.1",
+ "tslib": "^2.5.0"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/unts"
+ }
+ },
+ "node_modules/tabbable": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.1.2.tgz",
+ "integrity": "sha512-qCN98uP7i9z0fIS4amQ5zbGBOq+OSigYeGvPy7NDk8Y9yncqDZ9pRPgfsc2PJIVM9RrJj7GIfuRgmjoUU9zTHQ=="
+ },
+ "node_modules/tapable": {
+ "version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"dev": true,
@@ -17670,6 +17913,18 @@
"@popperjs/core": "^2.9.0"
}
},
+ "node_modules/titleize": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz",
+ "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/tmp": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
@@ -17797,6 +18052,18 @@
"node": ">=8"
}
},
+ "node_modules/ts-api-utils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz",
+ "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=16.13.0"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.2.0"
+ }
+ },
"node_modules/ts-loader": {
"version": "9.4.3",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.3.tgz",
@@ -18082,9 +18349,9 @@
}
},
"node_modules/typescript": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
- "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz",
+ "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -18461,14 +18728,14 @@
}
},
"node_modules/vite": {
- "version": "4.3.9",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
- "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
+ "version": "4.4.4",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.4.tgz",
+ "integrity": "sha512-4mvsTxjkveWrKDJI70QmelfVqTm+ihFAb6+xf4sjEU2TmUCTlVX87tmg/QooPEMQb/lM9qGHT99ebqPziEd3wg==",
"dev": true,
"dependencies": {
- "esbuild": "^0.17.5",
- "postcss": "^8.4.23",
- "rollup": "^3.21.0"
+ "esbuild": "^0.18.10",
+ "postcss": "^8.4.25",
+ "rollup": "^3.25.2"
},
"bin": {
"vite": "bin/vite.js"
@@ -18476,12 +18743,16 @@
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
"@types/node": ">= 14",
"less": "*",
+ "lightningcss": "^1.21.0",
"sass": "*",
"stylus": "*",
"sugarss": "*",
@@ -18494,6 +18765,9 @@
"less": {
"optional": true
},
+ "lightningcss": {
+ "optional": true
+ },
"sass": {
"optional": true
},
@@ -18523,43 +18797,432 @@
"vite": ">=2"
}
},
- "node_modules/vite-plugin-eslint/node_modules/rollup": {
- "version": "2.79.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
- "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
+ "node_modules/vite-plugin-eslint/node_modules/rollup": {
+ "version": "2.79.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
+ "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
+ "dev": true,
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/vite-plugin-pwa": {
+ "version": "0.16.4",
+ "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.16.4.tgz",
+ "integrity": "sha512-lmwHFIs9zI2H9bXJld/zVTbCqCQHZ9WrpyDMqosICDV0FVnCJwniX1NMDB79HGTIZzOQkY4gSZaVTJTw6maz/Q==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.3.4",
+ "fast-glob": "^3.2.12",
+ "pretty-bytes": "^6.0.0",
+ "workbox-build": "^7.0.0",
+ "workbox-window": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vite": "^3.1.0 || ^4.0.0",
+ "workbox-build": "^7.0.0",
+ "workbox-window": "^7.0.0"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/android-arm": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.13.tgz",
+ "integrity": "sha512-KwqFhxRFMKZINHzCqf8eKxE0XqWlAVPRxwy6rc7CbVFxzUWB2sA/s3hbMZeemPdhN3fKBkqOaFhTbS8xJXYIWQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/android-arm64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.13.tgz",
+ "integrity": "sha512-j7NhycJUoUAG5kAzGf4fPWfd17N6SM3o1X6MlXVqfHvs2buFraCJzos9vbeWjLxOyBKHyPOnuCuipbhvbYtTAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/android-x64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.13.tgz",
+ "integrity": "sha512-M2eZkRxR6WnWfVELHmv6MUoHbOqnzoTVSIxgtsyhm/NsgmL+uTmag/VVzdXvmahak1I6sOb1K/2movco5ikDJg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/darwin-arm64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.13.tgz",
+ "integrity": "sha512-f5goG30YgR1GU+fxtaBRdSW3SBG9pZW834Mmhxa6terzcboz7P2R0k4lDxlkP7NYRIIdBbWp+VgwQbmMH4yV7w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/darwin-x64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.13.tgz",
+ "integrity": "sha512-RIrxoKH5Eo+yE5BtaAIMZaiKutPhZjw+j0OCh8WdvKEKJQteacq0myZvBDLU+hOzQOZWJeDnuQ2xgSScKf1Ovw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.13.tgz",
+ "integrity": "sha512-AfRPhHWmj9jGyLgW/2FkYERKmYR+IjYxf2rtSLmhOrPGFh0KCETFzSjx/JX/HJnvIqHt/DRQD/KAaVsUKoI3Xg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/freebsd-x64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.13.tgz",
+ "integrity": "sha512-pGzWWZJBInhIgdEwzn8VHUBang8UvFKsvjDkeJ2oyY5gZtAM6BaxK0QLCuZY+qoj/nx/lIaItH425rm/hloETA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-arm": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.13.tgz",
+ "integrity": "sha512-4iMxLRMCxGyk7lEvkkvrxw4aJeC93YIIrfbBlUJ062kilUUnAiMb81eEkVvCVoh3ON283ans7+OQkuy1uHW+Hw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-arm64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.13.tgz",
+ "integrity": "sha512-hCzZbVJEHV7QM77fHPv2qgBcWxgglGFGCxk6KfQx6PsVIdi1u09X7IvgE9QKqm38OpkzaAkPnnPqwRsltvLkIQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-ia32": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.13.tgz",
+ "integrity": "sha512-I3OKGbynl3AAIO6onXNrup/ttToE6Rv2XYfFgLK/wnr2J+1g+7k4asLrE+n7VMhaqX+BUnyWkCu27rl+62Adug==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-loong64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.13.tgz",
+ "integrity": "sha512-8pcKDApAsKc6WW51ZEVidSGwGbebYw2qKnO1VyD8xd6JN0RN6EUXfhXmDk9Vc4/U3Y4AoFTexQewQDJGsBXBpg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-mips64el": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.13.tgz",
+ "integrity": "sha512-6GU+J1PLiVqWx8yoCK4Z0GnfKyCGIH5L2KQipxOtbNPBs+qNDcMJr9euxnyJ6FkRPyMwaSkjejzPSISD9hb+gg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-ppc64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.13.tgz",
+ "integrity": "sha512-pfn/OGZ8tyR8YCV7MlLl5hAit2cmS+j/ZZg9DdH0uxdCoJpV7+5DbuXrR+es4ayRVKIcfS9TTMCs60vqQDmh+w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-riscv64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.13.tgz",
+ "integrity": "sha512-aIbhU3LPg0lOSCfVeGHbmGYIqOtW6+yzO+Nfv57YblEK01oj0mFMtvDJlOaeAZ6z0FZ9D13oahi5aIl9JFphGg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-s390x": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.13.tgz",
+ "integrity": "sha512-Pct1QwF2sp+5LVi4Iu5Y+6JsGaV2Z2vm4O9Dd7XZ5tKYxEHjFtb140fiMcl5HM1iuv6xXO8O1Vrb1iJxHlv8UA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/linux-x64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.13.tgz",
+ "integrity": "sha512-zTrIP0KzYP7O0+3ZnmzvUKgGtUvf4+piY8PIO3V8/GfmVd3ZyHJGz7Ht0np3P1wz+I8qJ4rjwJKqqEAbIEPngA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/netbsd-x64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.13.tgz",
+ "integrity": "sha512-I6zs10TZeaHDYoGxENuksxE1sxqZpCp+agYeW039yqFwh3MgVvdmXL5NMveImOC6AtpLvE4xG5ujVic4NWFIDQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/openbsd-x64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.13.tgz",
+ "integrity": "sha512-W5C5nczhrt1y1xPG5bV+0M12p2vetOGlvs43LH8SopQ3z2AseIROu09VgRqydx5qFN7y9qCbpgHLx0kb0TcW7g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/sunos-x64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.13.tgz",
+ "integrity": "sha512-X/xzuw4Hzpo/yq3YsfBbIsipNgmsm8mE/QeWbdGdTTeZ77fjxI2K0KP3AlhZ6gU3zKTw1bKoZTuKLnqcJ537qw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/win32-arm64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.13.tgz",
+ "integrity": "sha512-4CGYdRQT/ILd+yLLE5i4VApMPfGE0RPc/wFQhlluDQCK09+b4JDbxzzjpgQqTPrdnP7r5KUtGVGZYclYiPuHrw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/win32-ia32": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.13.tgz",
+ "integrity": "sha512-D+wKZaRhQI+MUGMH+DbEr4owC2D7XnF+uyGiZk38QbgzLcofFqIOwFs7ELmIeU45CQgfHNy9Q+LKW3cE8g37Kg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/vite/node_modules/@esbuild/win32-x64": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.13.tgz",
+ "integrity": "sha512-iVl6lehAfJS+VmpF3exKpNQ8b0eucf5VWfzR8S7xFve64NBNz2jPUgx1X93/kfnkfgP737O+i1k54SVQS7uVZA==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "bin": {
- "rollup": "dist/bin/rollup"
- },
+ "optional": true,
+ "os": [
+ "win32"
+ ],
"engines": {
- "node": ">=10.0.0"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
+ "node": ">=12"
}
},
- "node_modules/vite-plugin-pwa": {
- "version": "0.16.4",
- "resolved": "https://registry.npmjs.org/vite-plugin-pwa/-/vite-plugin-pwa-0.16.4.tgz",
- "integrity": "sha512-lmwHFIs9zI2H9bXJld/zVTbCqCQHZ9WrpyDMqosICDV0FVnCJwniX1NMDB79HGTIZzOQkY4gSZaVTJTw6maz/Q==",
+ "node_modules/vite/node_modules/esbuild": {
+ "version": "0.18.13",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.13.tgz",
+ "integrity": "sha512-vhg/WR/Oiu4oUIkVhmfcc23G6/zWuEQKFS+yiosSHe4aN6+DQRXIfeloYGibIfVhkr4wyfuVsGNLr+sQU1rWWw==",
"dev": true,
- "dependencies": {
- "debug": "^4.3.4",
- "fast-glob": "^3.2.12",
- "pretty-bytes": "^6.0.0",
- "workbox-build": "^7.0.0",
- "workbox-window": "^7.0.0"
+ "hasInstallScript": true,
+ "bin": {
+ "esbuild": "bin/esbuild"
},
"engines": {
- "node": ">=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/antfu"
+ "node": ">=12"
},
- "peerDependencies": {
- "vite": "^3.1.0 || ^4.0.0",
- "workbox-build": "^7.0.0",
- "workbox-window": "^7.0.0"
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.18.13",
+ "@esbuild/android-arm64": "0.18.13",
+ "@esbuild/android-x64": "0.18.13",
+ "@esbuild/darwin-arm64": "0.18.13",
+ "@esbuild/darwin-x64": "0.18.13",
+ "@esbuild/freebsd-arm64": "0.18.13",
+ "@esbuild/freebsd-x64": "0.18.13",
+ "@esbuild/linux-arm": "0.18.13",
+ "@esbuild/linux-arm64": "0.18.13",
+ "@esbuild/linux-ia32": "0.18.13",
+ "@esbuild/linux-loong64": "0.18.13",
+ "@esbuild/linux-mips64el": "0.18.13",
+ "@esbuild/linux-ppc64": "0.18.13",
+ "@esbuild/linux-riscv64": "0.18.13",
+ "@esbuild/linux-s390x": "0.18.13",
+ "@esbuild/linux-x64": "0.18.13",
+ "@esbuild/netbsd-x64": "0.18.13",
+ "@esbuild/openbsd-x64": "0.18.13",
+ "@esbuild/sunos-x64": "0.18.13",
+ "@esbuild/win32-arm64": "0.18.13",
+ "@esbuild/win32-ia32": "0.18.13",
+ "@esbuild/win32-x64": "0.18.13"
}
},
"node_modules/vscode-oniguruma": {
@@ -19867,16 +20530,16 @@
"version": "4.4.0",
"license": "MIT",
"dependencies": {
- "@emotion/react": "^11.10.6",
- "@mantine/core": "^6.0.14",
- "@mantine/dropzone": "6.0.14",
- "@mantine/form": "^6.0.14",
- "@mantine/hooks": "^6.0.14",
- "@mantine/modals": "^6.0.14",
- "@mantine/notifications": "^6.0.14",
- "@mantine/prism": "^6.0.14",
- "@mantine/tiptap": "^6.0.14",
- "@tabler/icons-react": "^2.22.0",
+ "@emotion/react": "^11.11.1",
+ "@mantine/core": "^6.0.16",
+ "@mantine/dropzone": "6.0.16",
+ "@mantine/form": "^6.0.16",
+ "@mantine/hooks": "^6.0.16",
+ "@mantine/modals": "^6.0.16",
+ "@mantine/notifications": "^6.0.16",
+ "@mantine/prism": "^6.0.16",
+ "@mantine/tiptap": "^6.0.16",
+ "@tabler/icons-react": "^2.25.0",
"@tiptap/extension-code-block-lowlight": "^2.0.3",
"@tiptap/extension-link": "^2.0.3",
"@tiptap/pm": "^2.0.3",
@@ -19886,102 +20549,393 @@
"lowlight": "^2.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "react-icons": "^4.8.0",
- "react-router-dom": "^6.13.0",
+ "react-icons": "^4.10.1",
+ "react-router-dom": "^6.14.1",
"uuid": "^9.0.0",
"zod": "^3.21.4",
"zustand": "^4.3.9"
},
"devDependencies": {
- "@types/react": "^18.0.26",
- "@types/react-dom": "^18.0.9",
+ "@types/react": "^18.2.15",
+ "@types/react-dom": "^18.2.7",
"@types/uuid": "^9.0.2",
- "@typescript-eslint/eslint-plugin": "^5.54.0",
- "@typescript-eslint/parser": "^5.54.0",
- "@vitejs/plugin-react-swc": "^3.0.0",
- "eslint": "^8.35.0",
- "eslint-config-prettier": "^8.6.0",
- "eslint-plugin-prettier": "^4.2.1",
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
+ "@typescript-eslint/parser": "^6.0.0",
+ "@vitejs/plugin-react-swc": "^3.3.2",
+ "eslint": "^8.45.0",
+ "eslint-config-prettier": "^8.8.0",
+ "eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react-hooks": "^4.6.0",
- "eslint-plugin-react-refresh": "^0.4.1",
- "prettier": "^2.8.4",
- "typescript": "^4.9.3",
- "vite": "^4.0.0",
+ "eslint-plugin-react-refresh": "^0.4.3",
+ "prettier": "^3.0.0",
+ "typescript": "^5.1.6",
+ "vite": "^4.4.4",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-pwa": "^0.16.4"
}
},
+ "packages/web/node_modules/@mantine/core": {
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/core/-/core-6.0.16.tgz",
+ "integrity": "sha512-ai7HfWo214JLmf+QNEmFfTaBgxreMpY/ZK7dIDNkFfCmDAWjFxwCSc7flh8NHX2ZJN5uTc82p2i0MLJ/GZ5xrA==",
+ "dependencies": {
+ "@floating-ui/react": "^0.19.1",
+ "@mantine/styles": "6.0.16",
+ "@mantine/utils": "6.0.16",
+ "@radix-ui/react-scroll-area": "1.0.2",
+ "react-remove-scroll": "^2.5.5",
+ "react-textarea-autosize": "8.3.4"
+ },
+ "peerDependencies": {
+ "@mantine/hooks": "6.0.16",
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "packages/web/node_modules/@mantine/dropzone": {
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/dropzone/-/dropzone-6.0.16.tgz",
+ "integrity": "sha512-zVmJFPesI4NyLvjvhM77WwE+AO+ixPq934fjrtCvHTtFRVrbuuUa+tOk6LNPX0grQLOZMb0fnlZXy8KH03ES+w==",
+ "dependencies": {
+ "@mantine/utils": "6.0.16",
+ "react-dropzone": "14.2.3"
+ },
+ "peerDependencies": {
+ "@mantine/core": "6.0.16",
+ "@mantine/hooks": "6.0.16",
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "packages/web/node_modules/@mantine/hooks": {
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-6.0.16.tgz",
+ "integrity": "sha512-DnfMYSTSjYxbQJ80TzKHO5gRXGTIQKxBnRQVc+n4RANTwgWMiwEmxIwqRjbulfLzIhEvplskhqGgElunIAfw7g==",
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
"packages/web/node_modules/@mantine/modals": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/modals/-/modals-6.0.14.tgz",
- "integrity": "sha512-54kOKLfbsp3ox51DYTgMJgBQ3QQ6qaTPZBdABaBPNJcJ1mwIFUQ457+evegwf2r4sKqaT2edTMmumFoa0YXyVg==",
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/modals/-/modals-6.0.16.tgz",
+ "integrity": "sha512-RMDp5jZTrbXgMJN3aPBt82LsIL91xepQDq/zmtLnj2JJnDYTKZarvpOJPvUO/Ewyr6GYJ3iNbcXkV0w0CqCNGg==",
"dependencies": {
- "@mantine/utils": "6.0.14"
+ "@mantine/utils": "6.0.16"
},
"peerDependencies": {
- "@mantine/core": "6.0.14",
- "@mantine/hooks": "6.0.14",
+ "@mantine/core": "6.0.16",
+ "@mantine/hooks": "6.0.16",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"packages/web/node_modules/@mantine/notifications": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-6.0.14.tgz",
- "integrity": "sha512-ElzIVojgAplm9Gtq1qZWR/kjGupttRq8ctTUYmANV8yyXcbpErFr45RlYjDgJs2klQcZid3Pq7hVsjGKLF2MQw==",
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-6.0.16.tgz",
+ "integrity": "sha512-KqlPW51sxgQoJmIC2lEWMVlwPqy04D35iRMkCSget8aNgzk0K5csJppXo6qwMFn2GHKVGXFKJMBUp06IXQbiig==",
"dependencies": {
- "@mantine/utils": "6.0.14",
+ "@mantine/utils": "6.0.16",
"react-transition-group": "4.4.2"
},
"peerDependencies": {
- "@mantine/core": "6.0.14",
- "@mantine/hooks": "6.0.14",
+ "@mantine/core": "6.0.16",
+ "@mantine/hooks": "6.0.16",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"packages/web/node_modules/@mantine/prism": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/prism/-/prism-6.0.14.tgz",
- "integrity": "sha512-w7isUgEintOY3d6m0t31oA+2YvgI78gXBLOCdnGgBiE4kbYYnXUUBo5oTS6Otro1v+pXWZ5rZqPZlDT21jSxSA==",
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/prism/-/prism-6.0.16.tgz",
+ "integrity": "sha512-bWnwRMA7fBfSMpZO2YHIsJ4yt3JTZmPp1nQ62JKpey7rfCJMMuzuCXagCHZthEChZZoQnwmndr4agEzuNIIxmA==",
"dependencies": {
- "@mantine/utils": "6.0.14",
+ "@mantine/utils": "6.0.16",
"prism-react-renderer": "^1.2.1"
},
"peerDependencies": {
- "@mantine/core": "6.0.14",
- "@mantine/hooks": "6.0.14",
+ "@mantine/core": "6.0.16",
+ "@mantine/hooks": "6.0.16",
+ "react": ">=16.8.0",
+ "react-dom": ">=16.8.0"
+ }
+ },
+ "packages/web/node_modules/@mantine/styles": {
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/styles/-/styles-6.0.16.tgz",
+ "integrity": "sha512-0rDE3BzJOKVdPAbnL3XokVWNYgo1z323UgAURdB+WvzwZY7PhblwvrxUDwvvV77qCUENg2vU0LKHqTQD1DDLTg==",
+ "dependencies": {
+ "clsx": "1.1.1",
+ "csstype": "3.0.9"
+ },
+ "peerDependencies": {
+ "@emotion/react": ">=11.9.0",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"packages/web/node_modules/@mantine/tiptap": {
- "version": "6.0.14",
- "resolved": "https://registry.npmjs.org/@mantine/tiptap/-/tiptap-6.0.14.tgz",
- "integrity": "sha512-J7hhgLcCAN4snc7PKlU6ou0/Tvf0bWhexR/vExoNdYLvnCd7JfdDGWL+1O1SaXd2kDgWCmxzLTAiXoS71+l/Pw==",
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/tiptap/-/tiptap-6.0.16.tgz",
+ "integrity": "sha512-W/289lRW7AoNOh4/1WX31K0z+Uk9lJpZyC+m3TuywPSJCINU2ETmj1r+RZl3szf2hLCt5FhSspIAcPgkA2LYQw==",
"dependencies": {
- "@mantine/utils": "6.0.14"
+ "@mantine/utils": "6.0.16"
},
"peerDependencies": {
- "@mantine/core": "6.0.14",
- "@mantine/hooks": "6.0.14",
+ "@mantine/core": "6.0.16",
+ "@mantine/hooks": "6.0.16",
"@tabler/icons-react": ">=2.1.0",
"@tiptap/extension-link": "^2.0.0-beta.202",
"@tiptap/react": "^2.0.0-beta.202",
"react": ">=16.8.0"
}
},
- "packages/web/node_modules/typescript": {
- "version": "4.9.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
- "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "packages/web/node_modules/@mantine/utils": {
+ "version": "6.0.16",
+ "resolved": "https://registry.npmjs.org/@mantine/utils/-/utils-6.0.16.tgz",
+ "integrity": "sha512-UFel9DbifL3zS8pTJlr6GfwGd6464OWXCJdUq0oLydgimbC1VV2PnptBr6FMwIpPVcxouLOtY1cChzwFH95PSA==",
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "packages/web/node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.0.0.tgz",
+ "integrity": "sha512-xuv6ghKGoiq856Bww/yVYnXGsKa588kY3M0XK7uUW/3fJNNULKRfZfSBkMTSpqGG/8ZCXCadfh8G/z/B4aqS/A==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.5.0",
+ "@typescript-eslint/scope-manager": "6.0.0",
+ "@typescript-eslint/type-utils": "6.0.0",
+ "@typescript-eslint/utils": "6.0.0",
+ "@typescript-eslint/visitor-keys": "6.0.0",
+ "debug": "^4.3.4",
+ "grapheme-splitter": "^1.0.4",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.4",
+ "natural-compare": "^1.4.0",
+ "natural-compare-lite": "^1.4.0",
+ "semver": "^7.5.0",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "packages/web/node_modules/@typescript-eslint/parser": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.0.0.tgz",
+ "integrity": "sha512-TNaufYSPrr1U8n+3xN+Yp9g31vQDJqhXzzPSHfQDLcaO4tU+mCfODPxCwf4H530zo7aUBE3QIdxCXamEnG04Tg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "6.0.0",
+ "@typescript-eslint/types": "6.0.0",
+ "@typescript-eslint/typescript-estree": "6.0.0",
+ "@typescript-eslint/visitor-keys": "6.0.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "packages/web/node_modules/@typescript-eslint/scope-manager": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.0.0.tgz",
+ "integrity": "sha512-o4q0KHlgCZTqjuaZ25nw5W57NeykZT9LiMEG4do/ovwvOcPnDO1BI5BQdCsUkjxFyrCL0cSzLjvIMfR9uo7cWg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.0.0",
+ "@typescript-eslint/visitor-keys": "6.0.0"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "packages/web/node_modules/@typescript-eslint/type-utils": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.0.0.tgz",
+ "integrity": "sha512-ah6LJvLgkoZ/pyJ9GAdFkzeuMZ8goV6BH7eC9FPmojrnX9yNCIsfjB+zYcnex28YO3RFvBkV6rMV6WpIqkPvoQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/typescript-estree": "6.0.0",
+ "@typescript-eslint/utils": "6.0.0",
+ "debug": "^4.3.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "packages/web/node_modules/@typescript-eslint/types": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.0.0.tgz",
+ "integrity": "sha512-Zk9KDggyZM6tj0AJWYYKgF0yQyrcnievdhG0g5FqyU3Y2DRxJn4yWY21sJC0QKBckbsdKKjYDV2yVrrEvuTgxg==",
+ "dev": true,
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "packages/web/node_modules/@typescript-eslint/typescript-estree": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.0.0.tgz",
+ "integrity": "sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.0.0",
+ "@typescript-eslint/visitor-keys": "6.0.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "semver": "^7.5.0",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "packages/web/node_modules/@typescript-eslint/utils": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.0.0.tgz",
+ "integrity": "sha512-SOr6l4NB6HE4H/ktz0JVVWNXqCJTOo/mHnvIte1ZhBQ0Cvd04x5uKZa3zT6tiodL06zf5xxdK8COiDvPnQ27JQ==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.3.0",
+ "@types/json-schema": "^7.0.11",
+ "@types/semver": "^7.3.12",
+ "@typescript-eslint/scope-manager": "6.0.0",
+ "@typescript-eslint/types": "6.0.0",
+ "@typescript-eslint/typescript-estree": "6.0.0",
+ "eslint-scope": "^5.1.1",
+ "semver": "^7.5.0"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ }
+ },
+ "packages/web/node_modules/@typescript-eslint/visitor-keys": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.0.0.tgz",
+ "integrity": "sha512-cvJ63l8c0yXdeT5POHpL0Q1cZoRcmRKFCtSjNGJxPkcP571EfZMcNbzWAc7oK3D1dRzm/V5EwtkANTZxqvuuUA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.0.0",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "packages/web/node_modules/csstype": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz",
+ "integrity": "sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw=="
+ },
+ "packages/web/node_modules/eslint-plugin-prettier": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz",
+ "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==",
+ "dev": true,
+ "dependencies": {
+ "prettier-linter-helpers": "^1.0.0",
+ "synckit": "^0.8.5"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/prettier"
+ },
+ "peerDependencies": {
+ "@types/eslint": ">=8.0.0",
+ "eslint": ">=8.0.0",
+ "prettier": ">=3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/eslint": {
+ "optional": true
+ },
+ "eslint-config-prettier": {
+ "optional": true
+ }
+ }
+ },
+ "packages/web/node_modules/prettier": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz",
+ "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==",
"dev": true,
"bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
+ "prettier": "bin/prettier.cjs"
},
"engines": {
- "node": ">=4.2.0"
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
}
}
}
diff --git a/package.json b/package.json
index eed4085..e482355 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,8 @@
"packages/*"
],
"devDependencies": {
- "lerna": "^7.0.2"
+ "lerna": "^7.0.2",
+ "typescript": "^5.1.6"
},
"dependencies": {
"immer": "^10.0.2"
diff --git a/packages/web/package.json b/packages/web/package.json
index 78f3d88..5a2cf35 100644
--- a/packages/web/package.json
+++ b/packages/web/package.json
@@ -51,16 +51,16 @@
"dist"
],
"dependencies": {
- "@emotion/react": "^11.10.6",
- "@mantine/core": "^6.0.14",
- "@mantine/dropzone": "6.0.14",
- "@mantine/form": "^6.0.14",
- "@mantine/hooks": "^6.0.14",
- "@mantine/modals": "^6.0.14",
- "@mantine/notifications": "^6.0.14",
- "@mantine/prism": "^6.0.14",
- "@mantine/tiptap": "^6.0.14",
- "@tabler/icons-react": "^2.22.0",
+ "@emotion/react": "^11.11.1",
+ "@mantine/core": "^6.0.16",
+ "@mantine/dropzone": "6.0.16",
+ "@mantine/form": "^6.0.16",
+ "@mantine/hooks": "^6.0.16",
+ "@mantine/modals": "^6.0.16",
+ "@mantine/notifications": "^6.0.16",
+ "@mantine/prism": "^6.0.16",
+ "@mantine/tiptap": "^6.0.16",
+ "@tabler/icons-react": "^2.25.0",
"@tiptap/extension-code-block-lowlight": "^2.0.3",
"@tiptap/extension-link": "^2.0.3",
"@tiptap/pm": "^2.0.3",
@@ -70,27 +70,27 @@
"lowlight": "^2.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "react-icons": "^4.8.0",
- "react-router-dom": "^6.13.0",
+ "react-icons": "^4.10.1",
+ "react-router-dom": "^6.14.1",
"uuid": "^9.0.0",
"zod": "^3.21.4",
"zustand": "^4.3.9"
},
"devDependencies": {
- "@types/react": "^18.0.26",
- "@types/react-dom": "^18.0.9",
+ "@types/react": "^18.2.15",
+ "@types/react-dom": "^18.2.7",
"@types/uuid": "^9.0.2",
- "@typescript-eslint/eslint-plugin": "^5.54.0",
- "@typescript-eslint/parser": "^5.54.0",
- "@vitejs/plugin-react-swc": "^3.0.0",
- "eslint": "^8.35.0",
- "eslint-config-prettier": "^8.6.0",
- "eslint-plugin-prettier": "^4.2.1",
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
+ "@typescript-eslint/parser": "^6.0.0",
+ "@vitejs/plugin-react-swc": "^3.3.2",
+ "eslint": "^8.45.0",
+ "eslint-config-prettier": "^8.8.0",
+ "eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-react-hooks": "^4.6.0",
- "eslint-plugin-react-refresh": "^0.4.1",
- "prettier": "^2.8.4",
- "typescript": "^4.9.3",
- "vite": "^4.0.0",
+ "eslint-plugin-react-refresh": "^0.4.3",
+ "prettier": "^3.0.0",
+ "typescript": "^5.1.6",
+ "vite": "^4.4.4",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-pwa": "^0.16.4"
}
diff --git a/packages/web/src/changelog/index.ts b/packages/web/src/changelog/index.ts
index 5e74305..15b6432 100644
--- a/packages/web/src/changelog/index.ts
+++ b/packages/web/src/changelog/index.ts
@@ -1,16 +1,19 @@
import { ReactNode } from "react";
import v4_4_0 from "./v4-4-0";
+import v4_4_1 from "./v4-4-1";
export type ChangelogEntrySection = {
label: ReactNode;
items: ReactNode[];
+ description?: ReactNode;
};
export type ChangelogEntry = {
version: string;
date: Date;
sections: ChangelogEntrySection[];
+ description?: ReactNode;
};
// First entry is the latest version
-export const changelog = [v4_4_0];
+export const changelog = [v4_4_1, v4_4_0];
diff --git a/packages/web/src/changelog/v4-4-1.ts b/packages/web/src/changelog/v4-4-1.ts
new file mode 100644
index 0000000..7e05365
--- /dev/null
+++ b/packages/web/src/changelog/v4-4-1.ts
@@ -0,0 +1,21 @@
+import { ChangelogEntry } from ".";
+import { CHANGELOG_SECTION } from "../config/constants";
+
+const v4_4_1: ChangelogEntry = {
+ version: "4.4.1 - Performance Update",
+ date: new Date("july 15 2023"),
+ description:
+ "Although performance was not an issue before, I saw many easy opportunities to improve it. This update contains many small improvements that should make the app feel more responsive and less resource intensive.",
+ sections: [
+ {
+ label: CHANGELOG_SECTION.IMPROVEMENTS,
+ items: [
+ "Further improved state management",
+ "Significantly reduced bundle size by separating dependencies from the main bundle into separate chunks. They will only be loaded when needed.",
+ "Updated all project dependencies",
+ ],
+ },
+ ],
+};
+
+export default v4_4_1;
diff --git a/packages/web/src/components/About.tsx b/packages/web/src/components/About/About.tsx
similarity index 97%
rename from packages/web/src/components/About.tsx
rename to packages/web/src/components/About/About.tsx
index 1c57efa..8efb70e 100644
--- a/packages/web/src/components/About.tsx
+++ b/packages/web/src/components/About/About.tsx
@@ -1,5 +1,5 @@
import { Anchor, Stack, Text } from "@mantine/core";
-import { DISCORD_SERVER_INVITE } from "../config/constants";
+import { DISCORD_SERVER_INVITE } from "../../config/constants";
const About = () => {
return (
diff --git a/packages/web/src/components/About/AboutButton.tsx b/packages/web/src/components/About/AboutButton.tsx
new file mode 100644
index 0000000..659b02e
--- /dev/null
+++ b/packages/web/src/components/About/AboutButton.tsx
@@ -0,0 +1,32 @@
+import { Modal, Text } from "@mantine/core";
+import { useDisclosure } from "@mantine/hooks";
+import { FaRegQuestionCircle } from "react-icons/fa";
+import TippedActionIcon from "../common/TippedActionIcon";
+import About from "./About";
+
+const AboutButton = () => {
+ const [showAbout, { open: openAbout, close: closeAbout }] = useDisclosure();
+
+ return (
+ <>
+
+
+
+ About GPT Turbo Web}
+ >
+
+
+ >
+ );
+};
+
+export default AboutButton;
diff --git a/packages/web/src/components/AddConversation.tsx b/packages/web/src/components/AddConversation.tsx
index 0353175..f82dc4d 100644
--- a/packages/web/src/components/AddConversation.tsx
+++ b/packages/web/src/components/AddConversation.tsx
@@ -6,7 +6,13 @@ import {
Card,
createStyles,
} from "@mantine/core";
-import AddConversationForm from "./AddConversationForm";
+import React from "react";
+import { ConversationFormValues } from "../contexts/ConversationFormContext";
+import { addConversation } from "../store/actions/conversations/addConversation";
+import { setActiveConversation } from "../store/actions/conversations/setActiveConversation";
+import { addPersistedConversationId } from "../store/actions/persistence/addPersistedConversationId";
+import ConversationForm from "./forms/ConversationForm/ConversationForm";
+import { useGetFunction } from "../store/hooks/callableFunctions/useGetFunction";
const useStyles = createStyles((theme) => ({
card: {
@@ -23,6 +29,32 @@ const useStyles = createStyles((theme) => ({
const AddConversation = () => {
const { classes } = useStyles();
+ const getFunction = useGetFunction();
+
+ const onSubmit = React.useCallback(
+ ({
+ save,
+ headers,
+ proxy,
+ functionIds,
+ ...values
+ }: ConversationFormValues) => {
+ const newConversation = addConversation(values, { headers, proxy });
+ setActiveConversation(newConversation.id, true);
+
+ for (const functionId of functionIds) {
+ const callableFunction = getFunction(functionId);
+ if (callableFunction) {
+ newConversation.addFunction(callableFunction);
+ }
+ }
+
+ if (save) {
+ addPersistedConversationId(newConversation.id);
+ }
+ },
+ [getFunction]
+ );
return (
@@ -38,7 +70,7 @@ const AddConversation = () => {
New Conversation
-
+
diff --git a/packages/web/src/components/AddConversationForm.tsx b/packages/web/src/components/AddConversationForm.tsx
deleted file mode 100644
index 624756f..0000000
--- a/packages/web/src/components/AddConversationForm.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from "react";
-import ConversationForm from "./ConversationForm";
-import { ConversationFormValues } from "../contexts/ConversationFormContext";
-import useCallableFunctions from "../hooks/useCallableFunctions";
-import { addConversation } from "../store/actions/conversations/addConversation";
-import { setActiveConversation } from "../store/actions/conversations/setActiveConversation";
-import { addPersistedConversationId } from "../store/actions/persistence/addPersistedConversationId";
-
-const AddConversationForm = () => {
- const { getCallableFunction } = useCallableFunctions();
-
- const onSubmit = React.useCallback(
- ({
- save,
- headers,
- proxy,
- functionIds,
- ...values
- }: ConversationFormValues) => {
- const newConversation = addConversation(values, { headers, proxy });
- setActiveConversation(newConversation.id, true);
-
- for (const functionId of functionIds) {
- const callableFunction = getCallableFunction(functionId);
- newConversation.addFunction(callableFunction);
- }
-
- if (save) {
- addPersistedConversationId(newConversation.id);
- }
- },
- [getCallableFunction]
- );
-
- return ;
-};
-
-export default AddConversationForm;
diff --git a/packages/web/src/components/AppSettings.tsx b/packages/web/src/components/AppSettings/AppSettings.tsx
similarity index 91%
rename from packages/web/src/components/AppSettings.tsx
rename to packages/web/src/components/AppSettings/AppSettings.tsx
index 802ef5a..5637a10 100644
--- a/packages/web/src/components/AppSettings.tsx
+++ b/packages/web/src/components/AppSettings/AppSettings.tsx
@@ -9,8 +9,8 @@ import {
useMantineColorScheme,
} from "@mantine/core";
import AppStorageUsage from "./AppStorageUsage";
-import { useAppStore } from "../store";
-import { toggleShowUsage } from "../store/actions/appSettings/toggleShowUsage";
+import { useAppStore } from "../../store";
+import { toggleShowUsage } from "../../store/actions/appSettings/toggleShowUsage";
import AppSettingsDangerZone from "./AppSettingsDangerZone";
const AppSettings = () => {
diff --git a/packages/web/src/components/AppSettingsDangerZone.tsx b/packages/web/src/components/AppSettings/AppSettingsDangerZone.tsx
similarity index 73%
rename from packages/web/src/components/AppSettingsDangerZone.tsx
rename to packages/web/src/components/AppSettings/AppSettingsDangerZone.tsx
index 92b4e01..965485b 100644
--- a/packages/web/src/components/AppSettingsDangerZone.tsx
+++ b/packages/web/src/components/AppSettings/AppSettingsDangerZone.tsx
@@ -1,12 +1,12 @@
import { Group, SimpleGrid, Stack, Text } from "@mantine/core";
-import { removeAllCallableFunctions } from "../store/actions/callableFunctions/removeAllCallableFunctions";
-import { removeAllConversations } from "../store/actions/conversations/removeAllConversations";
-import InlineConfirmButton from "./InlineConfirmButton";
+import { removeAllCallableFunctions } from "../../store/actions/callableFunctions/removeAllCallableFunctions";
+import { removeAllConversations } from "../../store/actions/conversations/removeAllConversations";
+import InlineConfirmButton from "../common/InlineConfirmButton";
import React from "react";
-import { resetCallableFunctionWarnings } from "../store/actions/callableFunctions/resetCallableFunctionWarnings";
-import { resetDefaultSettings } from "../store/actions/defaultConversationSettings/resetDefaultSettings";
-import { removeAllSavedContexts } from "../store/actions/savedContexts/removeAllSavedContexts";
-import { removeAllSavedPrompts } from "../store/actions/savedPrompts/removeAllSavedPrompts";
+import { resetCallableFunctionWarnings } from "../../store/actions/callableFunctions/resetCallableFunctionWarnings";
+import { resetDefaultSettings } from "../../store/actions/defaultConversationSettings/resetDefaultSettings";
+import { removeAllSavedContexts } from "../../store/actions/savedContexts/removeAllSavedContexts";
+import { removeAllSavedPrompts } from "../../store/actions/savedPrompts/removeAllSavedPrompts";
const AppSettingsDangerZone = () => {
const actions = React.useMemo(
diff --git a/packages/web/src/components/AppStorageUsage.tsx b/packages/web/src/components/AppSettings/AppStorageUsage.tsx
similarity index 98%
rename from packages/web/src/components/AppStorageUsage.tsx
rename to packages/web/src/components/AppSettings/AppStorageUsage.tsx
index aeba139..7b236ea 100644
--- a/packages/web/src/components/AppStorageUsage.tsx
+++ b/packages/web/src/components/AppSettings/AppStorageUsage.tsx
@@ -8,7 +8,7 @@ import {
useMantineTheme,
} from "@mantine/core";
import React from "react";
-import { STORAGE_PERSISTENCE_KEY } from "../config/constants";
+import { STORAGE_PERSISTENCE_KEY } from "../../config/constants";
interface StorageUsage {
label: string;
diff --git a/packages/web/src/components/CallableFunctionCard.tsx b/packages/web/src/components/CallableFunctionCard.tsx
deleted file mode 100644
index 1264024..0000000
--- a/packages/web/src/components/CallableFunctionCard.tsx
+++ /dev/null
@@ -1,215 +0,0 @@
-import {
- ActionIcon,
- Card,
- CardProps,
- Code,
- Group,
- Menu,
- Stack,
- Text,
- Title,
-} from "@mantine/core";
-import React from "react";
-import { CallableFunction } from "gpt-turbo";
-import useCallableFunctions from "../hooks/useCallableFunctions";
-import {
- BiDotsVerticalRounded,
- BiDuplicate,
- BiEdit,
- BiExport,
-} from "react-icons/bi";
-import { useNavigate } from "react-router-dom";
-import { modals } from "@mantine/modals";
-import { BsTrash } from "react-icons/bs";
-import { callableFunctionExportschema } from "../entities/callableFunctionExport";
-import { useAppStore } from "../store";
-import { addCallableFunction } from "../store/actions/callableFunctions/addCallableFunction";
-import { deleteCallableFunction } from "../store/actions/callableFunctions/deleteCallableFunction";
-
-type CallableFunctionCardProps = Omit & {
- fn: CallableFunction;
-};
-
-const CallableFunctionCard = ({
- fn,
- ...cardProps
-}: CallableFunctionCardProps) => {
- const navigate = useNavigate();
- const callableFunctions = useAppStore((state) => state.callableFunctions);
- const { getCallableFunctionDisplayName, getCallableFunctionCode } =
- useCallableFunctions();
-
- const signature = React.useMemo(() => {
- const parameters = [
- ...fn.requiredParameters,
- ...fn.optionalParameters,
- ].map((parameter) => ({
- name: parameter.name,
- type: parameter.type,
- required: fn.requiredParameters.includes(parameter),
- }));
-
- let signature = `${fn.name}(`;
- signature += parameters
- .map(({ name, required, type }) => {
- return `${name}${required ? "" : "?"}: ${type}`;
- })
- .join(", ");
- signature += ")";
- return signature;
- }, [fn.name, fn.optionalParameters, fn.requiredParameters]);
-
- const onEdit = React.useCallback(
- () => navigate(`/functions/edit/${fn.id}`),
- [fn.id, navigate]
- );
-
- const onDuplicate = React.useCallback(() => {
- const displayName = getCallableFunctionDisplayName(fn.id);
-
- const copyDisplayName = (() => {
- let i = 1;
- let copy = `${displayName} (${i})`;
- while (
- callableFunctions.some(
- (fn) => getCallableFunctionDisplayName(fn.id) === copy
- )
- ) {
- copy = `${displayName} (${i++})`;
- }
- return copy;
- })();
-
- const copyName = (() => {
- let i = 1;
- let copy = `${fn.name}${i}`;
- while (callableFunctions.some((fn) => fn.name === copy)) {
- copy = `${fn.name}${i++}`;
- }
- return copy;
- })();
-
- modals.openConfirmModal({
- title: `Duplicate ${displayName}?`,
- centered: true,
- children: (
-
- This will create a new function with the same config and
- code, but the display name and function name will appear as{" "}
-
- {copyDisplayName}
- {" "}
- and{" "}
-
- {copyName}
-
-
- ),
- labels: { confirm: "Duplicate function", cancel: "Cancel" },
- onConfirm: () => {
- addCallableFunction(
- {
- ...fn.toJSON(),
- id: undefined,
- name: copyName,
- },
- copyDisplayName,
- getCallableFunctionCode(fn.id)
- );
- },
- });
- }, [
- callableFunctions,
- fn,
- getCallableFunctionCode,
- getCallableFunctionDisplayName,
- ]);
-
- const onDelete = React.useCallback(() => {
- const displayName = getCallableFunctionDisplayName(fn.id);
- modals.openConfirmModal({
- title: `Delete ${displayName}?`,
- centered: true,
- children: (
-
- Are you sure you want to delete {displayName}? This cannot
- be undone.
-
- ),
- labels: { confirm: "Delete function", cancel: "Cancel" },
- confirmProps: { color: "red" },
- onConfirm: () => {
- deleteCallableFunction(fn.id);
- },
- });
- }, [fn.id, getCallableFunctionDisplayName]);
-
- const onExport = React.useCallback(() => {
- const data = JSON.stringify(
- callableFunctionExportschema.parse({
- callableFunction: fn.toJSON(),
- code: getCallableFunctionCode(fn.id),
- displayName: getCallableFunctionDisplayName(fn.id),
- })
- );
- const blob = new Blob([data], { type: "application/json" });
- const url = URL.createObjectURL(blob);
- const a = document.createElement("a");
- a.href = url;
- a.download = `${fn.id}.json`;
- a.click();
- URL.revokeObjectURL(url);
- }, [fn, getCallableFunctionCode, getCallableFunctionDisplayName]);
-
- return (
-
-
-
-
- {getCallableFunctionDisplayName(fn.id)}
-
-
-
-
-
-
- {fn.description && {fn.description}}
- {signature}
-
-
-
- );
-};
-
-export default CallableFunctionCard;
diff --git a/packages/web/src/components/CallableFunctionCard/CallableFunctionCard.tsx b/packages/web/src/components/CallableFunctionCard/CallableFunctionCard.tsx
new file mode 100644
index 0000000..38f0608
--- /dev/null
+++ b/packages/web/src/components/CallableFunctionCard/CallableFunctionCard.tsx
@@ -0,0 +1,64 @@
+import {
+ Card,
+ CardProps,
+ Code,
+ Group,
+ Stack,
+ Text,
+ Title,
+} from "@mantine/core";
+import React from "react";
+import { CallableFunction } from "gpt-turbo";
+import CallableFunctionCardMenu from "./CallableFunctionCardMenu";
+import { useGetFunctionDisplayName } from "../../store/hooks/callableFunctions/useGetFunctionDisplayName";
+
+type CallableFunctionCardProps = Omit & {
+ fn: CallableFunction;
+};
+
+const CallableFunctionCard = ({
+ fn,
+ ...cardProps
+}: CallableFunctionCardProps) => {
+ const getFunctionDisplayName = useGetFunctionDisplayName();
+ const signature = React.useMemo(() => {
+ const parameters = [
+ ...fn.requiredParameters,
+ ...fn.optionalParameters,
+ ].map((parameter) => ({
+ name: parameter.name,
+ type: parameter.type,
+ required: fn.requiredParameters.includes(parameter),
+ }));
+
+ let signature = `${fn.name}(`;
+ signature += parameters
+ .map(({ name, required, type }) => {
+ return `${name}${required ? "" : "?"}: ${type}`;
+ })
+ .join(", ");
+ signature += ")";
+ return signature;
+ }, [fn.name, fn.optionalParameters, fn.requiredParameters]);
+
+ return (
+
+
+
+
+ {getFunctionDisplayName(fn.id) ?? "[N/A]"}
+
+
+
+
+
+
+ {fn.description && {fn.description}}
+ {signature}
+
+
+
+ );
+};
+
+export default CallableFunctionCard;
diff --git a/packages/web/src/components/CallableFunctionCard/CallableFunctionCardMenu.tsx b/packages/web/src/components/CallableFunctionCard/CallableFunctionCardMenu.tsx
new file mode 100644
index 0000000..a82063d
--- /dev/null
+++ b/packages/web/src/components/CallableFunctionCard/CallableFunctionCardMenu.tsx
@@ -0,0 +1,86 @@
+import { Menu, ActionIcon } from "@mantine/core";
+import React from "react";
+import {
+ BiDotsVerticalRounded,
+ BiEdit,
+ BiDuplicate,
+ BiExport,
+} from "react-icons/bi";
+import { BsTrash } from "react-icons/bs";
+import { useNavigate } from "react-router-dom";
+import { callableFunctionExportschema } from "../../entities/callableFunctionExport";
+import { useAppStore } from "../../store";
+import { deleteCallableFunction } from "../../store/actions/callableFunctions/deleteCallableFunction";
+import { duplicateCallableFunction } from "../../store/actions/callableFunctions/duplicateCallableFunction";
+import { useGetFunctionDisplayName } from "../../store/hooks/callableFunctions/useGetFunctionDisplayName";
+import { useGetFunctionCode } from "../../store/hooks/callableFunctions/useGetFunctionCode";
+
+interface CallableFunctionCardMenuProps {
+ id: string;
+}
+
+const CallableFunctionCardMenu = ({ id }: CallableFunctionCardMenuProps) => {
+ const navigate = useNavigate();
+ const fn = useAppStore((state) =>
+ state.callableFunctions.find((fn) => fn.id === id)
+ );
+ const getFunctionDisplayName = useGetFunctionDisplayName();
+ const getFunctionCode = useGetFunctionCode();
+
+ const onEdit = React.useCallback(() => {
+ if (!fn) return;
+ navigate(`/functions/edit/${fn.id}`);
+ }, [fn, navigate]);
+
+ const onDelete = React.useCallback(() => {
+ if (!fn) return;
+ deleteCallableFunction(fn.id);
+ }, [fn]);
+
+ const onExport = React.useCallback(() => {
+ if (!fn) return;
+ const data = JSON.stringify(
+ callableFunctionExportschema.parse({
+ callableFunction: fn.toJSON(),
+ code: getFunctionCode(fn.id),
+ displayName: getFunctionDisplayName(fn.id) ?? "[N/A]",
+ })
+ );
+ const blob = new Blob([data], { type: "application/json" });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement("a");
+ a.href = url;
+ a.download = `${fn.id}.json`;
+ a.click();
+ URL.revokeObjectURL(url);
+ }, [fn, getFunctionCode, getFunctionDisplayName]);
+
+ return (
+
+ );
+};
+
+export default CallableFunctionCardMenu;
diff --git a/packages/web/src/components/CallableFunctionImport.tsx b/packages/web/src/components/CallableFunctionImport/CallableFunctionImport.tsx
similarity index 93%
rename from packages/web/src/components/CallableFunctionImport.tsx
rename to packages/web/src/components/CallableFunctionImport/CallableFunctionImport.tsx
index 5e31792..236ee4e 100644
--- a/packages/web/src/components/CallableFunctionImport.tsx
+++ b/packages/web/src/components/CallableFunctionImport/CallableFunctionImport.tsx
@@ -1,5 +1,5 @@
import React, { Suspense } from "react";
-import { CallableFunctionExport } from "../entities/callableFunctionExport";
+import { CallableFunctionExport } from "../../entities/callableFunctionExport";
import CallableFunctionImportDropzone from "./CallableFunctionImportDropzone";
import {
Accordion,
@@ -13,10 +13,12 @@ import {
} from "@mantine/core";
import { v4 as uuid } from "uuid";
import { BiX } from "react-icons/bi";
-import TippedActionIcon from "./TippedActionIcon";
-import getFunctionSignature from "../utils/getFunctionSignature";
+import TippedActionIcon from "../common/TippedActionIcon";
+import getFunctionSignature from "../../utils/getFunctionSignature";
-const CodeEditor = React.lazy(() => import("./CodeEditor"));
+const CodeEditor = React.lazy(
+ () => import("../forms/CallableFunctionForm/CodeEditor")
+);
interface CallableFunctionImportProps {
onImport: (fns: CallableFunctionExport[]) => void;
diff --git a/packages/web/src/components/CallableFunctionImportButton.tsx b/packages/web/src/components/CallableFunctionImport/CallableFunctionImportButton.tsx
similarity index 56%
rename from packages/web/src/components/CallableFunctionImportButton.tsx
rename to packages/web/src/components/CallableFunctionImport/CallableFunctionImportButton.tsx
index d820747..ed41818 100644
--- a/packages/web/src/components/CallableFunctionImportButton.tsx
+++ b/packages/web/src/components/CallableFunctionImport/CallableFunctionImportButton.tsx
@@ -2,18 +2,18 @@ import { Button, Modal } from "@mantine/core";
import { BiCheck, BiImport, BiX } from "react-icons/bi";
import { useDisclosure } from "@mantine/hooks";
import CallableFunctionImport from "./CallableFunctionImport";
-import FunctionsImportWarning from "./FunctionsImportWarning";
+import FunctionsImportWarning from "../warnings/FunctionsImportWarning";
import React from "react";
-import { CallableFunctionExport } from "../entities/callableFunctionExport";
-import useCallableFunctions from "../hooks/useCallableFunctions";
+import { CallableFunctionExport } from "../../entities/callableFunctionExport";
import { notifications } from "@mantine/notifications";
-import getErrorInfo from "../utils/getErrorInfo";
-import { useAppStore } from "../store";
-import { addCallableFunction } from "../store/actions/callableFunctions/addCallableFunction";
+import getErrorInfo from "../../utils/getErrorInfo";
+import { addCallableFunction } from "../../store/actions/callableFunctions/addCallableFunction";
+import { useGetUniqueFunctionDisplayName } from "../../store/hooks/callableFunctions/useGetUniqueFunctionDisplayName";
+import { useGetUniqueFunctionName } from "../../store/hooks/callableFunctions/useGetUniqueFunctionName";
const CallableFunctionImportButton = () => {
- const callableFunctions = useAppStore((state) => state.callableFunctions);
- const { getCallableFunctionDisplayName } = useCallableFunctions();
+ const getUniqueFunctionDisplayName = useGetUniqueFunctionDisplayName();
+ const getUniqueFunctionName = useGetUniqueFunctionName();
const [
showImportModal,
{ open: openImportModal, close: closeImportModal },
@@ -21,35 +21,21 @@ const CallableFunctionImportButton = () => {
const onImport = React.useCallback(
(fns: CallableFunctionExport[]) => {
- const usedDisplayNames = callableFunctions.map((fn) =>
- getCallableFunctionDisplayName(fn.id)
- );
- const usedNames = callableFunctions.map((fn) => fn.name);
+ const createdDisplayNames: string[] = [];
+ const createdNames: string[] = [];
for (const fn of fns) {
- const importDisplayName = (() => {
- let i = 1;
- let copy = fn.displayName;
- while (
- usedDisplayNames.some(
- (displayName) => displayName === copy
- )
- ) {
- copy = `${fn.displayName} (${i++})`;
- }
- return copy;
- })();
- usedDisplayNames.push(importDisplayName);
+ const importDisplayName = getUniqueFunctionDisplayName(
+ fn.displayName,
+ createdDisplayNames
+ );
+ createdDisplayNames.push(importDisplayName);
- const importName = (() => {
- let i = 1;
- let copy = fn.callableFunction.name;
- while (usedNames.some((name) => name === copy)) {
- copy = `${fn.callableFunction.name}${i++}`;
- }
- return copy;
- })();
- usedNames.push(importName);
+ const importName = getUniqueFunctionName(
+ fn.callableFunction.name,
+ createdNames
+ );
+ createdNames.push(importName);
try {
addCallableFunction(
@@ -76,7 +62,7 @@ const CallableFunctionImportButton = () => {
closeImportModal();
},
- [callableFunctions, closeImportModal, getCallableFunctionDisplayName]
+ [closeImportModal, getUniqueFunctionDisplayName, getUniqueFunctionName]
);
return (
diff --git a/packages/web/src/components/CallableFunctionImportDropzone.tsx b/packages/web/src/components/CallableFunctionImport/CallableFunctionImportDropzone.tsx
similarity index 86%
rename from packages/web/src/components/CallableFunctionImportDropzone.tsx
rename to packages/web/src/components/CallableFunctionImport/CallableFunctionImportDropzone.tsx
index d9539d3..5c26147 100644
--- a/packages/web/src/components/CallableFunctionImportDropzone.tsx
+++ b/packages/web/src/components/CallableFunctionImport/CallableFunctionImportDropzone.tsx
@@ -5,8 +5,8 @@ import React from "react";
import {
CallableFunctionExport,
callableFunctionExportschema,
-} from "../entities/callableFunctionExport";
-import getErrorInfo from "../utils/getErrorInfo";
+} from "../../entities/callableFunctionExport";
+import getErrorInfo from "../../utils/getErrorInfo";
import { BiX, BiUpload } from "react-icons/bi";
import { BsFiletypeJson } from "react-icons/bs";
@@ -15,11 +15,14 @@ const readImportedFile = (file: File) => {
const reader = new FileReader();
reader.onload = () => {
try {
- resolve(
- callableFunctionExportschema.parse(
- JSON.parse(reader.result as string)
- )
+ const result = callableFunctionExportschema.safeParse(
+ JSON.parse(reader.result as string)
);
+ if (!result.success) {
+ reject(result.error);
+ } else {
+ resolve(result.data);
+ }
} catch (e) {
reject(e);
}
@@ -43,9 +46,9 @@ const CallableFunctionImportDropzone = ({
const handleDrop = React.useCallback(
async (files: File[]) => {
const importedFns = await Promise.all(
- files.map((file) => {
+ files.map(async (file) => {
try {
- return readImportedFile(file);
+ return await readImportedFile(file);
} catch (e) {
notifications.show({
title: "Failed to import function",
diff --git a/packages/web/src/components/Changelog.tsx b/packages/web/src/components/Changelog.tsx
deleted file mode 100644
index 494aded..0000000
--- a/packages/web/src/components/Changelog.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { Box, List, Stack, Text, Timeline, Title } from "@mantine/core";
-import { changelog } from "../changelog";
-
-const dateStr = (date: Date) => {
- return date.toLocaleDateString("en-US", {
- year: "numeric",
- month: "long",
- day: "numeric",
- });
-};
-
-const Changelog = () => {
- return (
-
-
- {changelog.map(({ version, date, sections }, i) => (
-
-
- {dateStr(date)}
-
-
- {sections.map(({ label, items }, j) => (
-
- {label}
-
- {items.map((item, k) => (
-
- {item}
-
- ))}
-
-
- ))}
-
-
- ))}
-
-
- );
-};
-
-export default Changelog;
diff --git a/packages/web/src/components/Changelog/Changelog.tsx b/packages/web/src/components/Changelog/Changelog.tsx
new file mode 100644
index 0000000..e1677be
--- /dev/null
+++ b/packages/web/src/components/Changelog/Changelog.tsx
@@ -0,0 +1,90 @@
+import {
+ Box,
+ Button,
+ Center,
+ List,
+ Stack,
+ Text,
+ Timeline,
+ Title,
+} from "@mantine/core";
+import { changelog } from "../../changelog";
+import { BsGithub } from "react-icons/bs";
+
+const dateStr = (date: Date) => {
+ return date.toLocaleDateString("en-US", {
+ year: "numeric",
+ month: "long",
+ day: "numeric",
+ });
+};
+
+const Changelog = () => {
+ return (
+
+
+ {changelog.map(
+ ({ version, date, sections, description }, i) => (
+
+
+ {dateStr(date)}
+
+ {description && (
+
+ {description}
+
+ )}
+
+ {sections.map(
+ ({ label, items, description }, j) => (
+
+ {label}
+ {description && (
+
+ {description}
+
+ )}
+
+ {items.map((item, k) => (
+
+ {item}
+
+ ))}
+
+
+ )
+ )}
+
+
+ )
+ )}
+
+ Changes before this point were not recorded. Please refer to
+ the repository's commit history if you really need to know!
+
+ }
+ color="dark"
+ >
+ View older changes on GitHub
+
+
+
+
+
+ );
+};
+
+export default Changelog;
diff --git a/packages/web/src/components/ChangelogButton.tsx b/packages/web/src/components/Changelog/ChangelogButton.tsx
similarity index 87%
rename from packages/web/src/components/ChangelogButton.tsx
rename to packages/web/src/components/Changelog/ChangelogButton.tsx
index 7359f13..33c3993 100644
--- a/packages/web/src/components/ChangelogButton.tsx
+++ b/packages/web/src/components/Changelog/ChangelogButton.tsx
@@ -2,10 +2,10 @@ import { Modal, ScrollArea, Center, Loader, Text } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import React, { Suspense } from "react";
import { BiCodeAlt } from "react-icons/bi";
-import TippedActionIcon from "./TippedActionIcon";
-import { useAppStore } from "../store";
-import { changelog } from "../changelog";
-import { setLastChangelog } from "../store/actions/appSettings/setLastChangelog";
+import TippedActionIcon from "../common/TippedActionIcon";
+import { useAppStore } from "../../store";
+import { changelog } from "../../changelog";
+import { setLastChangelog } from "../../store/actions/appSettings/setLastChangelog";
const Changelog = React.lazy(() => import("./Changelog"));
diff --git a/packages/web/src/components/ConversationNavbar.tsx b/packages/web/src/components/ConversationNavbar.tsx
deleted file mode 100644
index d78fcbc..0000000
--- a/packages/web/src/components/ConversationNavbar.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-import {
- Anchor,
- Burger,
- Divider,
- Group,
- MediaQuery,
- Modal,
- Navbar,
- Stack,
- Text,
- createStyles,
- useMantineTheme,
-} from "@mantine/core";
-import useConversationManager from "../hooks/useConversationManager";
-import { BiCog, BiPlus } from "react-icons/bi";
-import TippedActionIcon from "./TippedActionIcon";
-import Usage from "./Usage";
-import { useDisclosure, useMediaQuery } from "@mantine/hooks";
-import { BsDiscord, BsGithub } from "react-icons/bs";
-import NavbarConversations from "./NavbarConversations";
-import { AiOutlineFunction } from "react-icons/ai";
-import { Link } from "react-router-dom";
-import SettingsFormModal from "./SettingsFormModal";
-import { FaRegQuestionCircle } from "react-icons/fa";
-import About from "./About";
-import { DISCORD_SERVER_INVITE } from "../config/constants";
-import { useAppStore } from "../store";
-import { setActiveConversation } from "../store/actions/conversations/setActiveConversation";
-import ChangelogButton from "./ChangelogButton";
-
-const useStyles = createStyles(() => ({
- burger: {
- position: "absolute",
- top: 0,
- right: 0,
- zIndex: 101,
- },
-}));
-
-const AppNavbar = () => {
- const showUsage = useAppStore((state) => state.showUsage);
- const { activeConversation } = useConversationManager();
- const { classes } = useStyles();
- const theme = useMantineTheme();
- const [navbarOpened, { close: closeNavbar, toggle: toggleNavbar }] =
- useDisclosure();
- const [settingsOpened, { open: openSettings, close: closeSettings }] =
- useDisclosure();
- const [showAbout, { open: openAbout, close: closeAbout }] = useDisclosure();
-
- const isSm = useMediaQuery(`(max-width: ${theme.breakpoints.md})`);
-
- return (
- <>
-
-
-
-
-
-
-
-
-
- {activeConversation && (
- {
- setActiveConversation(null);
- closeNavbar();
- }}
- tip="Add conversation"
- >
-
-
- )}
-
-
-
-
-
-
-
-
-
- {activeConversation && showUsage && (
-
-
-
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- GPT Turbo Web v{APP_VERSION} by{" "}
-
- Tristan Chin
-
-
-
-
-
-
- About GPT Turbo Web}
- >
-
-
- >
- );
-};
-
-export default AppNavbar;
diff --git a/packages/web/src/components/ConversationNavbar/ConversationNavbar.tsx b/packages/web/src/components/ConversationNavbar/ConversationNavbar.tsx
new file mode 100644
index 0000000..2d8ae22
--- /dev/null
+++ b/packages/web/src/components/ConversationNavbar/ConversationNavbar.tsx
@@ -0,0 +1,53 @@
+import { Divider, Navbar, useMantineTheme } from "@mantine/core";
+import Usage from "../Usage/Usage";
+import { useMediaQuery } from "@mantine/hooks";
+import NavbarConversations from "./NavbarConversations/NavbarConversations";
+import { useAppStore } from "../../store";
+import ConversationNavbarHeader from "./ConversationNavbarHeader/ConversationNavbarHeader";
+import { useActiveConversation } from "../../store/hooks/conversations/useActiveConversation";
+import useConversationNavbar from "../../contexts/hooks/useConversationNavbar";
+import ConversationNavbarBurger from "./ConversationNavbarBurger";
+import ConversationNavbarFooter from "./ConversationNavbarFooter/ConversationNavbarFooter";
+
+const ConversationNavbar = () => {
+ const activeConversation = useActiveConversation();
+ const { navbarOpened, closeNavbar } = useConversationNavbar();
+ const showUsage = useAppStore((state) => state.showUsage);
+ const theme = useMantineTheme();
+
+ const isSm = useMediaQuery(`(max-width: ${theme.breakpoints.md})`);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+ {activeConversation && showUsage && (
+
+ <>
+
+
+ >
+
+ )}
+
+
+
+
+
+ >
+ );
+};
+
+export default ConversationNavbar;
diff --git a/packages/web/src/components/ConversationNavbar/ConversationNavbarBurger.tsx b/packages/web/src/components/ConversationNavbar/ConversationNavbarBurger.tsx
new file mode 100644
index 0000000..f046857
--- /dev/null
+++ b/packages/web/src/components/ConversationNavbar/ConversationNavbarBurger.tsx
@@ -0,0 +1,35 @@
+import { MediaQuery, Burger, createStyles } from "@mantine/core";
+import useConversationNavbar from "../../contexts/hooks/useConversationNavbar";
+
+const useStyles = createStyles(() => ({
+ burger: {
+ position: "absolute",
+ top: 0,
+ right: 0,
+ zIndex: 101,
+ },
+}));
+
+const ConversationNavbarBurger = () => {
+ const { classes } = useStyles();
+ const { navbarOpened, toggleNavbar } = useConversationNavbar();
+ return (
+
+
+
+ );
+};
+
+export default ConversationNavbarBurger;
diff --git a/packages/web/src/components/ConversationNavbar/ConversationNavbarFooter/ConversationNavbarFooter.tsx b/packages/web/src/components/ConversationNavbar/ConversationNavbarFooter/ConversationNavbarFooter.tsx
new file mode 100644
index 0000000..06b8532
--- /dev/null
+++ b/packages/web/src/components/ConversationNavbar/ConversationNavbarFooter/ConversationNavbarFooter.tsx
@@ -0,0 +1,42 @@
+import { Stack, Group, Anchor, Text } from "@mantine/core";
+import { BsGithub, BsDiscord } from "react-icons/bs";
+import { DISCORD_SERVER_INVITE } from "../../../config/constants";
+import AboutButton from "../../About/AboutButton";
+import ChangelogButton from "../../Changelog/ChangelogButton";
+import TippedActionIcon from "../../common/TippedActionIcon";
+
+const ConversationNavbarFooter = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ GPT Turbo Web v{APP_VERSION} by{" "}
+
+ Tristan Chin
+
+
+
+ );
+};
+
+export default ConversationNavbarFooter;
diff --git a/packages/web/src/components/ConversationNavbar/ConversationNavbarHeader/ConversationNavbarHeader.tsx b/packages/web/src/components/ConversationNavbar/ConversationNavbarHeader/ConversationNavbarHeader.tsx
new file mode 100644
index 0000000..ded6b33
--- /dev/null
+++ b/packages/web/src/components/ConversationNavbar/ConversationNavbarHeader/ConversationNavbarHeader.tsx
@@ -0,0 +1,42 @@
+import { Group } from "@mantine/core";
+import { AiOutlineFunction } from "react-icons/ai";
+import { BiPlus } from "react-icons/bi";
+import { Link } from "react-router-dom";
+import { setActiveConversation } from "../../../store/actions/conversations/setActiveConversation";
+import TippedActionIcon from "../../common/TippedActionIcon";
+import SettingsButton from "./SettingsButton";
+import { useActiveConversation } from "../../../store/hooks/conversations/useActiveConversation";
+import useConversationNavbar from "../../../contexts/hooks/useConversationNavbar";
+
+const ConversationNavbarHeader = () => {
+ const activeConversation = useActiveConversation();
+ const { closeNavbar } = useConversationNavbar();
+
+ return (
+
+
+ {activeConversation && (
+ {
+ setActiveConversation(null);
+ closeNavbar();
+ }}
+ tip="Add conversation"
+ >
+
+
+ )}
+
+
+
+
+ );
+};
+
+export default ConversationNavbarHeader;
diff --git a/packages/web/src/components/ConversationNavbar/ConversationNavbarHeader/SettingsButton.tsx b/packages/web/src/components/ConversationNavbar/ConversationNavbarHeader/SettingsButton.tsx
new file mode 100644
index 0000000..766244d
--- /dev/null
+++ b/packages/web/src/components/ConversationNavbar/ConversationNavbarHeader/SettingsButton.tsx
@@ -0,0 +1,27 @@
+import { useDisclosure } from "@mantine/hooks";
+import { BiCog } from "react-icons/bi";
+import TippedActionIcon from "../../common/TippedActionIcon";
+import SettingsFormModal from "../../modals/SettingsFormModal";
+
+const SettingsButton = () => {
+ const [settingsOpened, { open: openSettings, close: closeSettings }] =
+ useDisclosure();
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+};
+
+export default SettingsButton;
diff --git a/packages/web/src/components/NavbarConverationInfoIcon.tsx b/packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConverationInfoIcon.tsx
similarity index 100%
rename from packages/web/src/components/NavbarConverationInfoIcon.tsx
rename to packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConverationInfoIcon.tsx
diff --git a/packages/web/src/components/NavbarConversation.tsx b/packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConversation.tsx
similarity index 86%
rename from packages/web/src/components/NavbarConversation.tsx
rename to packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConversation.tsx
index 848c0d3..a27d0a0 100644
--- a/packages/web/src/components/NavbarConversation.tsx
+++ b/packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConversation.tsx
@@ -7,15 +7,17 @@ import {
createStyles,
} from "@mantine/core";
import { Conversation } from "gpt-turbo";
-import useConversationManager from "../hooks/useConversationManager";
import { BiCheck, BiPencil, BiTrash, BiX } from "react-icons/bi";
import React from "react";
import { useForm } from "@mantine/form";
-import TippedActionIcon from "./TippedActionIcon";
+import TippedActionIcon from "../../common/TippedActionIcon";
import NavbarConversationInfo from "./NavbarConversationInfo";
-import { setConversationName } from "../store/actions/conversations/setConversationName";
-import { removeConversation } from "../store/actions/conversations/removeConversation";
-import { setActiveConversation } from "../store/actions/conversations/setActiveConversation";
+import { setConversationName } from "../../../store/actions/conversations/setConversationName";
+import { removeConversation } from "../../../store/actions/conversations/removeConversation";
+import { setActiveConversation } from "../../../store/actions/conversations/setActiveConversation";
+import { useActiveConversation } from "../../../store/hooks/conversations/useActiveConversation";
+import { useGetConversationName } from "../../../store/hooks/conversations/useGetConversationName";
+import { DEFAULT_CONVERSATION_NAME } from "../../../config/constants";
interface NavbarConversationProps {
conversation: Conversation;
@@ -68,8 +70,8 @@ const NavbarConversation = ({
conversation,
onClick,
}: NavbarConversationProps) => {
- const { activeConversation, getConversationName } =
- useConversationManager();
+ const activeConversation = useActiveConversation();
+ const getConversationName = useGetConversationName();
const [isDeleting, setIsDeleting] = React.useState(false);
const [isEditing, setIsEditing] = React.useState(false);
const isActive = conversation.id === activeConversation?.id;
@@ -78,12 +80,16 @@ const NavbarConversation = ({
const editFormRef = React.useRef(null);
const editForm = useForm({
initialValues: {
- name: getConversationName(conversation.id),
+ name:
+ getConversationName(conversation.id) ??
+ DEFAULT_CONVERSATION_NAME,
},
});
const name = React.useMemo(() => {
- return getConversationName(conversation.id);
+ return (
+ getConversationName(conversation.id) ?? DEFAULT_CONVERSATION_NAME
+ );
}, [conversation.id, getConversationName]);
const onEdit = editForm.onSubmit((values) => {
diff --git a/packages/web/src/components/NavbarConversationInfo.tsx b/packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConversationInfo.tsx
similarity index 98%
rename from packages/web/src/components/NavbarConversationInfo.tsx
rename to packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConversationInfo.tsx
index de427c2..673d2fd 100644
--- a/packages/web/src/components/NavbarConversationInfo.tsx
+++ b/packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConversationInfo.tsx
@@ -17,7 +17,7 @@ import {
} from "react-icons/bs";
import { TbCircleDashed } from "react-icons/tb";
import NavbarConverationInfoIcon from "./NavbarConverationInfoIcon";
-import { useAppStore } from "../store";
+import { useAppStore } from "../../../store";
interface NavbarConversationInfoProps {
conversation: Conversation;
diff --git a/packages/web/src/components/NavbarConversations.tsx b/packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConversations.tsx
similarity index 86%
rename from packages/web/src/components/NavbarConversations.tsx
rename to packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConversations.tsx
index e68064e..0337b9e 100644
--- a/packages/web/src/components/NavbarConversations.tsx
+++ b/packages/web/src/components/ConversationNavbar/NavbarConversations/NavbarConversations.tsx
@@ -7,13 +7,13 @@ import {
createStyles,
} from "@mantine/core";
import NavbarConversation from "./NavbarConversation";
-import useConversationManager from "../hooks/useConversationManager";
import React from "react";
-import TippedActionIcon from "./TippedActionIcon";
+import TippedActionIcon from "../../common/TippedActionIcon";
import { BiTrash } from "react-icons/bi";
import { useTimeout } from "@mantine/hooks";
-import { useAppStore } from "../store";
-import { removeConversation } from "../store/actions/conversations/removeConversation";
+import { useAppStore } from "../../../store";
+import { removeConversation } from "../../../store/actions/conversations/removeConversation";
+import { useGetConversationLastEdit } from "../../../store/hooks/conversations/useGetConversationLastEdit";
interface NavbarConversationsProps {
onConversationSelect?: () => void;
@@ -77,7 +77,7 @@ const NavbarConversations = ({
}: NavbarConversationsProps) => {
const { classes } = useStyles();
const conversations = useAppStore((state) => state.conversations);
- const { getConversationLastEdit } = useConversationManager();
+ const getConversationLastEdit = useGetConversationLastEdit();
const [deleteConfirmation, setdeleteConfirmation] = React.useState<
string | null
>(null);
@@ -88,17 +88,20 @@ const NavbarConversations = ({
return conversations
.map((c) => ({
conversation: c,
- lastEdit: getConversationLastEdit(c.id),
+ lastEdit: getConversationLastEdit(c.id) ?? Date.now(),
}))
.sort((a, b) => b.lastEdit - a.lastEdit)
- .reduce((acc, { conversation, lastEdit }) => {
- const relativeDate = getRelativeDate(lastEdit);
- if (!acc[relativeDate]) {
- acc[relativeDate] = [];
- }
- acc[relativeDate].push(conversation);
- return acc;
- }, {} as Record);
+ .reduce(
+ (acc, { conversation, lastEdit }) => {
+ const relativeDate = getRelativeDate(lastEdit);
+ if (!acc[relativeDate]) {
+ acc[relativeDate] = [];
+ }
+ acc[relativeDate].push(conversation);
+ return acc;
+ },
+ {} as Record
+ );
}, [conversations, getConversationLastEdit]);
const makeDeleteGroup = React.useCallback(
diff --git a/packages/web/src/components/ConversationPageShell.tsx b/packages/web/src/components/ConversationPageShell.tsx
index 371689e..cc34a52 100644
--- a/packages/web/src/components/ConversationPageShell.tsx
+++ b/packages/web/src/components/ConversationPageShell.tsx
@@ -1,6 +1,7 @@
import { AppShell, useMantineTheme } from "@mantine/core";
-import ConversationNavbar from "./ConversationNavbar";
+import ConversationNavbar from "./ConversationNavbar/ConversationNavbar";
import { useMediaQuery } from "@mantine/hooks";
+import ConversationNavbarProvider from "../contexts/providers/ConversationNavbarProvider";
interface ConversationPageShellProps {
children?: React.ReactNode;
@@ -11,19 +12,21 @@ const ConversationPageShell = ({ children }: ConversationPageShellProps) => {
const isSm = useMediaQuery(`(max-width: ${theme.breakpoints.md})`);
return (
- }
- sx={(theme) => ({
- backgroundColor:
- theme.colorScheme === "dark"
- ? theme.colors.dark[8]
- : theme.colors.gray[1],
- })}
- >
- {children}
-
+
+ }
+ sx={(theme) => ({
+ backgroundColor:
+ theme.colorScheme === "dark"
+ ? theme.colors.dark[8]
+ : theme.colors.gray[1],
+ })}
+ >
+ {children}
+
+
);
};
diff --git a/packages/web/src/components/CodeBlock.tsx b/packages/web/src/components/Messages/CodeBlock.tsx
similarity index 97%
rename from packages/web/src/components/CodeBlock.tsx
rename to packages/web/src/components/Messages/CodeBlock.tsx
index 9910295..43ea67f 100644
--- a/packages/web/src/components/CodeBlock.tsx
+++ b/packages/web/src/components/Messages/CodeBlock.tsx
@@ -9,7 +9,7 @@ import {
import { Prism } from "@mantine/prism";
import { BiCheck } from "react-icons/bi";
import { RxClipboard } from "react-icons/rx";
-import { CodeLanguage } from "../utils/types";
+import { CodeLanguage } from "../../utils/types";
const CodeBlock = ({
language,
diff --git a/packages/web/src/components/Message.tsx b/packages/web/src/components/Messages/Message.tsx
similarity index 95%
rename from packages/web/src/components/Message.tsx
rename to packages/web/src/components/Messages/Message.tsx
index 1af10f0..3ed831a 100644
--- a/packages/web/src/components/Message.tsx
+++ b/packages/web/src/components/Messages/Message.tsx
@@ -23,16 +23,16 @@ import {
} from "react-icons/bi";
import { AiOutlineFunction } from "react-icons/ai";
import React from "react";
-import TippedActionIcon from "./TippedActionIcon";
+import TippedActionIcon from "../common/TippedActionIcon";
import { useForm } from "@mantine/form";
-import useConversationManager from "../hooks/useConversationManager";
import { notifications } from "@mantine/notifications";
import CodeBlock from "./CodeBlock";
import { useDisclosure, useMediaQuery } from "@mantine/hooks";
-import SavePromptModalBody from "./SavePromptModalBody";
-import { CODE_LANGUAGES } from "../config/constants";
-import { CodeLanguage } from "../utils/types";
-import getErrorInfo from "../utils/getErrorInfo";
+import SavePromptModalBody from "../modals/SavePromptModalBody";
+import { CODE_LANGUAGES } from "../../config/constants";
+import { CodeLanguage } from "../../utils/types";
+import getErrorInfo from "../../utils/getErrorInfo";
+import { useActiveConversation } from "../../store/hooks/conversations/useActiveConversation";
interface MessageProps {
message: Message;
@@ -56,7 +56,7 @@ const useStyles = createStyles((theme) => ({
}));
const MessageComponent = ({ message }: MessageProps) => {
- const { activeConversation: conversation } = useConversationManager();
+ const conversation = useActiveConversation();
const { classes } = useStyles();
const [isEditing, setIsEditing] = React.useState(false);
const form = useForm({
diff --git a/packages/web/src/components/Messages.tsx b/packages/web/src/components/Messages/Messages.tsx
similarity index 94%
rename from packages/web/src/components/Messages.tsx
rename to packages/web/src/components/Messages/Messages.tsx
index 52cbb0f..f6941b3 100644
--- a/packages/web/src/components/Messages.tsx
+++ b/packages/web/src/components/Messages/Messages.tsx
@@ -5,12 +5,12 @@ import {
createStyles,
useMantineTheme,
} from "@mantine/core";
-import useConversationManager from "../hooks/useConversationManager";
import Message from "./Message";
import React from "react";
import { useMediaQuery } from "@mantine/hooks";
import { CallableFunction, FunctionCallMessage } from "gpt-turbo";
-import useCallableFunctions from "../hooks/useCallableFunctions";
+import { useActiveConversation } from "../../store/hooks/conversations/useActiveConversation";
+import { useCallFunction } from "../../store/hooks/callableFunctions/useCallFunction";
const useStyles = createStyles(() => ({
scrollArea: {
@@ -21,11 +21,11 @@ const useStyles = createStyles(() => ({
}));
const Messages = () => {
- const { activeConversation: conversation } = useConversationManager();
+ const conversation = useActiveConversation();
const [messages, setMessages] = React.useState(
conversation?.getMessages() ?? []
);
- const { callFunction } = useCallableFunctions();
+ const callFunction = useCallFunction();
const viewport = React.useRef(null);
const [isSticky, setIsSticky] = React.useState(true);
const { classes } = useStyles();
diff --git a/packages/web/src/components/NavbarConversations/NavbarConversation.tsx b/packages/web/src/components/NavbarConversations/NavbarConversation.tsx
new file mode 100644
index 0000000..fd7dbb6
--- /dev/null
+++ b/packages/web/src/components/NavbarConversations/NavbarConversation.tsx
@@ -0,0 +1,232 @@
+import {
+ Anchor,
+ Group,
+ Stack,
+ Text,
+ TextInput,
+ createStyles,
+} from "@mantine/core";
+import { Conversation } from "gpt-turbo";
+import { BiCheck, BiPencil, BiTrash, BiX } from "react-icons/bi";
+import React from "react";
+import { useForm } from "@mantine/form";
+import TippedActionIcon from "../common/TippedActionIcon";
+import { setConversationName } from "../../store/actions/conversations/setConversationName";
+import { removeConversation } from "../../store/actions/conversations/removeConversation";
+import { setActiveConversation } from "../../store/actions/conversations/setActiveConversation";
+import NavbarConversationInfo from "../ConversationNavbar/NavbarConversations/NavbarConversationInfo";
+import { useActiveConversation } from "../../store/hooks/conversations/useActiveConversation";
+import { useGetConversationName } from "../../store/hooks/conversations/useGetConversationName";
+import { DEFAULT_CONVERSATION_NAME } from "../../config/constants";
+
+interface NavbarConversationProps {
+ conversation: Conversation;
+ onClick?: () => void;
+}
+
+const useStyles = createStyles((theme, { isActive }: { isActive: boolean }) => {
+ const dark = theme.colorScheme === "dark";
+ let backgroundColor: string | undefined;
+ let hoverBackgroundColor: string | undefined;
+ let color: string | undefined;
+
+ if (dark && isActive) {
+ backgroundColor = theme.colors.blue[7];
+ hoverBackgroundColor = theme.colors.blue[8];
+ color = theme.white;
+ } else if (dark && !isActive) {
+ backgroundColor = undefined;
+ hoverBackgroundColor = theme.colors.dark[6];
+ color = theme.white;
+ } else if (isActive) {
+ backgroundColor = theme.colors.blue[1];
+ hoverBackgroundColor = theme.colors.blue[2];
+ color = theme.colors.blue[7];
+ } else {
+ backgroundColor = undefined;
+ hoverBackgroundColor = theme.colors.gray[1];
+ color = theme.colors.gray[8];
+ }
+
+ return {
+ root: {
+ display: "flex",
+ alignItems: "center",
+ textDecoration: "none",
+ fontWeight: 600,
+ borderRadius: theme.radius.sm,
+ backgroundColor,
+ color,
+
+ "&:hover": {
+ textDecoration: "none",
+ backgroundColor: hoverBackgroundColor,
+ },
+ },
+ };
+});
+
+const NavbarConversation = ({
+ conversation,
+ onClick,
+}: NavbarConversationProps) => {
+ const activeConversation = useActiveConversation();
+ const getConversationName = useGetConversationName();
+ const [isDeleting, setIsDeleting] = React.useState(false);
+ const [isEditing, setIsEditing] = React.useState(false);
+ const isActive = conversation.id === activeConversation?.id;
+ const { classes } = useStyles({ isActive });
+
+ const editFormRef = React.useRef(null);
+ const editForm = useForm({
+ initialValues: {
+ name:
+ getConversationName(conversation.id) ??
+ DEFAULT_CONVERSATION_NAME,
+ },
+ });
+
+ const name = React.useMemo(() => {
+ return (
+ getConversationName(conversation.id) ?? DEFAULT_CONVERSATION_NAME
+ );
+ }, [conversation.id, getConversationName]);
+
+ const onEdit = editForm.onSubmit((values) => {
+ if (values.name && values.name !== name) {
+ setConversationName(conversation.id, values.name);
+ }
+ setIsEditing(false);
+ });
+
+ const onDelete = React.useCallback(() => {
+ removeConversation(conversation.id);
+ setIsDeleting(false);
+ }, [conversation.id]);
+
+ const onCancel = React.useCallback(() => {
+ setIsDeleting(false);
+ setIsEditing(false);
+ }, []);
+
+ React.useEffect(() => {
+ if (!isActive) {
+ setIsDeleting(false);
+ setIsEditing(false);
+ }
+ }, [isActive]);
+
+ const CancelAction = React.useMemo(
+ () => (
+ {
+ e.stopPropagation();
+ onCancel();
+ }}
+ >
+
+
+ ),
+ [onCancel]
+ );
+
+ const Actions = React.useMemo(() => {
+ if (isDeleting) {
+ return (
+ <>
+ {
+ e.stopPropagation();
+ onDelete();
+ }}
+ >
+
+
+ {CancelAction}
+ >
+ );
+ }
+
+ if (isEditing) {
+ return (
+ <>
+ {
+ e.stopPropagation();
+ editFormRef.current?.requestSubmit();
+ }}
+ >
+
+
+ {CancelAction}
+ >
+ );
+ }
+
+ return (
+ <>
+ {
+ e.stopPropagation();
+ setIsEditing(true);
+ }}
+ >
+
+
+ {
+ e.stopPropagation();
+ setIsDeleting(true);
+ }}
+ >
+
+
+ >
+ );
+ }, [CancelAction, isDeleting, isEditing, onDelete]);
+
+ return (
+ {
+ if (isEditing) return;
+ setActiveConversation(conversation.id);
+ onClick?.();
+ }}
+ >
+
+
+ {isEditing ? (
+
+ ) : (
+
+ {name}
+
+ )}
+ {!isEditing && (
+
+ )}
+
+ {isActive && (
+
+ {Actions}
+
+ )}
+
+
+ );
+};
+
+export default NavbarConversation;
diff --git a/packages/web/src/components/Usage.tsx b/packages/web/src/components/Usage/Usage.tsx
similarity index 81%
rename from packages/web/src/components/Usage.tsx
rename to packages/web/src/components/Usage/Usage.tsx
index 535147a..a0db6b8 100644
--- a/packages/web/src/components/Usage.tsx
+++ b/packages/web/src/components/Usage/Usage.tsx
@@ -1,15 +1,16 @@
import { Stack, Text, Title } from "@mantine/core";
import { Conversation } from "gpt-turbo";
-import useConversationManager from "../hooks/useConversationManager";
import UsageMetric from "./UsageMetric";
-import getPriceString from "../utils/getPriceString";
+import getPriceString from "../../utils/getPriceString";
+import { useGetConversationName } from "../../store/hooks/conversations/useGetConversationName";
+import { DEFAULT_CONVERSATION_NAME } from "../../config/constants";
interface UsageProps {
conversation: Conversation;
}
const Usage = ({ conversation }: UsageProps) => {
- const { getConversationName } = useConversationManager();
+ const getConversationName = useGetConversationName();
const metrics: {
label: React.ReactNode;
@@ -45,7 +46,8 @@ const Usage = ({ conversation }: UsageProps) => {
Usage
- {getConversationName(conversation.id)}
+ {getConversationName(conversation.id) ??
+ DEFAULT_CONVERSATION_NAME}
{metrics.map((metric, i) => (
diff --git a/packages/web/src/components/UsageMetric.tsx b/packages/web/src/components/Usage/UsageMetric.tsx
similarity index 100%
rename from packages/web/src/components/UsageMetric.tsx
rename to packages/web/src/components/Usage/UsageMetric.tsx
diff --git a/packages/web/src/components/ContentLoader.tsx b/packages/web/src/components/common/ContentLoader.tsx
similarity index 100%
rename from packages/web/src/components/ContentLoader.tsx
rename to packages/web/src/components/common/ContentLoader.tsx
diff --git a/packages/web/src/components/InlineConfirmButton.tsx b/packages/web/src/components/common/InlineConfirmButton.tsx
similarity index 100%
rename from packages/web/src/components/InlineConfirmButton.tsx
rename to packages/web/src/components/common/InlineConfirmButton.tsx
diff --git a/packages/web/src/components/TippedActionIcon.tsx b/packages/web/src/components/common/TippedActionIcon.tsx
similarity index 100%
rename from packages/web/src/components/TippedActionIcon.tsx
rename to packages/web/src/components/common/TippedActionIcon.tsx
diff --git a/packages/web/src/components/AppCatcher.tsx b/packages/web/src/components/error-handling/AppCatcher.tsx
similarity index 100%
rename from packages/web/src/components/AppCatcher.tsx
rename to packages/web/src/components/error-handling/AppCatcher.tsx
diff --git a/packages/web/src/components/StorageLoadError.tsx b/packages/web/src/components/error-handling/StorageLoadError.tsx
similarity index 96%
rename from packages/web/src/components/StorageLoadError.tsx
rename to packages/web/src/components/error-handling/StorageLoadError.tsx
index 166b196..2374fa3 100644
--- a/packages/web/src/components/StorageLoadError.tsx
+++ b/packages/web/src/components/error-handling/StorageLoadError.tsx
@@ -8,11 +8,11 @@ import {
Textarea,
} from "@mantine/core";
import React from "react";
-import getErrorInfo from "../utils/getErrorInfo";
-import { STORAGE_PERSISTENCE_KEY } from "../config/constants";
+import getErrorInfo from "../../utils/getErrorInfo";
+import { STORAGE_PERSISTENCE_KEY } from "../../config/constants";
import { BiBug } from "react-icons/bi";
import { BsFire } from "react-icons/bs";
-import { storeVersion } from "../store/persist/migrations";
+import { storeVersion } from "../../store/persist/migrations";
interface StorageLoadErrorProps {
isMigrationError: boolean;
diff --git a/packages/web/src/components/CallableFunctionForm.tsx b/packages/web/src/components/forms/CallableFunctionForm/CallableFunctionForm.tsx
similarity index 69%
rename from packages/web/src/components/CallableFunctionForm.tsx
rename to packages/web/src/components/forms/CallableFunctionForm/CallableFunctionForm.tsx
index d04a809..7d95103 100644
--- a/packages/web/src/components/CallableFunctionForm.tsx
+++ b/packages/web/src/components/forms/CallableFunctionForm/CallableFunctionForm.tsx
@@ -1,22 +1,13 @@
-import {
- Button,
- Center,
- Group,
- Loader,
- Stack,
- Text,
- TextInput,
-} from "@mantine/core";
+import { Button, Center, Group, Loader, Stack, TextInput } from "@mantine/core";
import CallableFunctionFormProvider, {
CallableFunctionFormProviderProps,
-} from "../contexts/providers/CallableFunctionFormProvider";
-import useCallableFunctionForm from "../hooks/useCallableFunctionForm";
+} from "../../../contexts/providers/CallableFunctionFormProvider";
+import useCallableFunctionForm from "../../../contexts/hooks/useCallableFunctionForm";
import { Link, useNavigate } from "react-router-dom";
import CallableFunctionFormParameters from "./CallableFunctionFormParameters";
-import OptionalTextInput from "./OptionalTextInput";
-import { modals } from "@mantine/modals";
+import OptionalTextInput from "../../inputs/OptionalTextInput";
import React, { Suspense } from "react";
-import { deleteCallableFunction } from "../store/actions/callableFunctions/deleteCallableFunction";
+import { deleteCallableFunction } from "../../../store/actions/callableFunctions/deleteCallableFunction";
const CallableFunctionFormCode = React.lazy(
() => import("./CallableFunctionFormCode")
@@ -37,26 +28,15 @@ const CallableFunctionFormProvided = ({
const form = useCallableFunctionForm();
const navigate = useNavigate();
- const openDeleteModal = React.useCallback(() => {
+ const handleDelete = React.useCallback(async () => {
const id = form.values.id;
if (!id) return;
- modals.openConfirmModal({
- title: `Delete ${form.values.displayName}?`,
- centered: true,
- children: (
-
- Are you sure you want to delete {form.values.displayName}?
- This cannot be undone.
-
- ),
- labels: { confirm: "Delete function", cancel: "Cancel" },
- confirmProps: { color: "red" },
- onConfirm: () => {
- deleteCallableFunction(id);
- navigate("/functions");
- },
- });
- }, [form.values.displayName, form.values.id, navigate]);
+
+ const deleted = await deleteCallableFunction(id);
+ if (!deleted) return;
+
+ navigate("/functions");
+ }, [form.values.id, navigate]);
return (
@@ -94,7 +74,7 @@ const CallableFunctionFormProvided = ({
diff --git a/packages/web/src/components/CallableFunctionFormCode.tsx b/packages/web/src/components/forms/CallableFunctionForm/CallableFunctionFormCode.tsx
similarity index 95%
rename from packages/web/src/components/CallableFunctionFormCode.tsx
rename to packages/web/src/components/forms/CallableFunctionForm/CallableFunctionFormCode.tsx
index 46bb5de..950a024 100644
--- a/packages/web/src/components/CallableFunctionFormCode.tsx
+++ b/packages/web/src/components/forms/CallableFunctionForm/CallableFunctionFormCode.tsx
@@ -1,9 +1,9 @@
import { Box, Group, Title, Text, Collapse, Stack, Alert } from "@mantine/core";
import { FaQuestion } from "react-icons/fa";
import CodeEditor from "./CodeEditor";
-import TippedActionIcon from "./TippedActionIcon";
+import TippedActionIcon from "../../common/TippedActionIcon";
import { useDisclosure } from "@mantine/hooks";
-import useCallableFunctionForm from "../hooks/useCallableFunctionForm";
+import useCallableFunctionForm from "../../../contexts/hooks/useCallableFunctionForm";
import { BsFillExclamationTriangleFill } from "react-icons/bs";
const CallableFunctionFormCode = () => {
diff --git a/packages/web/src/components/CallableFunctionFormParameters.tsx b/packages/web/src/components/forms/CallableFunctionForm/CallableFunctionFormParameters.tsx
similarity index 95%
rename from packages/web/src/components/CallableFunctionFormParameters.tsx
rename to packages/web/src/components/forms/CallableFunctionForm/CallableFunctionFormParameters.tsx
index e3ec62d..3ea2d2a 100644
--- a/packages/web/src/components/CallableFunctionFormParameters.tsx
+++ b/packages/web/src/components/forms/CallableFunctionForm/CallableFunctionFormParameters.tsx
@@ -3,12 +3,12 @@ import { useDisclosure } from "@mantine/hooks";
import { BiPlus, BiX } from "react-icons/bi";
import CallableFunctionParameterForm, {
CallableFunctionParameterFormProps,
-} from "./CallableFunctionParameterForm";
-import useCallableFunctionForm from "../hooks/useCallableFunctionForm";
+} from "../CallableFunctionParameterForm/CallableFunctionParameterForm";
+import useCallableFunctionForm from "../../../contexts/hooks/useCallableFunctionForm";
import React from "react";
import { JsonSchemaObject } from "gpt-turbo";
-import getFunctionParameters from "../utils/getFunctionParameters";
-import TippedActionIcon from "./TippedActionIcon";
+import getFunctionParameters from "../../../utils/getFunctionParameters";
+import TippedActionIcon from "../../common/TippedActionIcon";
import { modals } from "@mantine/modals";
const CallableFunctionFormParameters = () => {
diff --git a/packages/web/src/components/CodeEditor.tsx b/packages/web/src/components/forms/CallableFunctionForm/CodeEditor.tsx
similarity index 98%
rename from packages/web/src/components/CodeEditor.tsx
rename to packages/web/src/components/forms/CallableFunctionForm/CodeEditor.tsx
index 2388969..44f92d5 100644
--- a/packages/web/src/components/CodeEditor.tsx
+++ b/packages/web/src/components/forms/CallableFunctionForm/CodeEditor.tsx
@@ -7,7 +7,7 @@ import jsLanguageSyntax from "highlight.js/lib/languages/javascript";
import React from "react";
import { Divider, createStyles } from "@mantine/core";
import { JsonSchemaObject } from "gpt-turbo";
-import getFunctionSignature from "../utils/getFunctionSignature";
+import getFunctionSignature from "../../../utils/getFunctionSignature";
lowlight.registerLanguage("js", jsLanguageSyntax);
diff --git a/packages/web/src/components/CallableFunctionParameterForm.tsx b/packages/web/src/components/forms/CallableFunctionParameterForm/CallableFunctionParameterForm.tsx
similarity index 98%
rename from packages/web/src/components/CallableFunctionParameterForm.tsx
rename to packages/web/src/components/forms/CallableFunctionParameterForm/CallableFunctionParameterForm.tsx
index 4c35821..e8637bd 100644
--- a/packages/web/src/components/CallableFunctionParameterForm.tsx
+++ b/packages/web/src/components/forms/CallableFunctionParameterForm/CallableFunctionParameterForm.tsx
@@ -26,10 +26,10 @@ import {
} from "gpt-turbo";
import { z } from "zod";
import { useForm, zodResolver } from "@mantine/form";
-import OptionalTextInput from "./OptionalTextInput";
-import OptionalBooleanInput from "./OptionalBooleanInput";
+import OptionalTextInput from "../../inputs/OptionalTextInput";
+import OptionalBooleanInput from "../../inputs/OptionalBooleanInput";
import { BiInfoCircle } from "react-icons/bi";
-import getErrorInfo from "../utils/getErrorInfo";
+import getErrorInfo from "../../../utils/getErrorInfo";
type CallableFunctionParameterType =
| "string"
diff --git a/packages/web/src/components/ConversationForm.tsx b/packages/web/src/components/forms/ConversationForm/ConversationForm.tsx
similarity index 94%
rename from packages/web/src/components/ConversationForm.tsx
rename to packages/web/src/components/forms/ConversationForm/ConversationForm.tsx
index f14e82d..b01153a 100644
--- a/packages/web/src/components/ConversationForm.tsx
+++ b/packages/web/src/components/forms/ConversationForm/ConversationForm.tsx
@@ -1,13 +1,13 @@
import { Stack, Text, Button, Tabs, Box } from "@mantine/core";
import ConversationFormProvider, {
ConversationFormProviderProps,
-} from "../contexts/providers/ConversationFormProvider";
+} from "../../../contexts/providers/ConversationFormProvider";
import ConversationFormConversationTab from "./ConversationFormConversationTab";
import ConversationFormRequestTab from "./ConversationFormRequestTab";
import ConversationFormFunctionsTab from "./ConversationFormFunctionsTab";
-import useConversationForm from "../hooks/useConversationForm";
-import AppSettings from "./AppSettings";
+import AppSettings from "../../AppSettings/AppSettings";
import React from "react";
+import useConversationForm from "../../../contexts/hooks/useConversationForm";
interface ConversationFormProvidedProps {
hideAppSettings?: boolean;
diff --git a/packages/web/src/components/ConversationFormConversationTab.tsx b/packages/web/src/components/forms/ConversationForm/ConversationFormConversationTab.tsx
similarity index 85%
rename from packages/web/src/components/ConversationFormConversationTab.tsx
rename to packages/web/src/components/forms/ConversationForm/ConversationFormConversationTab.tsx
index 798f053..6f8fb1d 100644
--- a/packages/web/src/components/ConversationFormConversationTab.tsx
+++ b/packages/web/src/components/forms/ConversationForm/ConversationFormConversationTab.tsx
@@ -7,18 +7,18 @@ import {
Grid,
TextInput,
} from "@mantine/core";
-import useConversationForm from "../hooks/useConversationForm";
-import ApiKeyInput from "./ApiKeyInput";
-import ContextInput from "./ContextInput";
-import DisableModerationInput from "./DisableModerationInput";
-import DryInput from "./DryInput";
-import LogitBiasInput from "./LogitBiasInput";
-import ModelSelectInput from "./ModelSelectInput";
-import OptionalNumberInput from "./OptionalNumberInput";
-import SaveInput from "./SaveInput";
-import StopInput from "./StopInput";
-import StreamInput from "./StreamInput";
+import ApiKeyInput from "../../inputs/ApiKeyInput";
+import ContextInput from "../../inputs/ContextInput";
+import DisableModerationInput from "../../inputs/DisableModerationInput";
+import DryInput from "../../inputs/DryInput";
+import LogitBiasInput from "../../inputs/LogitBiasInput";
+import ModelSelectInput from "../../inputs/ModelSelectInput/ModelSelectInput";
+import OptionalNumberInput from "../../inputs/OptionalNumberInput";
+import SaveInput from "../../inputs/SaveInput";
+import StopInput from "../../inputs/StopInput";
+import StreamInput from "../../inputs/StreamInput";
import React from "react";
+import useConversationForm from "../../../contexts/hooks/useConversationForm";
const ConversationFormConversationTab = () => {
const form = useConversationForm();
diff --git a/packages/web/src/components/ConversationFormFunctionsTab.tsx b/packages/web/src/components/forms/ConversationForm/ConversationFormFunctionsTab.tsx
similarity index 77%
rename from packages/web/src/components/ConversationFormFunctionsTab.tsx
rename to packages/web/src/components/forms/ConversationForm/ConversationFormFunctionsTab.tsx
index a1dcab3..efe4776 100644
--- a/packages/web/src/components/ConversationFormFunctionsTab.tsx
+++ b/packages/web/src/components/forms/ConversationForm/ConversationFormFunctionsTab.tsx
@@ -1,14 +1,14 @@
import { Button, Center, Chip, Divider, Group, Stack } from "@mantine/core";
-import FunctionsWarning from "./FunctionsWarning";
-import useConversationForm from "../hooks/useConversationForm";
+import FunctionsWarning from "../../warnings/FunctionsWarning";
import { AiOutlineFunction } from "react-icons/ai";
import { Link } from "react-router-dom";
-import useCallableFunctions from "../hooks/useCallableFunctions";
-import { useAppStore } from "../store";
+import { useAppStore } from "../../../store";
+import { useGetFunctionDisplayName } from "../../../store/hooks/callableFunctions/useGetFunctionDisplayName";
+import useConversationForm from "../../../contexts/hooks/useConversationForm";
const ConversationFormFunctionsTab = () => {
const callableFunctions = useAppStore((state) => state.callableFunctions);
- const { getCallableFunctionDisplayName } = useCallableFunctions();
+ const getFunctionDisplayName = useGetFunctionDisplayName();
const form = useConversationForm();
return (
@@ -37,7 +37,8 @@ const ConversationFormFunctionsTab = () => {
{callableFunctions.map((fn) => (
- {getCallableFunctionDisplayName(fn.id)}
+ {getFunctionDisplayName(fn.id) ??
+ "[N/A]"}
))}
diff --git a/packages/web/src/components/ConversationFormRequestTab.tsx b/packages/web/src/components/forms/ConversationForm/ConversationFormRequestTab.tsx
similarity index 65%
rename from packages/web/src/components/ConversationFormRequestTab.tsx
rename to packages/web/src/components/forms/ConversationForm/ConversationFormRequestTab.tsx
index 9f3e666..6cadffb 100644
--- a/packages/web/src/components/ConversationFormRequestTab.tsx
+++ b/packages/web/src/components/forms/ConversationForm/ConversationFormRequestTab.tsx
@@ -1,7 +1,7 @@
import { Stack } from "@mantine/core";
-import useConversationForm from "../hooks/useConversationForm";
-import HeadersInput from "./HeadersInput";
-import ProxyInput from "./ProxyInput";
+import HeadersInput from "../../inputs/HeadersInput";
+import ProxyInput from "../../inputs/ProxyInput";
+import useConversationForm from "../../../contexts/hooks/useConversationForm";
const ConversationFormRequestTab = () => {
const form = useConversationForm();
diff --git a/packages/web/src/components/ApiKeyInput.tsx b/packages/web/src/components/inputs/ApiKeyInput.tsx
similarity index 100%
rename from packages/web/src/components/ApiKeyInput.tsx
rename to packages/web/src/components/inputs/ApiKeyInput.tsx
diff --git a/packages/web/src/components/ContextInput.tsx b/packages/web/src/components/inputs/ContextInput.tsx
similarity index 91%
rename from packages/web/src/components/ContextInput.tsx
rename to packages/web/src/components/inputs/ContextInput.tsx
index f11d901..aa40a5a 100644
--- a/packages/web/src/components/ContextInput.tsx
+++ b/packages/web/src/components/inputs/ContextInput.tsx
@@ -1,10 +1,10 @@
import { Modal, ScrollArea, Stack, Textarea } from "@mantine/core";
import { BiFolder, BiSave } from "react-icons/bi";
-import TippedActionIcon from "./TippedActionIcon";
+import TippedActionIcon from "../common/TippedActionIcon";
import { useDisclosure } from "@mantine/hooks";
-import SaveContextModalBody from "./SavePromptModalBody";
-import SavedContextsModalBody from "./SavedPromptsModalBody";
-import { useAppStore } from "../store";
+import SaveContextModalBody from "../modals/SavePromptModalBody";
+import SavedContextsModalBody from "../modals/SavedPromptsModalBody";
+import { useAppStore } from "../../store";
interface ContextInputProps {
value: string;
diff --git a/packages/web/src/components/DisableModerationInput.tsx b/packages/web/src/components/inputs/DisableModerationInput.tsx
similarity index 100%
rename from packages/web/src/components/DisableModerationInput.tsx
rename to packages/web/src/components/inputs/DisableModerationInput.tsx
diff --git a/packages/web/src/components/DryInput.tsx b/packages/web/src/components/inputs/DryInput.tsx
similarity index 100%
rename from packages/web/src/components/DryInput.tsx
rename to packages/web/src/components/inputs/DryInput.tsx
diff --git a/packages/web/src/components/HeadersInput.tsx b/packages/web/src/components/inputs/HeadersInput.tsx
similarity index 95%
rename from packages/web/src/components/HeadersInput.tsx
rename to packages/web/src/components/inputs/HeadersInput.tsx
index 63c3dda..11e8d78 100644
--- a/packages/web/src/components/HeadersInput.tsx
+++ b/packages/web/src/components/inputs/HeadersInput.tsx
@@ -41,10 +41,13 @@ const getValueFromHeaders = (value: Header[]) => {
if (headers.length === 0) return undefined;
- return headers.reduce((acc, { header, value: v }) => {
- acc[header] = v;
- return acc;
- }, {} as Record);
+ return headers.reduce(
+ (acc, { header, value: v }) => {
+ acc[header] = v;
+ return acc;
+ },
+ {} as Record
+ );
};
const HeadersInput = ({ value, onChange }: HeadersInputProps) => {
diff --git a/packages/web/src/components/LogitBiasInput.tsx b/packages/web/src/components/inputs/LogitBiasInput.tsx
similarity index 96%
rename from packages/web/src/components/LogitBiasInput.tsx
rename to packages/web/src/components/inputs/LogitBiasInput.tsx
index eafce2d..e6013e0 100644
--- a/packages/web/src/components/LogitBiasInput.tsx
+++ b/packages/web/src/components/inputs/LogitBiasInput.tsx
@@ -51,10 +51,13 @@ const getValueFromTokens = (value: LogitBias[]) => {
if (tokens.length === 0) return undefined;
- return tokens.reduce((acc, { token, probability }) => {
- acc[token] = Number(probability);
- return acc;
- }, {} as Record);
+ return tokens.reduce(
+ (acc, { token, probability }) => {
+ acc[token] = Number(probability);
+ return acc;
+ },
+ {} as Record
+ );
};
const LogitBiasInput = ({ value, onChange }: LogitBiasInputProps) => {
diff --git a/packages/web/src/components/ModelSelectInput.tsx b/packages/web/src/components/inputs/ModelSelectInput/ModelSelectInput.tsx
similarity index 100%
rename from packages/web/src/components/ModelSelectInput.tsx
rename to packages/web/src/components/inputs/ModelSelectInput/ModelSelectInput.tsx
diff --git a/packages/web/src/components/ModelSelectItem.tsx b/packages/web/src/components/inputs/ModelSelectInput/ModelSelectItem.tsx
similarity index 100%
rename from packages/web/src/components/ModelSelectItem.tsx
rename to packages/web/src/components/inputs/ModelSelectInput/ModelSelectItem.tsx
diff --git a/packages/web/src/components/OptionalBooleanInput.tsx b/packages/web/src/components/inputs/OptionalBooleanInput.tsx
similarity index 100%
rename from packages/web/src/components/OptionalBooleanInput.tsx
rename to packages/web/src/components/inputs/OptionalBooleanInput.tsx
diff --git a/packages/web/src/components/OptionalNumberInput.tsx b/packages/web/src/components/inputs/OptionalNumberInput.tsx
similarity index 100%
rename from packages/web/src/components/OptionalNumberInput.tsx
rename to packages/web/src/components/inputs/OptionalNumberInput.tsx
diff --git a/packages/web/src/components/OptionalTextInput.tsx b/packages/web/src/components/inputs/OptionalTextInput.tsx
similarity index 100%
rename from packages/web/src/components/OptionalTextInput.tsx
rename to packages/web/src/components/inputs/OptionalTextInput.tsx
diff --git a/packages/web/src/components/Prompt.tsx b/packages/web/src/components/inputs/Prompt/Prompt.tsx
similarity index 92%
rename from packages/web/src/components/Prompt.tsx
rename to packages/web/src/components/inputs/Prompt/Prompt.tsx
index b53de0d..35c7add 100644
--- a/packages/web/src/components/Prompt.tsx
+++ b/packages/web/src/components/inputs/Prompt/Prompt.tsx
@@ -7,7 +7,6 @@ import {
Textarea,
} from "@mantine/core";
import { useForm } from "@mantine/form";
-import useConversationManager from "../hooks/useConversationManager";
import { notifications } from "@mantine/notifications";
import React from "react";
import PromptUsage from "./PromptUsage";
@@ -20,15 +19,16 @@ import {
useOs,
} from "@mantine/hooks";
import { BiFolder, BiPaperPlane } from "react-icons/bi";
-import TippedActionIcon from "./TippedActionIcon";
-import SavedPromptsModalBody from "./SavedPromptsModalBody";
-import getErrorInfo from "../utils/getErrorInfo";
-import { useAppStore } from "../store";
-import { setConversationLastEdit } from "../store/actions/conversations/setConversationLastEdit";
+import TippedActionIcon from "../../common/TippedActionIcon";
+import SavedPromptsModalBody from "../../modals/SavedPromptsModalBody";
+import getErrorInfo from "../../../utils/getErrorInfo";
+import { useAppStore } from "../../../store";
+import { setConversationLastEdit } from "../../../store/actions/conversations/setConversationLastEdit";
+import { useActiveConversation } from "../../../store/hooks/conversations/useActiveConversation";
const Prompt = () => {
const showUsage = useAppStore((state) => state.showUsage);
- const { activeConversation: conversation } = useConversationManager();
+ const conversation = useActiveConversation();
const form = useForm({
initialValues: {
prompt: "",
diff --git a/packages/web/src/components/PromptUsage.tsx b/packages/web/src/components/inputs/Prompt/PromptUsage.tsx
similarity index 96%
rename from packages/web/src/components/PromptUsage.tsx
rename to packages/web/src/components/inputs/Prompt/PromptUsage.tsx
index 4d0a09a..e9142ee 100644
--- a/packages/web/src/components/PromptUsage.tsx
+++ b/packages/web/src/components/inputs/Prompt/PromptUsage.tsx
@@ -1,6 +1,6 @@
import { Tooltip, Stack, Group, Button, Text } from "@mantine/core";
import { getMessageSize, getMessageCost, Conversation } from "gpt-turbo";
-import getPriceString from "../utils/getPriceString";
+import getPriceString from "../../../utils/getPriceString";
import React from "react";
interface PromptUsageProps {
diff --git a/packages/web/src/components/ProxyInput.tsx b/packages/web/src/components/inputs/ProxyInput.tsx
similarity index 100%
rename from packages/web/src/components/ProxyInput.tsx
rename to packages/web/src/components/inputs/ProxyInput.tsx
diff --git a/packages/web/src/components/SaveInput.tsx b/packages/web/src/components/inputs/SaveInput.tsx
similarity index 100%
rename from packages/web/src/components/SaveInput.tsx
rename to packages/web/src/components/inputs/SaveInput.tsx
diff --git a/packages/web/src/components/StopInput.tsx b/packages/web/src/components/inputs/StopInput.tsx
similarity index 100%
rename from packages/web/src/components/StopInput.tsx
rename to packages/web/src/components/inputs/StopInput.tsx
diff --git a/packages/web/src/components/StreamInput.tsx b/packages/web/src/components/inputs/StreamInput.tsx
similarity index 100%
rename from packages/web/src/components/StreamInput.tsx
rename to packages/web/src/components/inputs/StreamInput.tsx
diff --git a/packages/web/src/components/SavePromptModalBody.tsx b/packages/web/src/components/modals/SavePromptModalBody.tsx
similarity index 86%
rename from packages/web/src/components/SavePromptModalBody.tsx
rename to packages/web/src/components/modals/SavePromptModalBody.tsx
index 7072714..4361c7e 100644
--- a/packages/web/src/components/SavePromptModalBody.tsx
+++ b/packages/web/src/components/modals/SavePromptModalBody.tsx
@@ -1,11 +1,11 @@
import { Button, Group, Stack, TextInput } from "@mantine/core";
import { useForm, zodResolver } from "@mantine/form";
-import { persistenceSavedContextSchema } from "../entities/persistenceSavedContext";
+import { persistenceSavedContextSchema } from "../../entities/persistenceSavedContext";
import { z } from "zod";
-import { persistenceSavedPromptSchema } from "../entities/persistenceSavedPrompt";
-import { useAppStore } from "../store";
-import { saveContext } from "../store/actions/savedContexts/saveContext";
-import { savePrompt } from "../store/actions/savedPrompts/savePrompt";
+import { persistenceSavedPromptSchema } from "../../entities/persistenceSavedPrompt";
+import { useAppStore } from "../../store";
+import { saveContext } from "../../store/actions/savedContexts/saveContext";
+import { savePrompt } from "../../store/actions/savedPrompts/savePrompt";
interface SaveContextModalBodyProps {
value: string;
diff --git a/packages/web/src/components/SavedPromptsModalBody.tsx b/packages/web/src/components/modals/SavedPromptsModalBody.tsx
similarity index 89%
rename from packages/web/src/components/SavedPromptsModalBody.tsx
rename to packages/web/src/components/modals/SavedPromptsModalBody.tsx
index 4803475..cdde898 100644
--- a/packages/web/src/components/SavedPromptsModalBody.tsx
+++ b/packages/web/src/components/modals/SavedPromptsModalBody.tsx
@@ -1,10 +1,10 @@
import { Accordion, Box, Stack } from "@mantine/core";
-import TippedActionIcon from "./TippedActionIcon";
+import TippedActionIcon from "../common/TippedActionIcon";
import { BiImport, BiTrash } from "react-icons/bi";
import React from "react";
-import { useAppStore } from "../store";
-import { removeSavedContext } from "../store/actions/savedContexts/removeSavedContext";
-import { removeSavedPrompt } from "../store/actions/savedPrompts/removeSavedPrompt";
+import { useAppStore } from "../../store";
+import { removeSavedContext } from "../../store/actions/savedContexts/removeSavedContext";
+import { removeSavedPrompt } from "../../store/actions/savedPrompts/removeSavedPrompt";
interface SavedContextsModalBodyProps {
onSelect: (value: string) => void;
diff --git a/packages/web/src/components/SettingsFormModal.tsx b/packages/web/src/components/modals/SettingsFormModal.tsx
similarity index 78%
rename from packages/web/src/components/SettingsFormModal.tsx
rename to packages/web/src/components/modals/SettingsFormModal.tsx
index 621a08d..07195c0 100644
--- a/packages/web/src/components/SettingsFormModal.tsx
+++ b/packages/web/src/components/modals/SettingsFormModal.tsx
@@ -1,10 +1,10 @@
import { Container, Modal, ModalProps, useMantineTheme } from "@mantine/core";
import { useMediaQuery } from "@mantine/hooks";
import React from "react";
-import { ConversationFormValues } from "../contexts/ConversationFormContext";
-import ConversationForm from "./ConversationForm";
-import { useAppStore } from "../store";
-import { setDefaultSettings } from "../store/actions/defaultConversationSettings/setDefaultSettings";
+import { ConversationFormValues } from "../../contexts/ConversationFormContext";
+import ConversationForm from "../forms/ConversationForm/ConversationForm";
+import { useAppStore } from "../../store";
+import { setDefaultSettings } from "../../store/actions/defaultConversationSettings/setDefaultSettings";
type SettingsFormModalProps = ModalProps;
diff --git a/packages/web/src/components/FunctionsImportWarning.tsx b/packages/web/src/components/warnings/FunctionsImportWarning.tsx
similarity index 93%
rename from packages/web/src/components/FunctionsImportWarning.tsx
rename to packages/web/src/components/warnings/FunctionsImportWarning.tsx
index 0a2963b..9da16dc 100644
--- a/packages/web/src/components/FunctionsImportWarning.tsx
+++ b/packages/web/src/components/warnings/FunctionsImportWarning.tsx
@@ -1,7 +1,7 @@
import { Alert, List, Center, Button, Text } from "@mantine/core";
import { FaExclamationTriangle } from "react-icons/fa";
-import { useAppStore } from "../store";
-import { dismissFunctionsImportWarning } from "../store/actions/callableFunctions/dismissFunctionsImportWarning";
+import { useAppStore } from "../../store";
+import { dismissFunctionsImportWarning } from "../../store/actions/callableFunctions/dismissFunctionsImportWarning";
interface FunctionsImportWarningProps {
children?: React.ReactNode;
diff --git a/packages/web/src/components/FunctionsWarning.tsx b/packages/web/src/components/warnings/FunctionsWarning.tsx
similarity index 93%
rename from packages/web/src/components/FunctionsWarning.tsx
rename to packages/web/src/components/warnings/FunctionsWarning.tsx
index d73f432..b28eafb 100644
--- a/packages/web/src/components/FunctionsWarning.tsx
+++ b/packages/web/src/components/warnings/FunctionsWarning.tsx
@@ -1,7 +1,7 @@
import { Alert, List, Anchor, Center, Button } from "@mantine/core";
import { FaExclamationTriangle } from "react-icons/fa";
-import { useAppStore } from "../store";
-import { dismissFunctionsWarning } from "../store/actions/callableFunctions/dismissFunctionsWarning";
+import { useAppStore } from "../../store";
+import { dismissFunctionsWarning } from "../../store/actions/callableFunctions/dismissFunctionsWarning";
interface FunctionsWarningProps {
children?: React.ReactNode;
diff --git a/packages/web/src/config/constants.ts b/packages/web/src/config/constants.ts
index f86dd27..74bb6db 100644
--- a/packages/web/src/config/constants.ts
+++ b/packages/web/src/config/constants.ts
@@ -43,3 +43,5 @@ export const CHANGELOG_SECTION = {
FIXES: "🐛 Bug fixes",
REMOVALS: "👋 Removals",
};
+
+export const DEFAULT_CONVERSATION_NAME = "New Chat";
diff --git a/packages/web/src/contexts/CallableFunctionsContext.ts b/packages/web/src/contexts/CallableFunctionsContext.ts
deleted file mode 100644
index 971c775..0000000
--- a/packages/web/src/contexts/CallableFunctionsContext.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { CallableFunction } from "gpt-turbo";
-import React from "react";
-import makeNotImplemented from "../utils/makeNotImplemented";
-
-export interface CallableFunctionsContextValue {
- getCallableFunction: (id: string) => CallableFunction;
- getCallableFunctionDisplayName: (id: string) => string;
- getCallableFunctionCode: (id: string) => string | undefined;
- callFunction: (
- id: string,
- args: Record
- ) => Promise;
-}
-
-const notImplemented = makeNotImplemented("CallableFunctionsContext");
-export const CallableFunctionsContext =
- React.createContext({
- getCallableFunction: notImplemented,
- getCallableFunctionDisplayName: notImplemented,
- getCallableFunctionCode: notImplemented,
- callFunction: notImplemented,
- });
diff --git a/packages/web/src/contexts/ConversationManagerContext.ts b/packages/web/src/contexts/ConversationManagerContext.ts
deleted file mode 100644
index 23b3137..0000000
--- a/packages/web/src/contexts/ConversationManagerContext.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from "react";
-import makeNotImplemented from "../utils/makeNotImplemented";
-import { Conversation } from "gpt-turbo";
-
-export interface ConversationManagerContextValue {
- activeConversation: Conversation | null;
- getConversationName: (id: string) => string;
- getConversationLastEdit: (id: string) => number;
-}
-
-const notImplemented = makeNotImplemented("ConversationManagerContext");
-export const ConversationManagerContext =
- React.createContext({
- activeConversation: null,
- getConversationName: notImplemented,
- getConversationLastEdit: notImplemented,
- });
diff --git a/packages/web/src/contexts/ConversationNavbarContext.ts b/packages/web/src/contexts/ConversationNavbarContext.ts
new file mode 100644
index 0000000..39e77d1
--- /dev/null
+++ b/packages/web/src/contexts/ConversationNavbarContext.ts
@@ -0,0 +1,18 @@
+import React from "react";
+import makeNotImplemented from "../utils/makeNotImplemented";
+
+export interface ConversationNavbarContextValue {
+ navbarOpened: boolean;
+ openNavbar: () => void;
+ closeNavbar: () => void;
+ toggleNavbar: () => void;
+}
+
+const notImplemented = makeNotImplemented("ConversationNavbarContext");
+export const ConversationNavbarContext =
+ React.createContext({
+ navbarOpened: false,
+ openNavbar: notImplemented,
+ closeNavbar: notImplemented,
+ toggleNavbar: notImplemented,
+ });
diff --git a/packages/web/src/contexts/hooks/useCallableFunctionForm.ts b/packages/web/src/contexts/hooks/useCallableFunctionForm.ts
new file mode 100644
index 0000000..9269f5c
--- /dev/null
+++ b/packages/web/src/contexts/hooks/useCallableFunctionForm.ts
@@ -0,0 +1,3 @@
+import { CallableFunctionFormContext } from "../CallableFunctionFormContext";
+
+export default CallableFunctionFormContext.useContext;
diff --git a/packages/web/src/contexts/hooks/useConversationForm.ts b/packages/web/src/contexts/hooks/useConversationForm.ts
new file mode 100644
index 0000000..162641f
--- /dev/null
+++ b/packages/web/src/contexts/hooks/useConversationForm.ts
@@ -0,0 +1,3 @@
+import { ConversationFormContext } from "../ConversationFormContext";
+
+export default ConversationFormContext.useContext;
diff --git a/packages/web/src/contexts/hooks/useConversationNavbar.ts b/packages/web/src/contexts/hooks/useConversationNavbar.ts
new file mode 100644
index 0000000..586aa35
--- /dev/null
+++ b/packages/web/src/contexts/hooks/useConversationNavbar.ts
@@ -0,0 +1,4 @@
+import React from "react";
+import { ConversationNavbarContext } from "../ConversationNavbarContext";
+
+export default () => React.useContext(ConversationNavbarContext);
diff --git a/packages/web/src/contexts/providers/CallableFunctionFormProvider.tsx b/packages/web/src/contexts/providers/CallableFunctionFormProvider.tsx
index 1d8a244..ac9e9bc 100644
--- a/packages/web/src/contexts/providers/CallableFunctionFormProvider.tsx
+++ b/packages/web/src/contexts/providers/CallableFunctionFormProvider.tsx
@@ -6,10 +6,11 @@ import {
} from "../CallableFunctionFormContext";
import { persistenceCallableFunctionSchema } from "../../entities/persistenceCallableFunction";
import React from "react";
-import useCallableFunctions from "../../hooks/useCallableFunctions";
import { useSearchParams } from "react-router-dom";
import functionTemplates from "../../utils/functionTemplates";
import { useAppStore } from "../../store";
+import { useGetFunctionDisplayName } from "../../store/hooks/callableFunctions/useGetFunctionDisplayName";
+import { useGetFunctionCode } from "../../store/hooks/callableFunctions/useGetFunctionCode";
export interface CallableFunctionFormProviderProps {
children: React.ReactNode;
@@ -23,8 +24,8 @@ const CallableFunctionFormProvider = ({
id,
}: CallableFunctionFormProviderProps) => {
const callableFunctions = useAppStore((state) => state.callableFunctions);
- const { getCallableFunctionDisplayName, getCallableFunctionCode } =
- useCallableFunctions();
+ const getFunctionDisplayName = useGetFunctionDisplayName();
+ const getFunctionCode = useGetFunctionCode();
const form = CallableFunctionFormContext.useForm({
initialValues: {
id: uuid(),
@@ -43,7 +44,7 @@ const CallableFunctionFormProvider = ({
const existingDisplayName = callableFunctions.find(
(f) =>
f.id !== values.id &&
- getCallableFunctionDisplayName(f.id) === values.displayName
+ getFunctionDisplayName(f.id) === values.displayName
);
if (existingName) {
@@ -67,16 +68,10 @@ const CallableFunctionFormProvider = ({
if (!callableFunction) return;
form.setValues({
...callableFunction.toJSON(),
- displayName: getCallableFunctionDisplayName(callableFunction.id),
- code: getCallableFunctionCode(callableFunction.id),
+ displayName: getFunctionDisplayName(callableFunction.id),
+ code: getFunctionCode(callableFunction.id),
});
- }, [
- callableFunctions,
- form,
- getCallableFunctionCode,
- getCallableFunctionDisplayName,
- id,
- ]);
+ }, [callableFunctions, form, getFunctionCode, getFunctionDisplayName, id]);
React.useEffect(() => {
if (form.isDirty() || !query.has("template")) return;
diff --git a/packages/web/src/contexts/providers/CallableFunctionsProvider.tsx b/packages/web/src/contexts/providers/CallableFunctionsProvider.tsx
deleted file mode 100644
index fa96ad0..0000000
--- a/packages/web/src/contexts/providers/CallableFunctionsProvider.tsx
+++ /dev/null
@@ -1,163 +0,0 @@
-import React from "react";
-import {
- CallableFunctionsContext,
- CallableFunctionsContextValue,
-} from "../CallableFunctionsContext";
-import { notifications } from "@mantine/notifications";
-import { randomId } from "@mantine/hooks";
-import { BiCheck, BiX } from "react-icons/bi";
-import getErrorInfo from "../../utils/getErrorInfo";
-import { useAppStore } from "../../store";
-
-interface CallableFunctionsProviderProps {
- children?: React.ReactNode;
-}
-
-const CallableFunctionsProvider = ({
- children,
-}: CallableFunctionsProviderProps) => {
- const [functions, displayNames, codes] = useAppStore((state) => [
- state.callableFunctions,
- state.callableFunctionDisplayNames,
- state.callableFunctionCodes,
- ]);
-
- const getCallableFunction = React.useCallback<
- CallableFunctionsContextValue["getCallableFunction"]
- >(
- (id) => {
- const callableFunction = functions.find((fn) => fn.id === id);
- if (callableFunction === undefined) {
- throw new Error(`No callable function found with id "${id}"`);
- }
- return callableFunction;
- },
- [functions]
- );
-
- const getCallableFunctionDisplayName = React.useCallback<
- CallableFunctionsContextValue["getCallableFunctionDisplayName"]
- >(
- (id) => {
- const displayName = displayNames[id];
- if (displayName === undefined) {
- throw new Error(
- `No display name found for callable function with id "${id}"`
- );
- }
- return displayName;
- },
- [displayNames]
- );
-
- const getCallableFunctionCode = React.useCallback<
- CallableFunctionsContextValue["getCallableFunctionCode"]
- >(
- (id) => {
- return codes[id];
- },
- [codes]
- );
-
- const callFunction = React.useCallback<
- CallableFunctionsContextValue["callFunction"]
- >(
- async (id, args) => {
- const callableFunction = getCallableFunction(id);
- const displayName = getCallableFunctionDisplayName(id);
-
- const code = getCallableFunctionCode(id);
- if (!code) return undefined;
-
- try {
- const { argNames, argValues } =
- callableFunction.parameters.reduce(
- (acc, fn) => {
- acc.argNames.push(fn.name);
- acc.argValues.push(args[fn.name] ?? undefined);
- return acc;
- },
- {
- argNames: [],
- argValues: [],
- } as { argNames: string[]; argValues: any[] }
- );
- const fn = new Function(...argNames, code);
-
- const result = fn(...argValues);
-
- if (result instanceof Promise) {
- const notifId = randomId();
- notifications.show({
- id: notifId,
- loading: true,
- title: "Function Call",
- message: `Calling ${displayName}...`,
- autoClose: false,
- withCloseButton: false,
- });
-
- try {
- const awaited = await result;
-
- notifications.update({
- id: notifId,
- color: "green",
- title: "Function Call Success",
- message: `${displayName} called successfully!`,
- icon: ,
- autoClose: 2000,
- });
-
- return awaited;
- } catch (e) {
- notifications.hide(notifId);
- throw e;
- }
- }
-
- return result;
- } catch (e) {
- console.error(e);
- const { message } = getErrorInfo(e);
- notifications.show({
- color: "red",
- title: "Function Call Failed",
- message: `${displayName} failed: ${message}`,
- icon: ,
- autoClose: false,
- withCloseButton: true,
- });
- return undefined;
- }
- },
- [
- getCallableFunction,
- getCallableFunctionCode,
- getCallableFunctionDisplayName,
- ]
- );
-
- const providerValue = React.useMemo(
- () => ({
- getCallableFunction,
- getCallableFunctionDisplayName,
- getCallableFunctionCode,
- callFunction,
- }),
- [
- callFunction,
- getCallableFunction,
- getCallableFunctionCode,
- getCallableFunctionDisplayName,
- ]
- );
-
- return (
-
- {children}
-
- );
-};
-
-export default CallableFunctionsProvider;
diff --git a/packages/web/src/contexts/providers/ConversationManagerProvider.tsx b/packages/web/src/contexts/providers/ConversationManagerProvider.tsx
deleted file mode 100644
index 2dead98..0000000
--- a/packages/web/src/contexts/providers/ConversationManagerProvider.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import React from "react";
-import {
- ConversationManagerContext,
- ConversationManagerContextValue,
-} from "../ConversationManagerContext";
-import { useAppStore } from "../../store";
-import { persistStore } from "../../store/persist/triggerPersist";
-
-interface ConversationManagerProviderProps {
- children?: React.ReactNode;
-}
-
-const ConversationManagerProvider = ({
- children,
-}: ConversationManagerProviderProps) => {
- const [conversations, names, lastEdits, activeId] = useAppStore((state) => [
- state.conversations,
- state.conversationNames,
- state.conversationLastEdits,
- state.activeConversationId,
- ]);
-
- const activeConversation = React.useMemo(
- () => conversations.find((c) => c.id === activeId) ?? null,
- [activeId, conversations]
- );
-
- const getConversationName = React.useCallback(
- (id: string) => {
- return names.get(id) ?? "New Chat";
- },
- [names]
- );
-
- const getConversationLastEdit = React.useCallback(
- (id: string) => {
- return lastEdits.get(id) ?? Date.now();
- },
- [lastEdits]
- );
-
- const providerValue = React.useMemo(
- () => ({
- activeId,
- activeConversation,
- getConversationName,
- getConversationLastEdit,
- }),
- [
- activeConversation,
- activeId,
- getConversationLastEdit,
- getConversationName,
- ]
- );
-
- React.useEffect(() => {
- if (!activeConversation) return;
- const unsubs: (() => void)[] = [];
-
- unsubs.push(
- activeConversation.onMessageAdded((message) => {
- if (message.content) {
- persistStore();
- }
-
- unsubs.push(
- message.onMessageStreamingStop(() => {
- persistStore();
- })
- );
- }),
- activeConversation.onMessageRemoved(() => {
- persistStore();
- })
- );
-
- return () => {
- unsubs.forEach((u) => u());
- };
- }, [activeConversation]);
-
- return (
-
- {children}
-
- );
-};
-
-export default ConversationManagerProvider;
diff --git a/packages/web/src/contexts/providers/ConversationNavbarProvider.tsx b/packages/web/src/contexts/providers/ConversationNavbarProvider.tsx
new file mode 100644
index 0000000..602496c
--- /dev/null
+++ b/packages/web/src/contexts/providers/ConversationNavbarProvider.tsx
@@ -0,0 +1,37 @@
+import React from "react";
+import {
+ ConversationNavbarContext,
+ ConversationNavbarContextValue,
+} from "../ConversationNavbarContext";
+import { useDisclosure } from "@mantine/hooks";
+
+interface ConversationNavbarProviderProps {
+ children?: React.ReactNode;
+}
+
+const ConversationNavbarProvider = ({
+ children,
+}: ConversationNavbarProviderProps) => {
+ const [
+ navbarOpened,
+ { open: openNavbar, close: closeNavbar, toggle: toggleNavbar },
+ ] = useDisclosure();
+
+ const providerValue = React.useMemo(
+ () => ({
+ navbarOpened,
+ openNavbar,
+ closeNavbar,
+ toggleNavbar,
+ }),
+ [closeNavbar, navbarOpened, openNavbar, toggleNavbar]
+ );
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default ConversationNavbarProvider;
diff --git a/packages/web/src/contexts/providers/index.tsx b/packages/web/src/contexts/providers/index.tsx
index 6271c65..e71d4f5 100644
--- a/packages/web/src/contexts/providers/index.tsx
+++ b/packages/web/src/contexts/providers/index.tsx
@@ -1,5 +1,3 @@
-import CallableFunctionsProvider from "./CallableFunctionsProvider";
-import ConversationManagerProvider from "./ConversationManagerProvider";
import MantineProviders from "./MantineProviders";
interface ProviderProps {
@@ -7,15 +5,7 @@ interface ProviderProps {
}
const Provider = ({ children }: ProviderProps) => {
- return (
-
-
-
- {children}
-
-
-
- );
+ return {children};
};
export default Provider;
diff --git a/packages/web/src/hooks/useCallableFunctionForm.ts b/packages/web/src/hooks/useCallableFunctionForm.ts
deleted file mode 100644
index 97ede42..0000000
--- a/packages/web/src/hooks/useCallableFunctionForm.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { CallableFunctionFormContext } from "../contexts/CallableFunctionFormContext";
-
-export default CallableFunctionFormContext.useContext;
diff --git a/packages/web/src/hooks/useCallableFunctions.ts b/packages/web/src/hooks/useCallableFunctions.ts
deleted file mode 100644
index 761c612..0000000
--- a/packages/web/src/hooks/useCallableFunctions.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import React from "react";
-import { CallableFunctionsContext } from "../contexts/CallableFunctionsContext";
-
-export default () => React.useContext(CallableFunctionsContext);
diff --git a/packages/web/src/hooks/useConversationForm.ts b/packages/web/src/hooks/useConversationForm.ts
deleted file mode 100644
index fc49e12..0000000
--- a/packages/web/src/hooks/useConversationForm.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { ConversationFormContext } from "../contexts/ConversationFormContext";
-
-export default ConversationFormContext.useContext;
diff --git a/packages/web/src/hooks/useConversationManager.ts b/packages/web/src/hooks/useConversationManager.ts
deleted file mode 100644
index 21a2c27..0000000
--- a/packages/web/src/hooks/useConversationManager.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import React from "react";
-import { ConversationManagerContext } from "../contexts/ConversationManagerContext";
-
-export default () => React.useContext(ConversationManagerContext);
diff --git a/packages/web/src/index.tsx b/packages/web/src/index.tsx
index 0e24af5..be246a8 100644
--- a/packages/web/src/index.tsx
+++ b/packages/web/src/index.tsx
@@ -1,7 +1,7 @@
import React from "react";
import ReactDOM from "react-dom/client";
import Providers from "./contexts/providers";
-import AppCatcher from "./components/AppCatcher";
+import AppCatcher from "./components/error-handling/AppCatcher";
import AppRouter from "./routers/AppRouter";
import { Container, Sx } from "@mantine/core";
diff --git a/packages/web/src/pages/ConversationPage.tsx b/packages/web/src/pages/ConversationPage.tsx
index 49145a6..dad16a1 100644
--- a/packages/web/src/pages/ConversationPage.tsx
+++ b/packages/web/src/pages/ConversationPage.tsx
@@ -1,13 +1,40 @@
import { Divider, Stack } from "@mantine/core";
import AddConversation from "../components/AddConversation";
-import useConversationManager from "../hooks/useConversationManager";
-import Messages from "../components/Messages";
-import Prompt from "../components/Prompt";
+import Messages from "../components/Messages/Messages";
+import Prompt from "../components/inputs/Prompt/Prompt";
import ConversationPageShell from "../components/ConversationPageShell";
import React from "react";
+import { persistStore } from "../store/persist/triggerPersist";
+import { useActiveConversation } from "../store/hooks/conversations/useActiveConversation";
const ConversationPage = () => {
- const { activeConversation } = useConversationManager();
+ const activeConversation = useActiveConversation();
+
+ React.useEffect(() => {
+ if (!activeConversation) return;
+ const unsubs: (() => void)[] = [];
+
+ unsubs.push(
+ activeConversation.onMessageAdded((message) => {
+ if (message.content) {
+ persistStore();
+ }
+
+ unsubs.push(
+ message.onMessageStreamingStop(() => {
+ persistStore();
+ })
+ );
+ }),
+ activeConversation.onMessageRemoved(() => {
+ persistStore();
+ })
+ );
+
+ return () => {
+ unsubs.forEach((u) => u());
+ };
+ }, [activeConversation]);
return (
diff --git a/packages/web/src/pages/FunctionEditorPage.tsx b/packages/web/src/pages/FunctionEditorPage.tsx
index 5c9baca..c98edcc 100644
--- a/packages/web/src/pages/FunctionEditorPage.tsx
+++ b/packages/web/src/pages/FunctionEditorPage.tsx
@@ -1,8 +1,8 @@
import { Container, Button } from "@mantine/core";
import { BiArrowBack } from "react-icons/bi";
import { Link, useNavigate, useParams } from "react-router-dom";
-import FunctionsWarning from "../components/FunctionsWarning";
-import CallableFunctionForm from "../components/CallableFunctionForm";
+import FunctionsWarning from "../components/warnings/FunctionsWarning";
+import CallableFunctionForm from "../components/forms/CallableFunctionForm/CallableFunctionForm";
import React from "react";
import { CallableFunctionFormProviderProps } from "../contexts/providers/CallableFunctionFormProvider";
import { addCallableFunction } from "../store/actions/callableFunctions/addCallableFunction";
diff --git a/packages/web/src/pages/FunctionsPage.tsx b/packages/web/src/pages/FunctionsPage.tsx
index 3587547..343e3f9 100644
--- a/packages/web/src/pages/FunctionsPage.tsx
+++ b/packages/web/src/pages/FunctionsPage.tsx
@@ -10,18 +10,18 @@ import {
} from "@mantine/core";
import { BiArrowBack, BiSearch } from "react-icons/bi";
import { Link } from "react-router-dom";
-import FunctionsWarning from "../components/FunctionsWarning";
+import FunctionsWarning from "../components/warnings/FunctionsWarning";
import { useInputState, useMediaQuery } from "@mantine/hooks";
import React from "react";
-import useCallableFunctions from "../hooks/useCallableFunctions";
-import CallableFunctionCard from "../components/CallableFunctionCard";
-import CallableFunctionImportButton from "../components/CallableFunctionImportButton";
+import CallableFunctionCard from "../components/CallableFunctionCard/CallableFunctionCard";
+import CallableFunctionImportButton from "../components/CallableFunctionImport/CallableFunctionImportButton";
import CallableFunctionCreateButton from "../components/CallableFunctionCreateButton";
import { useAppStore } from "../store";
+import { useGetFunctionDisplayName } from "../store/hooks/callableFunctions/useGetFunctionDisplayName";
const FunctionsPage = () => {
const callableFunctions = useAppStore((state) => state.callableFunctions);
- const { getCallableFunctionDisplayName } = useCallableFunctions();
+ const getFunctionDisplayName = useGetFunctionDisplayName();
const [search, setSearch] = useInputState("");
const theme = useMantineTheme();
const isSm = useMediaQuery(`(max-width: ${theme.breakpoints.md})`);
@@ -30,10 +30,10 @@ const FunctionsPage = () => {
() =>
callableFunctions.map((fn) => ({
fn,
- displayName: getCallableFunctionDisplayName(fn.id),
+ displayName: getFunctionDisplayName(fn.id),
name: fn.name,
})),
- [callableFunctions, getCallableFunctionDisplayName]
+ [callableFunctions, getFunctionDisplayName]
);
const filteredFunctions = React.useMemo(() => {
@@ -46,7 +46,10 @@ const FunctionsPage = () => {
}, [detailedFunctions, search]);
const filteredDisplayNames = React.useMemo(
- () => filteredFunctions.map(({ displayName }) => displayName),
+ () =>
+ filteredFunctions
+ .map(({ displayName }) => displayName)
+ .filter((displayName): displayName is string => !!displayName),
[filteredFunctions]
);
diff --git a/packages/web/src/routers/AppRouter.tsx b/packages/web/src/routers/AppRouter.tsx
index 0d7407f..9d2992e 100644
--- a/packages/web/src/routers/AppRouter.tsx
+++ b/packages/web/src/routers/AppRouter.tsx
@@ -4,7 +4,7 @@ import {
RouterProvider,
createBrowserRouter,
} from "react-router-dom";
-import ContentLoader from "../components/ContentLoader";
+import ContentLoader from "../components/common/ContentLoader";
import { Text } from "@mantine/core";
const ConversationPage = React.lazy(() => import("../pages/ConversationPage"));
diff --git a/packages/web/src/routers/FunctionsRouter.tsx b/packages/web/src/routers/FunctionsRouter.tsx
index 7817545..dc4db25 100644
--- a/packages/web/src/routers/FunctionsRouter.tsx
+++ b/packages/web/src/routers/FunctionsRouter.tsx
@@ -1,6 +1,6 @@
import React, { Suspense } from "react";
import { Routes, Route, Navigate, useMatches } from "react-router-dom";
-import ContentLoader from "../components/ContentLoader";
+import ContentLoader from "../components/common/ContentLoader";
import { Text } from "@mantine/core";
const FunctionsPage = React.lazy(() => import("../pages/FunctionsPage"));
diff --git a/packages/web/src/store/actions/appSettings/setLastChangelog.ts b/packages/web/src/store/actions/appSettings/setLastChangelog.ts
index e0b4366..b77a5c6 100644
--- a/packages/web/src/store/actions/appSettings/setLastChangelog.ts
+++ b/packages/web/src/store/actions/appSettings/setLastChangelog.ts
@@ -1,7 +1,7 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const setLastChangelog = (value: string) => {
- useAppStore.setState((state) => {
+export const setLastChangelog = createAction(({ set }, value: string) => {
+ set((state) => {
state.lastChangelog = value;
});
-};
+}, "setLastChangelog");
diff --git a/packages/web/src/store/actions/appSettings/toggleColorScheme.ts b/packages/web/src/store/actions/appSettings/toggleColorScheme.ts
index 9a09969..530e433 100644
--- a/packages/web/src/store/actions/appSettings/toggleColorScheme.ts
+++ b/packages/web/src/store/actions/appSettings/toggleColorScheme.ts
@@ -1,8 +1,12 @@
import { ColorScheme } from "@mantine/core";
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const toggleColorScheme = (value?: ColorScheme) => {
- useAppStore.setState(({ colorScheme }) => ({
- colorScheme: value || (colorScheme === "dark" ? "light" : "dark"),
- }));
-};
+export const toggleColorScheme = createAction(
+ ({ set }, value?: ColorScheme) => {
+ set((state) => {
+ state.colorScheme =
+ value || (state.colorScheme === "dark" ? "light" : "dark");
+ });
+ },
+ "toggleColorScheme"
+);
diff --git a/packages/web/src/store/actions/appSettings/toggleShowUsage.ts b/packages/web/src/store/actions/appSettings/toggleShowUsage.ts
index 21e8c16..fc4eae0 100644
--- a/packages/web/src/store/actions/appSettings/toggleShowUsage.ts
+++ b/packages/web/src/store/actions/appSettings/toggleShowUsage.ts
@@ -1,7 +1,7 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const toggleShowUsage = (showUsage?: boolean) => {
- useAppStore.setState((state) => {
+export const toggleShowUsage = createAction(({ set }, showUsage?: boolean) => {
+ set((state) => {
state.showUsage = showUsage ?? !state.showUsage;
});
-};
+}, "toggleShowUsage");
diff --git a/packages/web/src/store/actions/callableFunctions/addCallableFunction.ts b/packages/web/src/store/actions/callableFunctions/addCallableFunction.ts
index fdd560a..776fcce 100644
--- a/packages/web/src/store/actions/callableFunctions/addCallableFunction.ts
+++ b/packages/web/src/store/actions/callableFunctions/addCallableFunction.ts
@@ -1,29 +1,34 @@
import { CallableFunction, CallableFunctionModel } from "gpt-turbo";
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const addCallableFunction = (
- config: CallableFunction | CallableFunctionModel,
- displayName: string,
- code?: string
-) => {
- const callableFunction =
- config instanceof CallableFunction
- ? config
- : CallableFunction.fromJSON(config);
+export const addCallableFunction = createAction(
+ (
+ { set },
+ config: CallableFunction | CallableFunctionModel,
+ displayName: string,
+ code?: string
+ ) => {
+ const callableFunction =
+ config instanceof CallableFunction
+ ? config
+ : CallableFunction.fromJSON(config);
- useAppStore.setState((state) => {
- state.callableFunctions = state.callableFunctions
- .filter((f) => f.id !== callableFunction.id)
- .concat(callableFunction);
+ set((state) => {
+ state.callableFunctions = state.callableFunctions
+ .filter((f) => f.id !== callableFunction.id)
+ .concat(callableFunction);
- state.callableFunctionDisplayNames[callableFunction.id] = displayName;
+ state.callableFunctionDisplayNames[callableFunction.id] =
+ displayName;
- if (code) {
- state.callableFunctionCodes[callableFunction.id] = code;
- } else if (state.callableFunctionCodes[callableFunction.id]) {
- delete state.callableFunctionCodes[callableFunction.id];
- }
- });
+ if (code) {
+ state.callableFunctionCodes[callableFunction.id] = code;
+ } else if (state.callableFunctionCodes[callableFunction.id]) {
+ delete state.callableFunctionCodes[callableFunction.id];
+ }
+ });
- return callableFunction;
-};
+ return callableFunction;
+ },
+ "addCallableFunction"
+);
diff --git a/packages/web/src/store/actions/callableFunctions/callFunction.tsx b/packages/web/src/store/actions/callableFunctions/callFunction.tsx
deleted file mode 100644
index ee7b24c..0000000
--- a/packages/web/src/store/actions/callableFunctions/callFunction.tsx
+++ /dev/null
@@ -1,86 +0,0 @@
-import { notifications } from "@mantine/notifications";
-import { randomId } from "@mantine/hooks";
-import { BiCheck, BiX } from "react-icons/bi";
-import getErrorInfo from "../../../utils/getErrorInfo";
-import { useAppStore } from "../..";
-
-export const callFunction = async (
- id: string,
- args: Record
-) => {
- const callableFunction = useAppStore
- .getState()
- .callableFunctions.find((fn) => fn.id === id);
-
- if (!callableFunction) {
- throw new Error(`Function ${id} not found`);
- }
-
- const displayName =
- useAppStore.getState().callableFunctionDisplayNames[id] ??
- "Unknown Function";
-
- const code = useAppStore.getState().callableFunctionCodes[id];
- if (!code) return undefined;
-
- try {
- const { argNames, argValues } = callableFunction.parameters.reduce(
- (acc, fn) => {
- acc.argNames.push(fn.name);
- acc.argValues.push(args[fn.name] ?? undefined);
- return acc;
- },
- {
- argNames: [],
- argValues: [],
- } as { argNames: string[]; argValues: any[] }
- );
- const fn = new Function(...argNames, code);
-
- const result = fn(...argValues);
-
- if (result instanceof Promise) {
- const notifId = randomId();
- notifications.show({
- id: notifId,
- loading: true,
- title: "Function Call",
- message: `Calling ${displayName}...`,
- autoClose: false,
- withCloseButton: false,
- });
-
- try {
- const awaited = await result;
-
- notifications.update({
- id: notifId,
- color: "green",
- title: "Function Call Success",
- message: `${displayName} called successfully!`,
- icon: ,
- autoClose: 2000,
- });
-
- return awaited;
- } catch (e) {
- notifications.hide(notifId);
- throw e;
- }
- }
-
- return result;
- } catch (e) {
- console.error(e);
- const { message } = getErrorInfo(e);
- notifications.show({
- color: "red",
- title: "Function Call Failed",
- message: `${displayName} failed: ${message}`,
- icon: ,
- autoClose: false,
- withCloseButton: true,
- });
- return undefined;
- }
-};
diff --git a/packages/web/src/store/actions/callableFunctions/deleteCallableFunction.ts b/packages/web/src/store/actions/callableFunctions/deleteCallableFunction.ts
deleted file mode 100644
index 049e218..0000000
--- a/packages/web/src/store/actions/callableFunctions/deleteCallableFunction.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { useAppStore } from "../..";
-
-export const deleteCallableFunction = (id: string) => {
- useAppStore.setState((state) => {
- state.callableFunctions = state.callableFunctions.filter(
- (f) => f.id !== id
- );
- delete state.callableFunctionDisplayNames[id];
- delete state.callableFunctionCodes[id];
- });
-};
diff --git a/packages/web/src/store/actions/callableFunctions/deleteCallableFunction.tsx b/packages/web/src/store/actions/callableFunctions/deleteCallableFunction.tsx
new file mode 100644
index 0000000..361b09a
--- /dev/null
+++ b/packages/web/src/store/actions/callableFunctions/deleteCallableFunction.tsx
@@ -0,0 +1,50 @@
+import { modals } from "@mantine/modals";
+import { Text } from "@mantine/core";
+import { createAction } from "../createAction";
+
+export const deleteCallableFunction = createAction(
+ async ({ set, get }, id: string, showConfirm = true) => {
+ const { callableFunctions, callableFunctionDisplayNames } = get();
+
+ const fn = callableFunctions.find((fn) => fn.id === id);
+ if (!fn) return false;
+
+ const displayName = callableFunctionDisplayNames[fn.id] ?? "[N/A]";
+
+ const onConfirm = () => {
+ set((state) => {
+ state.callableFunctions = state.callableFunctions.filter(
+ (f) => f.id !== id
+ );
+ delete state.callableFunctionDisplayNames[id];
+ delete state.callableFunctionCodes[id];
+ });
+ };
+
+ if (!showConfirm) {
+ onConfirm();
+ return true;
+ }
+
+ return new Promise((resolve) => {
+ modals.openConfirmModal({
+ title: `Delete ${displayName}?`,
+ centered: true,
+ children: (
+
+ Are you sure you want to delete {displayName}? This
+ cannot be undone.
+
+ ),
+ labels: { confirm: "Delete function", cancel: "Cancel" },
+ confirmProps: { color: "red" },
+ onConfirm: () => {
+ onConfirm();
+ resolve(true);
+ },
+ onClose: () => resolve(false),
+ });
+ });
+ },
+ "deleteCallableFunction"
+);
diff --git a/packages/web/src/store/actions/callableFunctions/dismissFunctionsImportWarning.ts b/packages/web/src/store/actions/callableFunctions/dismissFunctionsImportWarning.ts
index 5eb4d96..363e6bc 100644
--- a/packages/web/src/store/actions/callableFunctions/dismissFunctionsImportWarning.ts
+++ b/packages/web/src/store/actions/callableFunctions/dismissFunctionsImportWarning.ts
@@ -1,5 +1,5 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const dismissFunctionsImportWarning = () => {
- useAppStore.setState({ showFunctionsImportWarning: false });
-};
+export const dismissFunctionsImportWarning = createAction(({ set }) => {
+ set({ showFunctionsImportWarning: false });
+}, "dismissFunctionsImportWarning");
diff --git a/packages/web/src/store/actions/callableFunctions/dismissFunctionsWarning.ts b/packages/web/src/store/actions/callableFunctions/dismissFunctionsWarning.ts
index 65ed507..cbc4846 100644
--- a/packages/web/src/store/actions/callableFunctions/dismissFunctionsWarning.ts
+++ b/packages/web/src/store/actions/callableFunctions/dismissFunctionsWarning.ts
@@ -1,5 +1,5 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const dismissFunctionsWarning = () => {
- useAppStore.setState({ showFunctionsWarning: false });
-};
+export const dismissFunctionsWarning = createAction(({ set }) => {
+ set({ showFunctionsWarning: false });
+}, "dismissFunctionsWarning");
diff --git a/packages/web/src/store/actions/callableFunctions/duplicateCallableFunction.tsx b/packages/web/src/store/actions/callableFunctions/duplicateCallableFunction.tsx
new file mode 100644
index 0000000..df5b933
--- /dev/null
+++ b/packages/web/src/store/actions/callableFunctions/duplicateCallableFunction.tsx
@@ -0,0 +1,68 @@
+import { Text } from "@mantine/core";
+import { modals } from "@mantine/modals";
+import { addCallableFunction } from "./addCallableFunction";
+import getUniqueString from "../../../utils/getUniqueString";
+import { createAction } from "../createAction";
+
+export const duplicateCallableFunction = createAction(
+ ({ get }, id: string, withConfirm = true) => {
+ const {
+ callableFunctions,
+ callableFunctionDisplayNames,
+ callableFunctionCodes,
+ } = get();
+
+ const fn = callableFunctions.find((fn) => fn.id === id);
+ if (!fn) return;
+
+ const displayName = callableFunctionDisplayNames[fn.id];
+ if (!displayName) return;
+
+ const copyDisplayName = getUniqueString(
+ displayName,
+ Object.values(callableFunctionDisplayNames),
+ (displayName, i) => `${displayName} (${i})`
+ );
+
+ const copyName = getUniqueString(
+ fn.name,
+ callableFunctions.map((fn) => fn.name),
+ (name, i) => `${name}${i}`
+ );
+
+ const onConfirm = () => {
+ addCallableFunction(
+ {
+ ...fn.toJSON(),
+ id: undefined,
+ name: copyName,
+ },
+ copyDisplayName,
+ callableFunctionCodes[fn.id]
+ );
+ };
+
+ if (!withConfirm) return onConfirm();
+
+ modals.openConfirmModal({
+ title: `Duplicate ${displayName}?`,
+ centered: true,
+ children: (
+
+ This will create a new function with the same config and
+ code, but the display name and function name will appear as{" "}
+
+ {copyDisplayName}
+ {" "}
+ and{" "}
+
+ {copyName}
+
+
+ ),
+ labels: { confirm: "Duplicate function", cancel: "Cancel" },
+ onConfirm,
+ });
+ },
+ "duplicateCallableFunction"
+);
diff --git a/packages/web/src/store/actions/callableFunctions/removeAllCallableFunctions.ts b/packages/web/src/store/actions/callableFunctions/removeAllCallableFunctions.ts
index 3205487..ed63836 100644
--- a/packages/web/src/store/actions/callableFunctions/removeAllCallableFunctions.ts
+++ b/packages/web/src/store/actions/callableFunctions/removeAllCallableFunctions.ts
@@ -1,9 +1,9 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const removeAllCallableFunctions = () => {
- useAppStore.setState((state) => {
+export const removeAllCallableFunctions = createAction(({ set }) => {
+ set((state) => {
state.callableFunctions = [];
state.callableFunctionDisplayNames = {};
state.callableFunctionCodes = {};
});
-};
+}, "removeAllCallableFunctions");
diff --git a/packages/web/src/store/actions/callableFunctions/resetCallableFunctionWarnings.ts b/packages/web/src/store/actions/callableFunctions/resetCallableFunctionWarnings.ts
index 5420ffe..b38757e 100644
--- a/packages/web/src/store/actions/callableFunctions/resetCallableFunctionWarnings.ts
+++ b/packages/web/src/store/actions/callableFunctions/resetCallableFunctionWarnings.ts
@@ -1,8 +1,8 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const resetCallableFunctionWarnings = () => {
- useAppStore.setState((state) => {
+export const resetCallableFunctionWarnings = createAction(({ set }) => {
+ set((state) => {
state.showFunctionsWarning = true;
state.showFunctionsImportWarning = true;
});
-};
+}, "resetCallableFunctionWarnings");
diff --git a/packages/web/src/store/actions/conversations/addConversation.ts b/packages/web/src/store/actions/conversations/addConversation.ts
index 33dd5ee..ff741bf 100644
--- a/packages/web/src/store/actions/conversations/addConversation.ts
+++ b/packages/web/src/store/actions/conversations/addConversation.ts
@@ -3,21 +3,25 @@ import {
ConversationConfigParameters,
RequestOptions,
} from "gpt-turbo";
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const addConversation = (
- conversation: Conversation | ConversationConfigParameters,
- requestOptions?: RequestOptions
-) => {
- const newConversation =
- conversation instanceof Conversation
- ? conversation
- : new Conversation(conversation, requestOptions);
+export const addConversation = createAction(
+ (
+ { set },
+ conversation: Conversation | ConversationConfigParameters,
+ requestOptions?: RequestOptions
+ ) => {
+ const newConversation =
+ conversation instanceof Conversation
+ ? conversation
+ : new Conversation(conversation, requestOptions);
- useAppStore.setState((state) => {
- state.conversations.push(newConversation);
- state.conversationLastEdits.set(newConversation.id, Date.now());
- });
+ set((state) => {
+ state.conversations.push(newConversation);
+ state.conversationLastEdits.set(newConversation.id, Date.now());
+ });
- return newConversation;
-};
+ return newConversation;
+ },
+ "addConversation"
+);
diff --git a/packages/web/src/store/actions/conversations/removeAllConversations.ts b/packages/web/src/store/actions/conversations/removeAllConversations.ts
index d5344e7..45458d0 100644
--- a/packages/web/src/store/actions/conversations/removeAllConversations.ts
+++ b/packages/web/src/store/actions/conversations/removeAllConversations.ts
@@ -1,11 +1,11 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
import { setActiveConversation } from "./setActiveConversation";
-export const removeAllConversations = () => {
- useAppStore.setState((state) => {
+export const removeAllConversations = createAction(({ set }) => {
+ set((state) => {
state.conversations = [];
state.conversationLastEdits = new Map();
state.conversationNames = new Map();
setActiveConversation(null);
});
-};
+}, "removeAllConversations");
diff --git a/packages/web/src/store/actions/conversations/removeConversation.ts b/packages/web/src/store/actions/conversations/removeConversation.ts
index 2a3cb5d..676fc6b 100644
--- a/packages/web/src/store/actions/conversations/removeConversation.ts
+++ b/packages/web/src/store/actions/conversations/removeConversation.ts
@@ -1,8 +1,8 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
import { setActiveConversation } from "./setActiveConversation";
-export const removeConversation = (id: string) => {
- useAppStore.setState((state) => {
+export const removeConversation = createAction(({ set }, id: string) => {
+ set((state) => {
state.conversations = state.conversations.filter(
(conversation) => conversation.id !== id
);
@@ -12,4 +12,4 @@ export const removeConversation = (id: string) => {
setActiveConversation(state.activeConversationId);
});
-};
+}, "removeConversation");
diff --git a/packages/web/src/store/actions/conversations/setActiveConversation.ts b/packages/web/src/store/actions/conversations/setActiveConversation.ts
index cd25732..f91b0ae 100644
--- a/packages/web/src/store/actions/conversations/setActiveConversation.ts
+++ b/packages/web/src/store/actions/conversations/setActiveConversation.ts
@@ -1,22 +1,25 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const setActiveConversation = (id: string | null, force = false) => {
- if (force) {
- useAppStore.setState({ activeConversationId: id });
- return;
- }
- if (!id) {
- useAppStore.setState({ activeConversationId: null });
- return;
- }
+export const setActiveConversation = createAction(
+ ({ get, set }, id: string | null, force = false) => {
+ if (force) {
+ set({ activeConversationId: id });
+ return;
+ }
+ if (!id) {
+ set({ activeConversationId: null });
+ return;
+ }
- const { conversations } = useAppStore.getState();
- const conversation = conversations.find((c) => c.id === id);
+ const { conversations } = get();
+ const conversation = conversations.find((c) => c.id === id);
- if (!conversation) {
- useAppStore.setState({ activeConversationId: null });
- return;
- }
+ if (!conversation) {
+ set({ activeConversationId: null });
+ return;
+ }
- useAppStore.setState({ activeConversationId: id });
-};
+ set({ activeConversationId: id });
+ },
+ "setActiveConversation"
+);
diff --git a/packages/web/src/store/actions/conversations/setConversationLastEdit.ts b/packages/web/src/store/actions/conversations/setConversationLastEdit.ts
index ab63929..47be3ab 100644
--- a/packages/web/src/store/actions/conversations/setConversationLastEdit.ts
+++ b/packages/web/src/store/actions/conversations/setConversationLastEdit.ts
@@ -1,7 +1,10 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const setConversationLastEdit = (id: string, lastEdit = Date.now()) => {
- useAppStore.setState((state) => {
- state.conversationLastEdits.set(id, lastEdit);
- });
-};
+export const setConversationLastEdit = createAction(
+ ({ set }, id: string, lastEdit = Date.now()) => {
+ set((state) => {
+ state.conversationLastEdits.set(id, lastEdit);
+ });
+ },
+ "setConversationLastEdit"
+);
diff --git a/packages/web/src/store/actions/conversations/setConversationName.ts b/packages/web/src/store/actions/conversations/setConversationName.ts
index 428e103..0d6f7ab 100644
--- a/packages/web/src/store/actions/conversations/setConversationName.ts
+++ b/packages/web/src/store/actions/conversations/setConversationName.ts
@@ -1,7 +1,10 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const setConversationName = (id: string, name: string) => {
- useAppStore.setState((state) => {
- state.conversationNames.set(id, name);
- });
-};
+export const setConversationName = createAction(
+ ({ set }, id: string, name: string) => {
+ set((state) => {
+ state.conversationNames.set(id, name);
+ });
+ },
+ "setConversationName"
+);
diff --git a/packages/web/src/store/actions/createAction.ts b/packages/web/src/store/actions/createAction.ts
new file mode 100644
index 0000000..af0e2f7
--- /dev/null
+++ b/packages/web/src/store/actions/createAction.ts
@@ -0,0 +1,49 @@
+import { useAppStore } from "..";
+
+export type AppStoreSet = typeof useAppStore.setState;
+export type AppStoreGet = typeof useAppStore.getState;
+export type AppStoreSubscribe = typeof useAppStore.subscribe;
+export type AppStorePersist = typeof useAppStore.persist;
+
+export interface AppStoreMethods {
+ set: AppStoreSet;
+ get: AppStoreGet;
+ subscribe: AppStoreSubscribe;
+ persist: AppStorePersist;
+}
+
+export type AppStoreAction = (
+ storeMethods: AppStoreMethods,
+ ...args: any[]
+) => any;
+
+export const createAction = <
+ A extends AppStoreAction,
+ P extends any[] = A extends (
+ storeMethods: AppStoreMethods,
+ ...args: infer U
+ ) => any
+ ? U
+ : never,
+ F = (...args: P) => ReturnType,
+>(
+ action: A,
+ actionName: string | undefined | { type: unknown } = action.name ||
+ undefined
+): F => {
+ const set: AppStoreSet = (nextStateOrUpdater, shouldReplace, action) => {
+ return useAppStore.setState(
+ nextStateOrUpdater,
+ shouldReplace,
+ action || actionName
+ );
+ };
+
+ const storeMethods: AppStoreMethods = {
+ set,
+ get: useAppStore.getState,
+ subscribe: useAppStore.subscribe,
+ persist: useAppStore.persist,
+ };
+ return ((...args: P) => action(storeMethods, ...args)) as F;
+};
diff --git a/packages/web/src/store/actions/defaultConversationSettings/resetDefaultSettings.ts b/packages/web/src/store/actions/defaultConversationSettings/resetDefaultSettings.ts
index 0bfb775..73862b0 100644
--- a/packages/web/src/store/actions/defaultConversationSettings/resetDefaultSettings.ts
+++ b/packages/web/src/store/actions/defaultConversationSettings/resetDefaultSettings.ts
@@ -1,9 +1,9 @@
-import { useAppStore } from "../..";
import { initialDefaultConversationSettingsState } from "../../slices/defaultConversationSettingsSlice";
+import { createAction } from "../createAction";
-export const resetDefaultSettings = () => {
- useAppStore.setState((state) => {
+export const resetDefaultSettings = createAction(({ set }) => {
+ set((state) => {
state.defaultSettings =
initialDefaultConversationSettingsState.defaultSettings;
});
-};
+}, "resetDefaultSettings");
diff --git a/packages/web/src/store/actions/defaultConversationSettings/setDefaultSettings.ts b/packages/web/src/store/actions/defaultConversationSettings/setDefaultSettings.ts
index a96ffb7..ec890a4 100644
--- a/packages/web/src/store/actions/defaultConversationSettings/setDefaultSettings.ts
+++ b/packages/web/src/store/actions/defaultConversationSettings/setDefaultSettings.ts
@@ -1,8 +1,11 @@
-import { useAppStore } from "../..";
import { PersistenceDefaultSettings } from "../../../entities/persistenceDefaultSettings";
+import { createAction } from "../createAction";
-export const setDefaultSettings = (settings: PersistenceDefaultSettings) => {
- useAppStore.setState((state) => {
- state.defaultSettings = settings;
- });
-};
+export const setDefaultSettings = createAction(
+ ({ set }, settings: PersistenceDefaultSettings) => {
+ set((state) => {
+ state.defaultSettings = settings;
+ });
+ },
+ "setDefaultSettings"
+);
diff --git a/packages/web/src/store/actions/persistence/addPersistedConversationId.ts b/packages/web/src/store/actions/persistence/addPersistedConversationId.ts
index 7ee728e..21b346f 100644
--- a/packages/web/src/store/actions/persistence/addPersistedConversationId.ts
+++ b/packages/web/src/store/actions/persistence/addPersistedConversationId.ts
@@ -1,7 +1,10 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const addPersistedConversationId = (id: string) => {
- useAppStore.setState((state) => {
- state.persistedConversationIds.push(id);
- });
-};
+export const addPersistedConversationId = createAction(
+ ({ set }, id: string) => {
+ set((state) => {
+ state.persistedConversationIds.push(id);
+ });
+ },
+ "addPersistedConversationId"
+);
diff --git a/packages/web/src/store/actions/savedContexts/removeAllSavedContexts.ts b/packages/web/src/store/actions/savedContexts/removeAllSavedContexts.ts
index 3403f42..6ec1738 100644
--- a/packages/web/src/store/actions/savedContexts/removeAllSavedContexts.ts
+++ b/packages/web/src/store/actions/savedContexts/removeAllSavedContexts.ts
@@ -1,7 +1,7 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const removeAllSavedContexts = () => {
- useAppStore.setState((state) => {
+export const removeAllSavedContexts = createAction(({ set }) => {
+ set((state) => {
state.savedContexts = [];
});
-};
+}, "removeAllSavedContexts");
diff --git a/packages/web/src/store/actions/savedContexts/removeSavedContext.ts b/packages/web/src/store/actions/savedContexts/removeSavedContext.ts
index 4861e41..9138f11 100644
--- a/packages/web/src/store/actions/savedContexts/removeSavedContext.ts
+++ b/packages/web/src/store/actions/savedContexts/removeSavedContext.ts
@@ -1,9 +1,12 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const removeSavedContext = (contextName: string) => {
- useAppStore.setState((state) => {
- state.savedContexts = state.savedContexts.filter(
- (context) => context.name !== contextName
- );
- });
-};
+export const removeSavedContext = createAction(
+ ({ set }, contextName: string) => {
+ set((state) => {
+ state.savedContexts = state.savedContexts.filter(
+ (context) => context.name !== contextName
+ );
+ });
+ },
+ "removeSavedContext"
+);
diff --git a/packages/web/src/store/actions/savedContexts/saveContext.ts b/packages/web/src/store/actions/savedContexts/saveContext.ts
index a737101..f150e6c 100644
--- a/packages/web/src/store/actions/savedContexts/saveContext.ts
+++ b/packages/web/src/store/actions/savedContexts/saveContext.ts
@@ -1,7 +1,10 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const saveContext = (name: string, value: string) => {
- useAppStore.setState((state) => {
- state.savedContexts.push({ name, value });
- });
-};
+export const saveContext = createAction(
+ ({ set }, name: string, value: string) => {
+ set((state) => {
+ state.savedContexts.push({ name, value });
+ });
+ },
+ "saveContext"
+);
diff --git a/packages/web/src/store/actions/savedPrompts/removeAllSavedPrompts.ts b/packages/web/src/store/actions/savedPrompts/removeAllSavedPrompts.ts
index f8c052b..8f1360c 100644
--- a/packages/web/src/store/actions/savedPrompts/removeAllSavedPrompts.ts
+++ b/packages/web/src/store/actions/savedPrompts/removeAllSavedPrompts.ts
@@ -1,7 +1,7 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const removeAllSavedPrompts = () => {
- useAppStore.setState((state) => {
+export const removeAllSavedPrompts = createAction(({ set }) => {
+ set((state) => {
state.savedPrompts = [];
});
-};
+}, "removeAllSavedPrompts");
diff --git a/packages/web/src/store/actions/savedPrompts/removeSavedPrompt.ts b/packages/web/src/store/actions/savedPrompts/removeSavedPrompt.ts
index c2dfb9b..d705b53 100644
--- a/packages/web/src/store/actions/savedPrompts/removeSavedPrompt.ts
+++ b/packages/web/src/store/actions/savedPrompts/removeSavedPrompt.ts
@@ -1,9 +1,9 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const removeSavedPrompt = (promptName: string) => {
- useAppStore.setState((state) => {
+export const removeSavedPrompt = createAction(({ set }, promptName: string) => {
+ set((state) => {
state.savedPrompts = state.savedPrompts.filter(
(prompt) => prompt.name !== promptName
);
});
-};
+}, "removeSavedPrompt");
diff --git a/packages/web/src/store/actions/savedPrompts/savePrompt.ts b/packages/web/src/store/actions/savedPrompts/savePrompt.ts
index d05b8dd..3889031 100644
--- a/packages/web/src/store/actions/savedPrompts/savePrompt.ts
+++ b/packages/web/src/store/actions/savedPrompts/savePrompt.ts
@@ -1,7 +1,10 @@
-import { useAppStore } from "../..";
+import { createAction } from "../createAction";
-export const savePrompt = (name: string, value: string) => {
- useAppStore.setState((state) => {
- state.savedPrompts.push({ name, value });
- });
-};
+export const savePrompt = createAction(
+ ({ set }, name: string, value: string) => {
+ set((state) => {
+ state.savedPrompts.push({ name, value });
+ });
+ },
+ "savePrompt"
+);
diff --git a/packages/web/src/store/hooks/callableFunctions/useCallFunction.tsx b/packages/web/src/store/hooks/callableFunctions/useCallFunction.tsx
new file mode 100644
index 0000000..e631e8b
--- /dev/null
+++ b/packages/web/src/store/hooks/callableFunctions/useCallFunction.tsx
@@ -0,0 +1,89 @@
+import React from "react";
+import { useGetFunction } from "./useGetFunction";
+import { useGetFunctionDisplayName } from "./useGetFunctionDisplayName";
+import { useGetFunctionCode } from "./useGetFunctionCode";
+import { randomId } from "@mantine/hooks";
+import { notifications } from "@mantine/notifications";
+import { BiCheck, BiX } from "react-icons/bi";
+import getErrorInfo from "../../../utils/getErrorInfo";
+
+export const useCallFunction = () => {
+ const getFunction = useGetFunction();
+ const getDisplayName = useGetFunctionDisplayName();
+ const getCode = useGetFunctionCode();
+
+ return React.useCallback(
+ async (id: string, args: Record) => {
+ const callableFunction = getFunction(id);
+ if (!callableFunction) return undefined;
+
+ const code = getCode(id);
+ if (!code) return undefined;
+
+ const displayName = getDisplayName(id) ?? "[N/A]";
+
+ try {
+ const { argNames, argValues } =
+ callableFunction.parameters.reduce(
+ (acc, param) => {
+ acc.argNames.push(param.name);
+ acc.argValues.push(args[param.name] ?? undefined);
+ return acc;
+ },
+ {
+ argNames: [],
+ argValues: [],
+ } as { argNames: string[]; argValues: any[] }
+ );
+ const fn = new Function(...argNames, code);
+
+ const result = fn(...argValues);
+
+ if (result instanceof Promise) {
+ const notifId = randomId();
+ notifications.show({
+ id: notifId,
+ loading: true,
+ title: "Function Call",
+ message: `Calling ${displayName}...`,
+ autoClose: false,
+ withCloseButton: false,
+ });
+
+ try {
+ const awaited = await result;
+
+ notifications.update({
+ id: notifId,
+ color: "green",
+ title: "Function Call Success",
+ message: `${displayName} called successfully!`,
+ icon: ,
+ autoClose: 2000,
+ });
+
+ return awaited;
+ } catch (e) {
+ notifications.hide(notifId);
+ throw e;
+ }
+ }
+
+ return result;
+ } catch (e) {
+ console.error(e);
+ const { message } = getErrorInfo(e);
+ notifications.show({
+ color: "red",
+ title: "Function Call Failed",
+ message: `${displayName} failed: ${message}`,
+ icon: ,
+ autoClose: false,
+ withCloseButton: true,
+ });
+ return undefined;
+ }
+ },
+ [getCode, getDisplayName, getFunction]
+ );
+};
diff --git a/packages/web/src/store/hooks/callableFunctions/useGetFunction.ts b/packages/web/src/store/hooks/callableFunctions/useGetFunction.ts
new file mode 100644
index 0000000..92977ab
--- /dev/null
+++ b/packages/web/src/store/hooks/callableFunctions/useGetFunction.ts
@@ -0,0 +1,14 @@
+import React from "react";
+import { useAppStore } from "../..";
+
+export const useGetFunction = () => {
+ const functions = useAppStore((state) => state.callableFunctions);
+
+ return React.useCallback(
+ (id: string) => {
+ const callableFunction = functions.find((fn) => fn.id === id);
+ return callableFunction;
+ },
+ [functions]
+ );
+};
diff --git a/packages/web/src/store/hooks/callableFunctions/useGetFunctionCode.ts b/packages/web/src/store/hooks/callableFunctions/useGetFunctionCode.ts
new file mode 100644
index 0000000..e4a8dd1
--- /dev/null
+++ b/packages/web/src/store/hooks/callableFunctions/useGetFunctionCode.ts
@@ -0,0 +1,13 @@
+import React from "react";
+import { useAppStore } from "../..";
+
+export const useGetFunctionCode = () => {
+ const codes = useAppStore((state) => state.callableFunctionCodes);
+
+ return React.useCallback(
+ (id: string): string | undefined => {
+ return codes[id];
+ },
+ [codes]
+ );
+};
diff --git a/packages/web/src/store/hooks/callableFunctions/useGetFunctionDisplayName.ts b/packages/web/src/store/hooks/callableFunctions/useGetFunctionDisplayName.ts
new file mode 100644
index 0000000..4b632ce
--- /dev/null
+++ b/packages/web/src/store/hooks/callableFunctions/useGetFunctionDisplayName.ts
@@ -0,0 +1,16 @@
+import React from "react";
+import { useAppStore } from "../..";
+
+export const useGetFunctionDisplayName = () => {
+ const displayNames = useAppStore(
+ (state) => state.callableFunctionDisplayNames
+ );
+
+ return React.useCallback(
+ (id: string): string | undefined => {
+ const displayName = displayNames[id];
+ return displayName;
+ },
+ [displayNames]
+ );
+};
diff --git a/packages/web/src/store/hooks/callableFunctions/useGetUniqueFunctionDisplayName.ts b/packages/web/src/store/hooks/callableFunctions/useGetUniqueFunctionDisplayName.ts
new file mode 100644
index 0000000..27c29cf
--- /dev/null
+++ b/packages/web/src/store/hooks/callableFunctions/useGetUniqueFunctionDisplayName.ts
@@ -0,0 +1,24 @@
+import React from "react";
+import { useAppStore } from "../..";
+import getUniqueString from "../../../utils/getUniqueString";
+
+export const useGetUniqueFunctionDisplayName = () => {
+ const callableFunctionDisplayNames = useAppStore(
+ (state) => state.callableFunctionDisplayNames
+ );
+
+ return React.useCallback(
+ (displayName: string, extraDisplayNames: string[] = []) => {
+ const usedDisplayNames = [
+ ...Object.values(callableFunctionDisplayNames),
+ ...extraDisplayNames,
+ ];
+ return getUniqueString(
+ displayName,
+ usedDisplayNames,
+ (str, i) => `${str} (${i})`
+ );
+ },
+ [callableFunctionDisplayNames]
+ );
+};
diff --git a/packages/web/src/store/hooks/callableFunctions/useGetUniqueFunctionName.ts b/packages/web/src/store/hooks/callableFunctions/useGetUniqueFunctionName.ts
new file mode 100644
index 0000000..55846c1
--- /dev/null
+++ b/packages/web/src/store/hooks/callableFunctions/useGetUniqueFunctionName.ts
@@ -0,0 +1,20 @@
+import React from "react";
+import { useAppStore } from "../..";
+import getUniqueString from "../../../utils/getUniqueString";
+
+export const useGetUniqueFunctionName = () => {
+ const callableFunctions = useAppStore((state) => state.callableFunctions);
+ const names = React.useMemo(
+ () =>
+ callableFunctions.map((callableFunction) => callableFunction.name),
+ [callableFunctions]
+ );
+
+ return React.useCallback(
+ (name: string, extraNames: string[] = []) => {
+ const usedNames = [...names, ...extraNames];
+ return getUniqueString(name, usedNames, (n, i) => `${n}${i}`);
+ },
+ [names]
+ );
+};
diff --git a/packages/web/src/store/hooks/conversations/useActiveConversation.ts b/packages/web/src/store/hooks/conversations/useActiveConversation.ts
new file mode 100644
index 0000000..7773cbd
--- /dev/null
+++ b/packages/web/src/store/hooks/conversations/useActiveConversation.ts
@@ -0,0 +1,16 @@
+import React from "react";
+import { shallow } from "zustand/shallow";
+import { useAppStore } from "../..";
+
+export const useActiveConversation = () => {
+ const [conversations, activeConversationId] = useAppStore(
+ (state) => [state.conversations, state.activeConversationId],
+ shallow
+ );
+
+ return React.useMemo(() => {
+ return conversations.find(
+ (conversation) => conversation.id === activeConversationId
+ );
+ }, [activeConversationId, conversations]);
+};
diff --git a/packages/web/src/store/hooks/conversations/useGetConversationLastEdit.ts b/packages/web/src/store/hooks/conversations/useGetConversationLastEdit.ts
new file mode 100644
index 0000000..7167069
--- /dev/null
+++ b/packages/web/src/store/hooks/conversations/useGetConversationLastEdit.ts
@@ -0,0 +1,13 @@
+import React from "react";
+import { useAppStore } from "../..";
+
+export const useGetConversationLastEdit = () => {
+ const conversationLastEdits = useAppStore(
+ (state) => state.conversationLastEdits
+ );
+
+ return React.useCallback(
+ (id: string) => conversationLastEdits.get(id),
+ [conversationLastEdits]
+ );
+};
diff --git a/packages/web/src/store/hooks/conversations/useGetConversationName.ts b/packages/web/src/store/hooks/conversations/useGetConversationName.ts
new file mode 100644
index 0000000..f5399fd
--- /dev/null
+++ b/packages/web/src/store/hooks/conversations/useGetConversationName.ts
@@ -0,0 +1,11 @@
+import React from "react";
+import { useAppStore } from "../..";
+
+export const useGetConversationName = () => {
+ const conversationNames = useAppStore((state) => state.conversationNames);
+
+ return React.useCallback(
+ (id: string) => conversationNames.get(id),
+ [conversationNames]
+ );
+};
diff --git a/packages/web/src/store/index.ts b/packages/web/src/store/index.ts
index 94aae0d..264206b 100644
--- a/packages/web/src/store/index.ts
+++ b/packages/web/src/store/index.ts
@@ -58,7 +58,7 @@ export type AppStateSlice = StateCreator<
[
["zustand/persist", AppPersistedState],
["zustand/immer", never],
- ["zustand/devtools", never]
+ ["zustand/devtools", never],
],
[],
T
diff --git a/packages/web/src/store/persist/migrateOldData.ts b/packages/web/src/store/persist/migrateOldData.ts
index 891c2b0..754157a 100644
--- a/packages/web/src/store/persist/migrateOldData.ts
+++ b/packages/web/src/store/persist/migrateOldData.ts
@@ -1,13 +1,5 @@
import { notifications } from "@mantine/notifications";
import { CallableFunction, Conversation } from "gpt-turbo";
-import { addConversation } from "../actions/conversations/addConversation";
-import { setConversationName } from "../actions/conversations/setConversationName";
-import { setConversationLastEdit } from "../actions/conversations/setConversationLastEdit";
-import { addCallableFunction } from "../actions/callableFunctions/addCallableFunction";
-import { saveContext } from "../actions/savedContexts/saveContext";
-import { savePrompt } from "../actions/savedPrompts/savePrompt";
-import { setDefaultSettings } from "../actions/defaultConversationSettings/setDefaultSettings";
-import { addPersistedConversationId } from "../actions/persistence/addPersistedConversationId";
const notify = (
title: string,
@@ -28,6 +20,31 @@ const notify = (
// TODO: Remove this after a while. This is to migrate users from the old persistence system to the new one.
// Not EVERYTHING is migrated, but the most important things are.
export const migrateOldData = async () => {
+ // Wait a second to make sure the store is initialized
+ await new Promise((resolve) => setTimeout(resolve, 1000));
+ const { addConversation } = await import(
+ "../actions/conversations/addConversation"
+ );
+ const { setConversationName } = await import(
+ "../actions/conversations/setConversationName"
+ );
+ const { setConversationLastEdit } = await import(
+ "../actions/conversations/setConversationLastEdit"
+ );
+ const { addCallableFunction } = await import(
+ "../actions/callableFunctions/addCallableFunction"
+ );
+ const { saveContext } = await import(
+ "../actions/savedContexts/saveContext"
+ );
+ const { savePrompt } = await import("../actions/savedPrompts/savePrompt");
+ const { setDefaultSettings } = await import(
+ "../actions/defaultConversationSettings/setDefaultSettings"
+ );
+ const { addPersistedConversationId } = await import(
+ "../actions/persistence/addPersistedConversationId"
+ );
+
const oldPersistence = localStorage.getItem("gpt-turbo-persistence");
const oldSettings = localStorage.getItem("gpt-turbo-settings");
diff --git a/packages/web/src/store/persist/onStoreRehydrate.tsx b/packages/web/src/store/persist/onStoreRehydrate.tsx
index 48e2772..2fcd7af 100644
--- a/packages/web/src/store/persist/onStoreRehydrate.tsx
+++ b/packages/web/src/store/persist/onStoreRehydrate.tsx
@@ -1,7 +1,7 @@
import { modals } from "@mantine/modals";
import { AppState } from "..";
import { Text } from "@mantine/core";
-import StorageLoadError from "../../components/StorageLoadError";
+import StorageLoadError from "../../components/error-handling/StorageLoadError";
import { STORAGE_PERSISTENCE_KEY } from "../../config/constants";
import { StoreMigrationError } from "./migrations";
import getErrorInfo from "../../utils/getErrorInfo";
diff --git a/packages/web/src/store/persist/partializeStore.ts b/packages/web/src/store/persist/partializeStore.ts
index c668696..e3b3f7c 100644
--- a/packages/web/src/store/persist/partializeStore.ts
+++ b/packages/web/src/store/persist/partializeStore.ts
@@ -1,4 +1,5 @@
import { AppPersistedState, AppState } from "..";
+import { DEFAULT_CONVERSATION_NAME } from "../../config/constants";
import { persistenceSchema } from "../../entities/persistence";
export const partializeStore = (state: AppState): AppPersistedState => {
@@ -32,7 +33,9 @@ export const partializeStore = (state: AppState): AppPersistedState => {
.map((c) => {
const lastEdited =
state.conversationLastEdits.get(c.id) ?? Date.now();
- const name = state.conversationNames.get(c.id) ?? "New Chat";
+ const name =
+ state.conversationNames.get(c.id) ??
+ DEFAULT_CONVERSATION_NAME;
return {
...c.toJSON(),
lastEdited,
diff --git a/packages/web/src/store/persist/triggerPersist.ts b/packages/web/src/store/persist/triggerPersist.ts
index 66e7d08..47c948c 100644
--- a/packages/web/src/store/persist/triggerPersist.ts
+++ b/packages/web/src/store/persist/triggerPersist.ts
@@ -1,14 +1,14 @@
-import { useAppStore } from "..";
import { STORAGE_PERSISTENCE_KEY } from "../../config/constants";
+import { createAction } from "../actions/createAction";
import { storeVersion } from "./migrations";
import { partializeStore } from "./partializeStore";
import { storeStorage } from "./storeStorage";
-export const persistStore = () => {
- const state = useAppStore.getState();
+export const persistStore = createAction(({ get }) => {
+ const state = get();
const persistedState = partializeStore(state);
storeStorage.setItem(STORAGE_PERSISTENCE_KEY, {
state: persistedState,
version: storeVersion,
});
-};
+}, "persistStore");
diff --git a/packages/web/src/utils/getUniqueString.ts b/packages/web/src/utils/getUniqueString.ts
new file mode 100644
index 0000000..fe03ec4
--- /dev/null
+++ b/packages/web/src/utils/getUniqueString.ts
@@ -0,0 +1,12 @@
+export default (
+ str: string,
+ otherStrs: string[],
+ transform: (str: string, i: number) => string
+) => {
+ let i = 1;
+ let uniqueStr = str;
+ while (otherStrs.some((name) => name === uniqueStr)) {
+ uniqueStr = transform(str, i++);
+ }
+ return uniqueStr;
+};
diff --git a/packages/web/vite.config.ts b/packages/web/vite.config.ts
index 4a6904b..ace978a 100644
--- a/packages/web/vite.config.ts
+++ b/packages/web/vite.config.ts
@@ -49,6 +49,41 @@ export default defineConfig({
define: {
APP_VERSION: JSON.stringify(process.env.npm_package_version),
},
+ build: {
+ rollupOptions: {
+ output: {
+ manualChunks: {
+ "mantine-core": [
+ "@mantine/core",
+ "@mantine/hooks",
+ "@emotion/react",
+ ],
+ "mantine-dropzone": ["@mantine/dropzone"],
+ "mantine-form": ["@mantine/form"],
+ "mantine-modals": ["@mantine/modals"],
+ "mantine-notifications": ["@mantine/notifications"],
+ "mantine-prism": ["@mantine/prism"],
+ "mantine-tiptap": [
+ "@tiptap/extension-code-block-lowlight",
+ "@tiptap/extension-link",
+ "@tiptap/react",
+ "@tiptap/starter-kit",
+ "@mantine/tiptap",
+ "@tabler/icons-react",
+ "lowlight",
+ ],
+ "gpt-turbo": ["gpt-turbo"],
+ react: ["react"],
+ "react-dom": ["react-dom"],
+ "react-icons": ["react-icons"],
+ "react-router-dom": ["react-router-dom"],
+ uuid: ["uuid"],
+ zod: ["zod"],
+ zustand: ["zustand"],
+ },
+ },
+ },
+ },
server: {
port: 3000,
host: true,