mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Cleanup Stores. [server]
This commit is contained in:
@@ -17,16 +17,16 @@ import { Brand } from '~/common/app.config';
|
||||
import { ROUTE_APP_CHAT, ROUTE_INDEX } from '~/common/app.routes';
|
||||
|
||||
// apps access
|
||||
import { incrementalNewsVersion, useAppNewsStateStore } from '../../src/apps/news/news.version';
|
||||
import { incrementalNewsVersion } from '../../src/apps/news/news.version';
|
||||
|
||||
// capabilities access
|
||||
import { useCapabilityBrowserSpeechRecognition, useCapabilityElevenLabs, useCapabilityTextToImage } from '~/common/components/useCapabilities';
|
||||
|
||||
// stores access
|
||||
import { getLLMsDebugInfo } from '~/common/stores/llms/store-llms';
|
||||
import { useAppStateStore } from '~/common/state/store-appstate';
|
||||
import { useChatStore } from '~/common/stores/chat/store-chats';
|
||||
import { useFolderStore } from '~/common/state/store-folders';
|
||||
import { useFolderStore } from '~/common/stores/folders/store-chat-folders';
|
||||
import { useLogicSherpaStore } from '~/common/logic/store-logic-sherpa';
|
||||
import { useUXLabsStore } from '~/common/state/store-ux-labs';
|
||||
|
||||
// utils access
|
||||
@@ -81,8 +81,7 @@ function AppDebug() {
|
||||
const chatsCount = useChatStore.getState().conversations?.length;
|
||||
const uxLabsExperiments = Object.entries(useUXLabsStore.getState()).filter(([_k, v]) => v === true).map(([k, _]) => k).join(', ');
|
||||
const { folders, enableFolders } = useFolderStore.getState();
|
||||
const { lastSeenNewsVersion } = useAppNewsStateStore.getState();
|
||||
const { usageCount } = useAppStateStore.getState();
|
||||
const { lastSeenNewsVersion, usageCount } = useLogicSherpaStore.getState();
|
||||
|
||||
// derived state
|
||||
const cClient = {
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as React from 'react';
|
||||
import { Alert, Box, Button, Typography } from '@mui/joy';
|
||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||
|
||||
import { setComposerStartupText } from '../../src/apps/chat/components/composer/store-composer';
|
||||
import { setComposerStartupText } from '~/common/logic/store-logic-sherpa';
|
||||
|
||||
import { callBrowseFetchPage } from '~/modules/browse/browse.client';
|
||||
|
||||
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { AppNews } from '../src/apps/news/AppNews';
|
||||
import { markNewsAsSeen } from '../src/apps/news/news.version';
|
||||
|
||||
import { markNewsAsSeen } from '~/common/logic/store-logic-sherpa';
|
||||
import { withNextJSPerPageLayout } from '~/common/layout/withLayout';
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Box, Button, Typography } from '@mui/joy';
|
||||
|
||||
import { BeamStoreApi, useBeamStore } from '~/modules/beam/store-beam.hooks';
|
||||
import { BeamView } from '~/modules/beam/BeamView';
|
||||
import { createBeamVanillaStore } from '~/modules/beam/store-beam-vanilla';
|
||||
import { createBeamVanillaStore } from '~/modules/beam/store-beam_vanilla';
|
||||
|
||||
import { OptimaToolbarIn } from '~/common/layout/optima/portals/OptimaPortalsIn';
|
||||
import { createDConversation, DConversation } from '~/common/stores/chat/chat.conversation';
|
||||
|
||||
@@ -32,7 +32,7 @@ import { getConversation, getConversationSystemPurposeId, useConversation } from
|
||||
import { optimaActions, optimaOpenModels, optimaOpenPreferences, useSetOptimaAppMenu } from '~/common/layout/optima/useOptima';
|
||||
import { themeBgAppChatComposer } from '~/common/app.theme';
|
||||
import { useChatLLM } from '~/common/stores/llms/llms.hooks';
|
||||
import { useFolderStore } from '~/common/state/store-folders';
|
||||
import { useFolderStore } from '~/common/stores/folders/store-chat-folders';
|
||||
import { useGlobalShortcuts } from '~/common/components/shortcuts/useGlobalShortcuts';
|
||||
import { useIsMobile, useIsTallScreen } from '~/common/components/useMatchMedia';
|
||||
import { useOverlayComponents } from '~/common/layout/overlays/useOverlayComponents';
|
||||
|
||||
@@ -20,7 +20,7 @@ import { openFileForAttaching } from '~/common/components/ButtonAttachFiles';
|
||||
import { optimaOpenPreferences } from '~/common/layout/optima/useOptima';
|
||||
import { useBrowserTranslationWarning } from '~/common/components/useIsBrowserTranslating';
|
||||
import { useCapabilityElevenLabs } from '~/common/components/useCapabilities';
|
||||
import { useChatOverlayStore } from '~/common/chat-overlay/store-chat-overlay';
|
||||
import { useChatOverlayStore } from '~/common/chat-overlay/store-perchat_vanilla';
|
||||
import { useScrollToBottom } from '~/common/scroll-to-bottom/useScrollToBottom';
|
||||
|
||||
import { ChatMessage, ChatMessageMemo } from './message/ChatMessage';
|
||||
|
||||
@@ -9,7 +9,7 @@ import VerticalSplitOutlinedIcon from '@mui/icons-material/VerticalSplitOutlined
|
||||
|
||||
import { ScaledTextBlockRenderer } from '~/modules/blocks/ScaledTextBlockRenderer';
|
||||
|
||||
import type { DEphemeral } from '~/common/chat-overlay/store-ephemeralsoverlay-slice';
|
||||
import type { DEphemeral } from '~/common/chat-overlay/store-perchat_ephemerals_slice';
|
||||
import { ConversationHandler } from '~/common/chat-overlay/ConversationHandler';
|
||||
import { adjustContentScaling, ContentScaling, lineHeightChatTextMd } from '~/common/app.theme';
|
||||
import { useUIPreferencesStore } from '~/common/state/store-ui';
|
||||
|
||||
@@ -41,8 +41,8 @@ import { lineHeightTextareaMd } from '~/common/app.theme';
|
||||
import { optimaOpenPreferences } from '~/common/layout/optima/useOptima';
|
||||
import { platformAwareKeystrokes } from '~/common/components/KeyStroke';
|
||||
import { supportsScreenCapture } from '~/common/util/screenCaptureUtils';
|
||||
import { useAppStateStore } from '~/common/state/store-appstate';
|
||||
import { useChatComposerOverlayStore } from '~/common/chat-overlay/store-chat-overlay';
|
||||
import { useChatComposerOverlayStore } from '~/common/chat-overlay/store-perchat_vanilla';
|
||||
import { useComposerStartupText, useLogicSherpaStore } from '~/common/logic/store-logic-sherpa';
|
||||
import { useDebouncer } from '~/common/components/useDebouncer';
|
||||
import { useOverlayComponents } from '~/common/layout/overlays/useOverlayComponents';
|
||||
import { useUICounter, useUIPreferencesStore } from '~/common/state/store-ui';
|
||||
@@ -75,7 +75,6 @@ import { StatusBar } from '../StatusBar';
|
||||
import { TokenBadgeMemo } from './tokens/TokenBadge';
|
||||
import { TokenProgressbarMemo } from './tokens/TokenProgressbar';
|
||||
import { useComposerDragDrop } from './useComposerDragDrop';
|
||||
import { useComposerStartupText } from './store-composer';
|
||||
|
||||
|
||||
const zIndexComposerOverlayMic = 10;
|
||||
@@ -124,7 +123,7 @@ export function Composer(props: {
|
||||
labsShowCost: state.labsShowCost,
|
||||
labsShowShortcutBar: state.labsShowShortcutBar,
|
||||
})));
|
||||
const timeToShowTips = useAppStateStore(state => state.usageCount >= 5);
|
||||
const timeToShowTips = useLogicSherpaStore(state => state.usageCount >= 5);
|
||||
const { novel: explainShiftEnter, touch: touchShiftEnter } = useUICounter('composer-shift-enter');
|
||||
const { novel: explainAltEnter, touch: touchAltEnter } = useUICounter('composer-alt-enter');
|
||||
const { novel: explainCtrlEnter, touch: touchCtrlEnter } = useUICounter('composer-ctrl-enter');
|
||||
|
||||
@@ -23,7 +23,7 @@ import { showImageDataURLInNewTab } from '~/common/util/imageUtils';
|
||||
import { useUIPreferencesStore } from '~/common/state/store-ui';
|
||||
|
||||
import type { AttachmentDraftId } from '~/common/attachment-drafts/attachment.types';
|
||||
import type { AttachmentDraftsStoreApi } from '~/common/attachment-drafts/store-attachment-drafts-slice';
|
||||
import type { AttachmentDraftsStoreApi } from '~/common/attachment-drafts/store-perchat-attachment-drafts_slice';
|
||||
import type { LLMAttachmentDraft } from './useLLMAttachmentDrafts';
|
||||
import type { LLMAttachmentDraftsAction } from './LLMAttachmentsList';
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import { ConfirmationModal } from '~/common/components/modals/ConfirmationModal'
|
||||
import { useOverlayComponents } from '~/common/layout/overlays/useOverlayComponents';
|
||||
|
||||
import type { AttachmentDraftId } from '~/common/attachment-drafts/attachment.types';
|
||||
import type { AttachmentDraftsStoreApi } from '~/common/attachment-drafts/store-attachment-drafts-slice';
|
||||
import type { AttachmentDraftsStoreApi } from '~/common/attachment-drafts/store-perchat-attachment-drafts_slice';
|
||||
import type { DMessageImageRefPart } from '~/common/stores/chat/chat.fragments';
|
||||
|
||||
import { ViewImageRefPartModal } from '../../message/fragments-content/ViewImageRefPartModal';
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
|
||||
/// Composer Store
|
||||
|
||||
interface ComposerStore {
|
||||
|
||||
startupText: string | null; // if not null, the composer will load this text at startup
|
||||
setStartupText: (text: string | null) => void;
|
||||
|
||||
}
|
||||
|
||||
const useComposerStore = create<ComposerStore>()(
|
||||
persist((set, _get) => ({
|
||||
|
||||
startupText: null,
|
||||
setStartupText: (text: string | null) => set({ startupText: text }),
|
||||
|
||||
}),
|
||||
{
|
||||
name: 'app-composer',
|
||||
version: 1,
|
||||
}),
|
||||
);
|
||||
|
||||
export const setComposerStartupText = (text: string | null) =>
|
||||
useComposerStore.getState().setStartupText(text);
|
||||
|
||||
export const useComposerStartupText = (): [string | null, (text: string | null) => void] => {
|
||||
const text = useComposerStore(state => state.startupText);
|
||||
return [text, useComposerStore.getState().setStartupText];
|
||||
};
|
||||
@@ -5,7 +5,7 @@ import FolderIcon from '@mui/icons-material/Folder';
|
||||
|
||||
import { DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
import { OptimaBarDropdownMemo, OptimaDropdownItems } from '~/common/layout/optima/bar/OptimaBarDropdown';
|
||||
import { useFolderStore } from '~/common/state/store-folders';
|
||||
import { useFolderStore } from '~/common/stores/folders/store-chat-folders';
|
||||
|
||||
|
||||
export const ClearFolderText = 'No Folder';
|
||||
|
||||
@@ -16,7 +16,7 @@ import StarOutlineRoundedIcon from '@mui/icons-material/StarOutlineRounded';
|
||||
|
||||
import type { DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
import { CloseableMenu } from '~/common/components/CloseableMenu';
|
||||
import { DFolder, useFolderStore } from '~/common/state/store-folders';
|
||||
import { DFolder, useFolderStore } from '~/common/stores/folders/store-chat-folders';
|
||||
import { DebouncedInputMemo } from '~/common/components/DebouncedInput';
|
||||
import { FoldersToggleOff } from '~/common/components/icons/FoldersToggleOff';
|
||||
import { FoldersToggleOn } from '~/common/components/icons/FoldersToggleOn';
|
||||
|
||||
@@ -17,7 +17,7 @@ import { SystemPurposeId, SystemPurposes } from '../../../../data';
|
||||
import { autoConversationTitle } from '~/modules/aifn/autotitle/autoTitle';
|
||||
|
||||
import type { DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
import type { DFolder } from '~/common/state/store-folders';
|
||||
import type { DFolder } from '~/common/stores/folders/store-chat-folders';
|
||||
import { ANIM_BUSY_TYPING } from '~/common/util/dMessageUtils';
|
||||
import { InlineTextarea } from '~/common/components/InlineTextarea';
|
||||
import { isDeepEqual } from '~/common/util/hooks/useDeep';
|
||||
|
||||
@@ -5,7 +5,7 @@ import AddIcon from '@mui/icons-material/Add';
|
||||
import FolderIcon from '@mui/icons-material/Folder';
|
||||
|
||||
import { InlineTextarea } from '~/common/components/InlineTextarea';
|
||||
import { getRotatingFolderColor, useFolderStore } from '~/common/state/store-folders';
|
||||
import { getRotatingFolderColor, useFolderStore } from '~/common/stores/folders/store-chat-folders';
|
||||
|
||||
|
||||
export function AddFolderButton() {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { List, ListItem, ListItemButton, ListItemDecorator, Sheet } from '@mui/j
|
||||
import FolderIcon from '@mui/icons-material/Folder';
|
||||
|
||||
import { ContentScaling, themeScalingMap } from '~/common/app.theme';
|
||||
import { DFolder, useFolderStore } from '~/common/state/store-folders';
|
||||
import { DFolder, useFolderStore } from '~/common/stores/folders/store-chat-folders';
|
||||
import { StrictModeDroppable } from '~/common/components/StrictModeDroppable';
|
||||
|
||||
import { AddFolderButton } from './AddFolderButton';
|
||||
|
||||
@@ -10,7 +10,7 @@ import FolderIcon from '@mui/icons-material/Folder';
|
||||
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||
|
||||
import { CloseableMenu } from '~/common/components/CloseableMenu';
|
||||
import { DFolder, FOLDERS_COLOR_PALETTE, useFolderStore } from '~/common/state/store-folders';
|
||||
import { DFolder, FOLDERS_COLOR_PALETTE, useFolderStore } from '~/common/stores/folders/store-chat-folders';
|
||||
import { InlineTextarea } from '~/common/components/InlineTextarea';
|
||||
import { themeZIndexOverMobileDrawer } from '~/common/app.theme';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import type { DFolder } from '~/common/state/store-folders';
|
||||
import type { DFolder } from '~/common/stores/folders/store-chat-folders';
|
||||
import { DMessage, DMessageUserFlag, MESSAGE_FLAG_STARRED, messageFragmentsReduceText, messageHasUserFlag, messageUserFlagToEmoji } from '~/common/stores/chat/chat.message';
|
||||
import { conversationTitle, DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
import { getLocalMidnightInUTCTimestamp, getTimeBucketEn } from '~/common/util/timeUtils';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { Box, Button, Card, CardContent, Divider, Input, Typography } from '@mui/joy';
|
||||
import WarningRoundedIcon from '@mui/icons-material/WarningRounded';
|
||||
|
||||
import { forgetChatLinkItem, useSharedChatLinkItems } from '~/modules/trade/link/store-link';
|
||||
import { forgetChatLinkItem, useSharedChatLinkItems } from '~/modules/trade/link/store-share-link';
|
||||
|
||||
import { Brand } from '~/common/app.config';
|
||||
import { ConfirmationModal } from '~/common/components/modals/ConfirmationModal';
|
||||
|
||||
@@ -4,7 +4,7 @@ import TimeAgo from 'react-timeago';
|
||||
import { Box, ListDivider, ListItem, ListItemButton, ListItemDecorator, Switch, Typography } from '@mui/joy';
|
||||
import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline';
|
||||
|
||||
import type { SharedChatLinkItem } from '~/modules/trade/link/store-link';
|
||||
import type { SharedChatLinkItem } from '~/modules/trade/link/store-share-link';
|
||||
|
||||
import { Link } from '~/common/components/Link';
|
||||
import { OptimaDrawerHeader } from '~/common/layout/optima/drawer/OptimaDrawerHeader';
|
||||
|
||||
@@ -1,49 +1,4 @@
|
||||
// NOTE: this is a separate file to help with bundle tracing, as it's included by the ProviderBootstrapLogic (i.e. by All pages)
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
import { useAppStateStore } from '~/common/state/store-appstate';
|
||||
|
||||
|
||||
// update this variable every time you want to broadcast a new version to clients
|
||||
export const incrementalNewsVersion: number = 16.1; // not notifying for 1.16.8
|
||||
|
||||
|
||||
interface NewsState {
|
||||
lastSeenNewsVersion: number;
|
||||
}
|
||||
|
||||
export const useAppNewsStateStore = create<NewsState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
lastSeenNewsVersion: 0,
|
||||
}),
|
||||
{
|
||||
name: 'app-news',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
export function shallRedirectToNews() {
|
||||
const { lastSeenNewsVersion } = useAppNewsStateStore.getState();
|
||||
const { usageCount } = useAppStateStore.getState();
|
||||
const isNewsOutdated = (lastSeenNewsVersion || 0) < incrementalNewsVersion;
|
||||
return isNewsOutdated && usageCount > 2;
|
||||
}
|
||||
|
||||
export function markNewsAsSeen() {
|
||||
useAppNewsStateStore.setState({ lastSeenNewsVersion: incrementalNewsVersion });
|
||||
}
|
||||
|
||||
|
||||
// NOTE: moved to the ProviderBootstrapLogic, and to the functions above - we used to have hoooks for switching to the news
|
||||
/*export function useRedirectToNewsOnUpdates() {
|
||||
React.useEffect(() => {
|
||||
const { usageCount, lastSeenNewsVersion } = useAppStateStore.getState();
|
||||
const isNewsOutdated = (lastSeenNewsVersion || 0) < incrementalVersion;
|
||||
if (isNewsOutdated && usageCount > 2)
|
||||
return runWhenIdle(navigateToNews, 20000);
|
||||
}, []);
|
||||
}*/
|
||||
|
||||
@@ -14,7 +14,7 @@ import { GoogleSearchSettings } from '~/modules/google/GoogleSearchSettings';
|
||||
import { ProdiaSettings } from '~/modules/t2i/prodia/ProdiaSettings';
|
||||
import { T2ISettings } from '~/modules/t2i/T2ISettings';
|
||||
|
||||
import type { PreferencesTabId } from '~/common/layout/optima/store-optima';
|
||||
import type { PreferencesTabId } from '~/common/layout/optima/store-layout-optima';
|
||||
import { GoodModal } from '~/common/components/modals/GoodModal';
|
||||
import { useIsMobile } from '~/common/components/useMatchMedia';
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ import SettingsIcon from '@mui/icons-material/Settings';
|
||||
|
||||
import { Brand } from '~/common/app.config';
|
||||
import { ChatBeamIcon } from '~/common/components/icons/ChatBeamIcon';
|
||||
import { hasNoChatLinkItems } from '~/modules/trade/link/store-link';
|
||||
import { hasNoChatLinkItems } from '~/modules/trade/link/store-share-link';
|
||||
|
||||
|
||||
// enable to show all items, for layout development
|
||||
|
||||
@@ -13,7 +13,7 @@ import { pdfToImageDataURLs, pdfToText } from '~/common/util/pdfUtils';
|
||||
import { createDMessageDataInlineText, createDocAttachmentFragment, DMessageAttachmentFragment, DMessageDataInline, DMessageDocPart, DVMimeType, isContentOrAttachmentFragment, isDocPart, specialContentPartToDocAttachmentFragment } from '~/common/stores/chat/chat.fragments';
|
||||
|
||||
import type { AttachmentCreationOptions, AttachmentDraft, AttachmentDraftConverter, AttachmentDraftId, AttachmentDraftInput, AttachmentDraftSource, AttachmentDraftSourceOriginFile, DraftEgoFragmentsInputData, DraftWebInputData, DraftYouTubeInputData } from './attachment.types';
|
||||
import type { AttachmentsDraftsStore } from './store-attachment-drafts-slice';
|
||||
import type { AttachmentsDraftsStore } from './store-perchat-attachment-drafts_slice';
|
||||
import { attachmentGetLiveFileId, attachmentSourceSupportsLiveFile } from './attachment.livefile';
|
||||
import { guessInputContentTypeFromMime, heuristicMimeTypeFixup, mimeTypeIsDocX, mimeTypeIsPDF, mimeTypeIsPlainText, mimeTypeIsSupportedImage, reverseLookupMimeType } from './attachment.mimetypes';
|
||||
import { imageDataToImageAttachmentFragmentViaDBlob } from './attachment.dblobs';
|
||||
|
||||
@@ -10,10 +10,10 @@ import type { DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
import type { DMessageFragment } from '~/common/stores/chat/chat.fragments';
|
||||
import type { DMessageId } from '~/common/stores/chat/chat.message';
|
||||
import { getAllFilesFromDirectoryRecursively, getDataTransferFilesOrPromises } from '~/common/util/fileSystemUtils';
|
||||
import { useChatAttachmentsStore } from '~/common/chat-overlay/store-chat-overlay';
|
||||
import { useChatAttachmentsStore } from '~/common/chat-overlay/store-perchat_vanilla';
|
||||
|
||||
import type { AttachmentDraftSourceOriginDTO, AttachmentDraftSourceOriginFile } from './attachment.types';
|
||||
import type { AttachmentDraftsStoreApi } from './store-attachment-drafts-slice';
|
||||
import type { AttachmentDraftsStoreApi } from './store-perchat-attachment-drafts_slice';
|
||||
|
||||
|
||||
// enable to debug operations
|
||||
|
||||
@@ -3,7 +3,7 @@ import { bareBonesPromptMixer } from '~/modules/persona/pmix/pmix';
|
||||
import { SystemPurposes } from '../../data';
|
||||
import { gcChatImageAssets } from '../../apps/chat/editors/image-generate';
|
||||
|
||||
import { createBeamVanillaStore } from '~/modules/beam/store-beam-vanilla';
|
||||
import { createBeamVanillaStore } from '~/modules/beam/store-beam_vanilla';
|
||||
|
||||
import type { DConversationId } from '~/common/stores/chat/chat.conversation';
|
||||
import type { DLLMId } from '~/common/stores/llms/llms.types';
|
||||
@@ -14,8 +14,8 @@ import { getChatLLMId } from '~/common/stores/llms/store-llms';
|
||||
|
||||
import { getChatAutoAI } from '../../apps/chat/store-app-chat';
|
||||
|
||||
import { createDEphemeral } from './store-ephemeralsoverlay-slice';
|
||||
import { createPerChatVanillaStore } from './store-chat-overlay';
|
||||
import { createDEphemeral } from './store-perchat_ephemerals_slice';
|
||||
import { createPerChatVanillaStore } from './store-perchat_vanilla';
|
||||
|
||||
|
||||
// configuration
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
import { StoreApi, useStore } from 'zustand';
|
||||
import { createStore as createVanillaStore } from 'zustand/vanilla';
|
||||
|
||||
import { AttachmentsDraftsStore, createAttachmentDraftsStoreSlice } from '~/common/attachment-drafts/store-attachment-drafts-slice';
|
||||
import { ComposerOverlayStore, createComposerOverlayStoreSlice } from './store-composeroverlay-slice';
|
||||
import { createEphemeralsOverlayStoreSlice, EphemeralsOverlayStore } from './store-ephemeralsoverlay-slice';
|
||||
import { AttachmentsDraftsStore, createAttachmentDraftsStoreSlice } from '~/common/attachment-drafts/store-perchat-attachment-drafts_slice';
|
||||
import { ComposerOverlayStore, createComposerOverlayStoreSlice } from './store-perchat_composer_slice';
|
||||
import { createEphemeralsOverlayStoreSlice, EphemeralsOverlayStore } from './store-perchat_ephemerals_slice';
|
||||
|
||||
|
||||
/* Per-chat overlay store, combining all the slices.
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
import { OptimaPortalId, useOptimaPortalsStore } from './store-optima-portals';
|
||||
import { OptimaPortalId, useLayoutPortalsStore } from './store-layout-portals';
|
||||
|
||||
|
||||
export function OptimaDrawerIn(props: { children: React.ReactNode }) {
|
||||
@@ -25,11 +25,11 @@ export function OptimaToolbarIn(props: { children: React.ReactNode }) {
|
||||
*/
|
||||
function useOptimaPortalTargetElement(targetPortalId: OptimaPortalId) {
|
||||
// get the output element
|
||||
const targetPortalEl = useOptimaPortalsStore(state => state.portals[targetPortalId]?.element ?? null);
|
||||
const targetPortalEl = useLayoutPortalsStore(state => state.portals[targetPortalId]?.element ?? null);
|
||||
|
||||
// increment/decrement input count
|
||||
React.useEffect(() => {
|
||||
const { incrementInputs, decrementInputs } = useOptimaPortalsStore.getState();
|
||||
const { incrementInputs, decrementInputs } = useLayoutPortalsStore.getState();
|
||||
incrementInputs(targetPortalId);
|
||||
return () => decrementInputs(targetPortalId);
|
||||
}, [targetPortalId]);
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ interface OptimaPortalActions {
|
||||
}
|
||||
|
||||
|
||||
export const useOptimaPortalsStore = create<OptimaPortalState & OptimaPortalActions>((_set, _get) => ({
|
||||
export const useLayoutPortalsStore = create<OptimaPortalState & OptimaPortalActions>((_set, _get) => ({
|
||||
|
||||
// init state
|
||||
portals: {
|
||||
@@ -1,5 +1,5 @@
|
||||
import { OptimaPortalId, useOptimaPortalsStore } from './store-optima-portals';
|
||||
import { OptimaPortalId, useLayoutPortalsStore } from './store-layout-portals';
|
||||
|
||||
export function useOptimaPortalHasInputs(portalTargetId: OptimaPortalId) {
|
||||
return useOptimaPortalsStore(state => state.portals[portalTargetId]?.inputs >= 1);
|
||||
return useLayoutPortalsStore(state => state.portals[portalTargetId]?.inputs >= 1);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { OptimaPortalId, useOptimaPortalsStore } from './store-optima-portals';
|
||||
import { OptimaPortalId, useLayoutPortalsStore } from './store-layout-portals';
|
||||
|
||||
|
||||
/**
|
||||
@@ -20,7 +20,7 @@ export function useOptimaPortalOutRef(portalTargetId: OptimaPortalId, debugCalle
|
||||
const ref = React.useRef<HTMLElement>(null);
|
||||
|
||||
React.useLayoutEffect(() => {
|
||||
const { setElement } = useOptimaPortalsStore.getState();
|
||||
const { setElement } = useLayoutPortalsStore.getState();
|
||||
if (!ref.current) {
|
||||
console.warn(`useOptimaPortalOut: ref.current is null for type ${portalTargetId} (called by ${debugCallerName})`);
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ export interface OptimaActions {
|
||||
}
|
||||
|
||||
|
||||
export const useOptimaStore = create<OptimaState & OptimaActions>((_set, _get) => ({
|
||||
export const useLayoutOptimaStore = create<OptimaState & OptimaActions>((_set, _get) => ({
|
||||
|
||||
...initialState,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
import { OptimaActions, PreferencesTabId, useOptimaStore } from './store-optima';
|
||||
import { OptimaActions, PreferencesTabId, useLayoutOptimaStore } from './store-layout-optima';
|
||||
|
||||
|
||||
// configuration
|
||||
@@ -16,52 +16,52 @@ export function optimaActions(): Omit<OptimaActions,
|
||||
| 'closePanel' | 'openPanel' | 'togglePanel'
|
||||
| 'openPreferences'
|
||||
> {
|
||||
return useOptimaStore.getState();
|
||||
return useLayoutOptimaStore.getState();
|
||||
}
|
||||
|
||||
export function optimaCloseDrawer() {
|
||||
useOptimaStore.getState().closeDrawer();
|
||||
useLayoutOptimaStore.getState().closeDrawer();
|
||||
}
|
||||
|
||||
export function optimaOpenDrawer(event?: React.MouseEvent) {
|
||||
_eatMouseEvent(event);
|
||||
useOptimaStore.getState().openDrawer();
|
||||
useLayoutOptimaStore.getState().openDrawer();
|
||||
}
|
||||
|
||||
export function optimaToggleDrawer(event?: React.MouseEvent) {
|
||||
_eatMouseEvent(event);
|
||||
useOptimaStore.getState().toggleDrawer();
|
||||
useLayoutOptimaStore.getState().toggleDrawer();
|
||||
}
|
||||
|
||||
export function optimaCloseAppMenu() {
|
||||
useOptimaStore.getState().closeAppMenu();
|
||||
useLayoutOptimaStore.getState().closeAppMenu();
|
||||
}
|
||||
|
||||
export function optimaOpenAppMenu(event?: React.MouseEvent) {
|
||||
_eatMouseEvent(event);
|
||||
useOptimaStore.getState().openAppMenu();
|
||||
useLayoutOptimaStore.getState().openAppMenu();
|
||||
}
|
||||
|
||||
export function optimaClosePanel() {
|
||||
useOptimaStore.getState().closePanel();
|
||||
useLayoutOptimaStore.getState().closePanel();
|
||||
}
|
||||
|
||||
export function optimaOpenPanel(event?: React.MouseEvent) {
|
||||
_eatMouseEvent(event);
|
||||
useOptimaStore.getState().openPanel();
|
||||
useLayoutOptimaStore.getState().openPanel();
|
||||
}
|
||||
|
||||
export function optimaTogglePanel(event?: React.MouseEvent) {
|
||||
_eatMouseEvent(event);
|
||||
useOptimaStore.getState().togglePanel();
|
||||
useLayoutOptimaStore.getState().togglePanel();
|
||||
}
|
||||
|
||||
export function optimaOpenModels() {
|
||||
useOptimaStore.getState().openModels();
|
||||
useLayoutOptimaStore.getState().openModels();
|
||||
}
|
||||
|
||||
export function optimaOpenPreferences(changeTab?: PreferencesTabId) {
|
||||
useOptimaStore.getState().openPreferences(changeTab);
|
||||
useLayoutOptimaStore.getState().openPreferences(changeTab);
|
||||
}
|
||||
|
||||
function _eatMouseEvent(event?: (React.MouseEvent | React.TouchEvent)) {
|
||||
@@ -75,19 +75,19 @@ function _eatMouseEvent(event?: (React.MouseEvent | React.TouchEvent)) {
|
||||
/// React to UI State (mainly within the Optima Layout itself)
|
||||
|
||||
export function useOptimaDrawerOpen() {
|
||||
return useOptimaStore(({ drawerIsOpen }) => drawerIsOpen);
|
||||
return useLayoutOptimaStore(({ drawerIsOpen }) => drawerIsOpen);
|
||||
}
|
||||
|
||||
export function useOptimaAppMenuOpen() {
|
||||
return useOptimaStore(({ appMenuIsOpen }) => appMenuIsOpen);
|
||||
return useLayoutOptimaStore(({ appMenuIsOpen }) => appMenuIsOpen);
|
||||
}
|
||||
|
||||
export function useOptimaPanelOpen() {
|
||||
return useOptimaStore(({ panelIsOpen }) => panelIsOpen);
|
||||
return useLayoutOptimaStore(({ panelIsOpen }) => panelIsOpen);
|
||||
}
|
||||
|
||||
export function useOptimaModalsState() {
|
||||
return useOptimaStore(useShallow(state => ({
|
||||
return useLayoutOptimaStore(useShallow(state => ({
|
||||
showKeyboardShortcuts: state.showKeyboardShortcuts,
|
||||
showPreferences: state.showPreferences,
|
||||
preferencesTab: state.preferencesTab,
|
||||
@@ -95,7 +95,7 @@ export function useOptimaModalsState() {
|
||||
}
|
||||
|
||||
export function useOptimaModelsModalsState() {
|
||||
return useOptimaStore(useShallow(state => ({
|
||||
return useLayoutOptimaStore(useShallow(state => ({
|
||||
showModelOptions: state.showModelOptions,
|
||||
showModels: state.showModels,
|
||||
showPreferences: state.showPreferences,
|
||||
@@ -109,7 +109,7 @@ export function useOptimaModelsModalsState() {
|
||||
* Reacts the App Menu component
|
||||
*/
|
||||
export function useOptimaAppMenu() {
|
||||
return useOptimaStore(state => state.menuComponent);
|
||||
return useLayoutOptimaStore(state => state.menuComponent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,12 +118,12 @@ export function useOptimaAppMenu() {
|
||||
export function useSetOptimaAppMenu(menu: React.ReactNode, debugCallerName: string) {
|
||||
React.useEffect(() => {
|
||||
if (DEBUG_OPTIMA_PLUGGING) console.log(' +PLUG layout', debugCallerName);
|
||||
useOptimaStore.setState({
|
||||
useLayoutOptimaStore.setState({
|
||||
menuComponent: menu,
|
||||
});
|
||||
return () => {
|
||||
if (DEBUG_OPTIMA_PLUGGING) console.log(' -UNplug layout', debugCallerName);
|
||||
useOptimaStore.setState({
|
||||
useLayoutOptimaStore.setState({
|
||||
menuComponent: null,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { useOverlayStore } from './store-overlays';
|
||||
import { useLayoutOverlaysStore } from './store-layout-overlays';
|
||||
|
||||
|
||||
export const OverlaysInsert: React.FC = () => {
|
||||
|
||||
// external state
|
||||
const overlays = useOverlayStore(state => state.overlays);
|
||||
const overlays = useLayoutOverlaysStore(state => state.overlays);
|
||||
|
||||
// Transient Overlays / Modals
|
||||
return overlays.map(({ id, component }) => (
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ interface OverlayActions {
|
||||
// removeOverlaysBy: (predicate: (item: OverlayItem) => boolean) => void;
|
||||
}
|
||||
|
||||
export const useOverlayStore = create<OverlayState & OverlayActions>((set, get) => ({
|
||||
export const useLayoutOverlaysStore = create<OverlayState & OverlayActions>((set, get) => ({
|
||||
|
||||
// state
|
||||
overlays: [],
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { GlobalOverlayId, useOverlayStore } from './store-overlays';
|
||||
import { GlobalOverlayId, useLayoutOverlaysStore } from './store-layout-overlays';
|
||||
|
||||
|
||||
enum OverlayCloseReason {
|
||||
@@ -65,7 +65,7 @@ export function useOverlayComponents(): {
|
||||
): Promise<TResolve> => {
|
||||
return new Promise<TResolve>((pResolve, pReject) => {
|
||||
|
||||
const { appendOverlay, overlayExists, overlayToFront, removeOverlay } = useOverlayStore.getState();
|
||||
const { appendOverlay, overlayExists, overlayToFront, removeOverlay } = useLayoutOverlaysStore.getState();
|
||||
|
||||
// Check if the overlay already exists and exit early
|
||||
// This is like doReject, but doesn't remove the overlay as we don't insert it
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
import { incrementalNewsVersion } from '../../apps/news/news.version';
|
||||
|
||||
|
||||
// Sherpa State: navigation thought the app, remembers the counters for progressive disclosure of complex features
|
||||
|
||||
interface SherpaStore {
|
||||
|
||||
usageCount: number;
|
||||
|
||||
lastSeenNewsVersion: number;
|
||||
|
||||
chatComposerPrefill: string | null; // if not null, the composer will load this text at startup
|
||||
setChatComposerPrefill: (text: string | null) => void;
|
||||
|
||||
}
|
||||
|
||||
export const useLogicSherpaStore = create<SherpaStore>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
|
||||
usageCount: 0,
|
||||
|
||||
lastSeenNewsVersion: 0,
|
||||
|
||||
chatComposerPrefill: null,
|
||||
setChatComposerPrefill: (text) => set({ chatComposerPrefill: text }),
|
||||
|
||||
}),
|
||||
{
|
||||
name: 'app-state',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// increment the usage count
|
||||
useLogicSherpaStore.setState((state) => ({ usageCount: (state.usageCount || 0) + 1 }));
|
||||
|
||||
|
||||
/// News Navigation
|
||||
|
||||
export function shallRedirectToNews() {
|
||||
const { lastSeenNewsVersion, usageCount } = useLogicSherpaStore.getState();
|
||||
|
||||
// first time user - ignore the news up to the next refresh
|
||||
if (lastSeenNewsVersion === 0) {
|
||||
markNewsAsSeen();
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the news is outdated and the user has used the app a few times, show the news
|
||||
const isNewsOutdated = (lastSeenNewsVersion || 0) < incrementalNewsVersion;
|
||||
return isNewsOutdated && usageCount >= 3;
|
||||
}
|
||||
|
||||
export function markNewsAsSeen() {
|
||||
useLogicSherpaStore.setState({ lastSeenNewsVersion: incrementalNewsVersion });
|
||||
}
|
||||
|
||||
|
||||
// Chat Composer Prefill
|
||||
|
||||
export const setComposerStartupText = (text: string | null) => {
|
||||
useLogicSherpaStore.getState().setChatComposerPrefill(text);
|
||||
};
|
||||
|
||||
export const useComposerStartupText = (): [string | null, (text: string | null) => void] => {
|
||||
return useLogicSherpaStore(useShallow(state => [state.chatComposerPrefill, state.setChatComposerPrefill]));
|
||||
};
|
||||
@@ -3,11 +3,11 @@ import { useRouter } from 'next/router';
|
||||
|
||||
import { gcAttachmentDBlobs } from '~/common/attachment-drafts/attachment.dblobs';
|
||||
import { gcChatImageAssets } from '../../apps/chat/editors/image-generate';
|
||||
import { markNewsAsSeen, shallRedirectToNews } from '../../apps/news/news.version';
|
||||
|
||||
import { autoConfInitiateConfiguration } from '~/common/logic/autoconf';
|
||||
import { navigateToNews, ROUTE_APP_CHAT } from '~/common/app.routes';
|
||||
import { autoConfInitiateConfiguration } from '~/common/logic/store-logic-autoconf_vanilla';
|
||||
import { estimatePersistentStorageOrThrow, requestPersistentStorage } from '~/common/util/storageUtils';
|
||||
import { markNewsAsSeen, shallRedirectToNews } from '~/common/logic/store-logic-sherpa';
|
||||
import { navigateToNews, ROUTE_APP_CHAT } from '~/common/app.routes';
|
||||
import { useNextLoadProgress } from '~/common/components/useNextLoadProgress';
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export function ProviderBootstrapLogic(props: { children: React.ReactNode }) {
|
||||
useNextLoadProgress(route, events);
|
||||
|
||||
|
||||
// [bootup] logic
|
||||
// [boot-up] logic
|
||||
const isOnChat = route === ROUTE_APP_CHAT;
|
||||
const doRedirectToNews = isOnChat && shallRedirectToNews();
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
|
||||
// App State
|
||||
|
||||
interface AppStateData {
|
||||
usageCount: number;
|
||||
}
|
||||
|
||||
export const useAppStateStore = create<AppStateData>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
|
||||
usageCount: 0,
|
||||
|
||||
}),
|
||||
{
|
||||
name: 'app-state',
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// increment the usage count
|
||||
useAppStateStore.setState((state) => ({ usageCount: (state.usageCount || 0) + 1 }));
|
||||
@@ -7,7 +7,7 @@ import { Is } from '~/common/util/pwaUtils';
|
||||
// UX Labs Experiments
|
||||
|
||||
// UxLabsSettings.tsx contains the graduated settings, but the following are not stated:
|
||||
// - Text Tools: dinamically shown where applicable
|
||||
// - Text Tools: dynamically shown where applicable
|
||||
// - Chat Mode: Follow-Ups; moved to Chat Advanced UI
|
||||
interface UXLabsStore {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { SystemPurposeId } from '../../../data';
|
||||
|
||||
import type { DFolder } from '~/common/state/store-folders';
|
||||
import type { DFolder } from '~/common/stores/folders/store-chat-folders';
|
||||
import type { LiveFileId } from '~/common/livefile/liveFile.types';
|
||||
import { liveFileGetAllValidIDs } from '~/common/livefile/store-live-file';
|
||||
|
||||
|
||||
+116
-116
@@ -1,116 +1,116 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
|
||||
type TaggedListItem<TId extends string, TTag extends string> = {
|
||||
id: TId;
|
||||
listTags: TTag[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a persistent list of type TaggedListItem that will handle list functions, and item editing functions.
|
||||
* - your item can have all the properties you want, but must have an id and listTags property
|
||||
* - your item will be serialized/de-serialized to/from localStorage, make sure it's JSON-serializable
|
||||
*/
|
||||
export function createStoredTaggetList<TItem extends TaggedListItem<string, string>>(persistName: string) {
|
||||
|
||||
// Infer TId and TTag from TItem's id and listTags array type
|
||||
type TId = TItem['id'];
|
||||
type TTag = TItem['listTags'][number];
|
||||
|
||||
type SelectionMap = {
|
||||
[K in TTag]?: TId;
|
||||
};
|
||||
|
||||
type TaggedListState = {
|
||||
// State
|
||||
items: TItem[];
|
||||
selections: SelectionMap; // Maps TTag to selected TId
|
||||
|
||||
// Actions
|
||||
addItem: (item: TItem) => void;
|
||||
removeItem: (itemId: TId) => void;
|
||||
modifyItem: (itemId: TId, changes: Partial<TItem>) => void;
|
||||
modifyItemDeep: (itemId: TId, updater: (item: TItem) => TItem) => void;
|
||||
|
||||
selectItemForTag: (tag: TTag, itemId: TId) => void;
|
||||
};
|
||||
|
||||
return create<TaggedListState>()(persist((set, get) => ({
|
||||
|
||||
items: [] as TItem[],
|
||||
selections: {} as SelectionMap,
|
||||
|
||||
|
||||
addItem: (item: TItem) => set((state: TaggedListState) => ({
|
||||
items: [...state.items, item],
|
||||
})),
|
||||
|
||||
removeItem: (itemId: TId) => set((state: TaggedListState) => ({
|
||||
items: state.items.filter((item: TItem) => item.id !== itemId),
|
||||
selections: Object.fromEntries(
|
||||
Object.entries(state.selections).filter(([, selectedId]) => selectedId !== itemId),
|
||||
) as SelectionMap,
|
||||
})),
|
||||
|
||||
modifyItem: (itemId: TId, changes: Partial<TItem>) => set((state: TaggedListState) => ({
|
||||
items: state.items.map((item: TItem) => item.id === itemId ? { ...item, ...changes } : item),
|
||||
})),
|
||||
|
||||
modifyItemDeep: (itemId: TId, updater: (item: TItem) => TItem) => set((state: TaggedListState) => ({
|
||||
items: state.items.map((item: TItem) => item.id === itemId ? updater(item) : item),
|
||||
})),
|
||||
|
||||
|
||||
selectItemForTag: (tag: TTag, itemId: TId) => {
|
||||
const item = get().items.find((item) => item.id === itemId);
|
||||
if (item && item.listTags.includes(tag)) {
|
||||
set((state) => ({
|
||||
selections: { ...state.selections, [tag]: itemId },
|
||||
}));
|
||||
} else {
|
||||
console.warn(`Item with id ${itemId} does not support tag ${tag} and cannot be selected for it.`);
|
||||
}
|
||||
},
|
||||
|
||||
}),
|
||||
|
||||
{
|
||||
name: persistName,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/* Example:
|
||||
|
||||
// Define the specific subtype for VoiceOutModel
|
||||
type VoiceModelId = string;
|
||||
type VoiceModelTag = 'voice' | 'text' | 'image' | 'video' | 'audio';
|
||||
|
||||
// Define the VoiceOutModel interface
|
||||
export interface VoiceOutModel extends TaggedListItem<VoiceModelId, VoiceModelTag> {
|
||||
music: string;
|
||||
count: number;
|
||||
fruits: string[];
|
||||
}
|
||||
|
||||
// Create the Zustand store with the specific VoiceOutModel type
|
||||
const useVoiceOutModels = createStoredTaggetList<VoiceOutModel>('app-voice-synth');
|
||||
|
||||
export const useVoiceModel = (modelId: VoiceModelId) => {
|
||||
const { item, modifyItem } = useVoiceOutModels(useShallow(state => ({
|
||||
item: state.items.find(item => item.id === modelId) as Readonly<VoiceOutModel>,
|
||||
modifyItem: state.modifyItem,
|
||||
})));
|
||||
|
||||
// Memoize all the update functions at once
|
||||
const { setMusic, setCount, setFruits } = React.useMemo(() => ({
|
||||
setMusic: (music: string) => modifyItem(modelId, { music }),
|
||||
setCount: (count: number) => modifyItem(modelId, { count }),
|
||||
setFruits: (fruits: string[]) => modifyItem(modelId, { fruits }),
|
||||
}), [modifyItem, modelId]);
|
||||
|
||||
return { item, setMusic, setCount, setFruits };
|
||||
};
|
||||
*/
|
||||
// import { create } from 'zustand';
|
||||
// import { persist } from 'zustand/middleware';
|
||||
//
|
||||
//
|
||||
// type TaggedListItem<TId extends string, TTag extends string> = {
|
||||
// id: TId;
|
||||
// listTags: TTag[];
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Create a persistent list of type TaggedListItem that will handle list functions, and item editing functions.
|
||||
// * - your item can have all the properties you want, but must have an id and listTags property
|
||||
// * - your item will be serialized/de-serialized to/from localStorage, make sure it's JSON-serializable
|
||||
// */
|
||||
// export function createStoredTaggedList<TItem extends TaggedListItem<string, string>>(persistName: string) {
|
||||
//
|
||||
// // Infer TId and TTag from TItem's id and listTags array type
|
||||
// type TId = TItem['id'];
|
||||
// type TTag = TItem['listTags'][number];
|
||||
//
|
||||
// type SelectionMap = {
|
||||
// [K in TTag]?: TId;
|
||||
// };
|
||||
//
|
||||
// type TaggedListState = {
|
||||
// // State
|
||||
// items: TItem[];
|
||||
// selections: SelectionMap; // Maps TTag to selected TId
|
||||
//
|
||||
// // Actions
|
||||
// addItem: (item: TItem) => void;
|
||||
// removeItem: (itemId: TId) => void;
|
||||
// modifyItem: (itemId: TId, changes: Partial<TItem>) => void;
|
||||
// modifyItemDeep: (itemId: TId, updater: (item: TItem) => TItem) => void;
|
||||
//
|
||||
// selectItemForTag: (tag: TTag, itemId: TId) => void;
|
||||
// };
|
||||
//
|
||||
// return create<TaggedListState>()(persist((set, get) => ({
|
||||
//
|
||||
// items: [] as TItem[],
|
||||
// selections: {} as SelectionMap,
|
||||
//
|
||||
//
|
||||
// addItem: (item: TItem) => set((state: TaggedListState) => ({
|
||||
// items: [...state.items, item],
|
||||
// })),
|
||||
//
|
||||
// removeItem: (itemId: TId) => set((state: TaggedListState) => ({
|
||||
// items: state.items.filter((item: TItem) => item.id !== itemId),
|
||||
// selections: Object.fromEntries(
|
||||
// Object.entries(state.selections).filter(([, selectedId]) => selectedId !== itemId),
|
||||
// ) as SelectionMap,
|
||||
// })),
|
||||
//
|
||||
// modifyItem: (itemId: TId, changes: Partial<TItem>) => set((state: TaggedListState) => ({
|
||||
// items: state.items.map((item: TItem) => item.id === itemId ? { ...item, ...changes } : item),
|
||||
// })),
|
||||
//
|
||||
// modifyItemDeep: (itemId: TId, updater: (item: TItem) => TItem) => set((state: TaggedListState) => ({
|
||||
// items: state.items.map((item: TItem) => item.id === itemId ? updater(item) : item),
|
||||
// })),
|
||||
//
|
||||
//
|
||||
// selectItemForTag: (tag: TTag, itemId: TId) => {
|
||||
// const item = get().items.find((item) => item.id === itemId);
|
||||
// if (item && item.listTags.includes(tag)) {
|
||||
// set((state) => ({
|
||||
// selections: { ...state.selections, [tag]: itemId },
|
||||
// }));
|
||||
// } else {
|
||||
// console.warn(`Item with id ${itemId} does not support tag ${tag} and cannot be selected for it.`);
|
||||
// }
|
||||
// },
|
||||
//
|
||||
// }),
|
||||
//
|
||||
// {
|
||||
// name: persistName,
|
||||
// }),
|
||||
// );
|
||||
// }
|
||||
//
|
||||
//
|
||||
// /* Example:
|
||||
//
|
||||
// // Define the specific subtype for VoiceOutModel
|
||||
// type VoiceModelId = string;
|
||||
// type VoiceModelTag = 'voice' | 'text' | 'image' | 'video' | 'audio';
|
||||
//
|
||||
// // Define the VoiceOutModel interface
|
||||
// export interface VoiceOutModel extends TaggedListItem<VoiceModelId, VoiceModelTag> {
|
||||
// music: string;
|
||||
// count: number;
|
||||
// fruits: string[];
|
||||
// }
|
||||
//
|
||||
// // Create the Zustand store with the specific VoiceOutModel type
|
||||
// const useVoiceOutModels = createStoredTaggetList<VoiceOutModel>('app-voice-synth');
|
||||
//
|
||||
// export const useVoiceModel = (modelId: VoiceModelId) => {
|
||||
// const { item, modifyItem } = useVoiceOutModels(useShallow(state => ({
|
||||
// item: state.items.find(item => item.id === modelId) as Readonly<VoiceOutModel>,
|
||||
// modifyItem: state.modifyItem,
|
||||
// })));
|
||||
//
|
||||
// // Memoize all the update functions at once
|
||||
// const { setMusic, setCount, setFruits } = React.useMemo(() => ({
|
||||
// setMusic: (music: string) => modifyItem(modelId, { music }),
|
||||
// setCount: (count: number) => modifyItem(modelId, { count }),
|
||||
// setFruits: (fruits: string[]) => modifyItem(modelId, { fruits }),
|
||||
// }), [modifyItem, modelId]);
|
||||
//
|
||||
// return { item, setMusic, setCount, setFruits };
|
||||
// };
|
||||
// */
|
||||
@@ -6,7 +6,7 @@ import type { DMessage } from '~/common/stores/chat/chat.message';
|
||||
import { agiUuid } from '~/common/util/idUtils';
|
||||
|
||||
import { CUSTOM_FACTORY_ID, FFactoryId, findFusionFactory, FUSION_FACTORIES, FUSION_FACTORY_DEFAULT } from './instructions/beam.gather.factories';
|
||||
import { RootStoreSlice } from '../store-beam-vanilla';
|
||||
import { RootStoreSlice } from '../store-beam_vanilla';
|
||||
import { ScatterStoreSlice } from '../scatter/beam.scatter';
|
||||
import { gatherStartFusion, gatherStopFusion, Instruction } from './instructions/beam.gather.execution';
|
||||
import { updateBeamLastConfig } from '../store-module-beam';
|
||||
|
||||
@@ -9,7 +9,7 @@ import { createPlaceholderMetaFragment } from '~/common/stores/chat/chat.fragmen
|
||||
import { findLLMOrThrow } from '~/common/stores/llms/store-llms';
|
||||
import { getUXLabsHighPerformance } from '~/common/state/store-ux-labs';
|
||||
|
||||
import type { RootStoreSlice } from '../store-beam-vanilla';
|
||||
import type { RootStoreSlice } from '../store-beam_vanilla';
|
||||
import { SCATTER_DEBUG_STATE, SCATTER_PLACEHOLDER } from '../beam.config';
|
||||
import { updateBeamLastConfig } from '../store-module-beam';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { type StoreApi, useStore } from 'zustand';
|
||||
|
||||
import type { BeamStore } from './store-beam-vanilla';
|
||||
import type { BeamStore } from './store-beam_vanilla';
|
||||
|
||||
|
||||
export type BeamStoreApi = Readonly<StoreApi<BeamStore>>;
|
||||
|
||||
@@ -23,7 +23,7 @@ import { getOriginUrl } from '~/common/util/urlUtils';
|
||||
import { webShare, webSharePresent } from '~/common/util/pwaUtils';
|
||||
|
||||
import type { StorageDeleteSchema, StoragePutSchema } from '../server/link';
|
||||
import { forgetChatLinkItem } from './store-link';
|
||||
import { forgetChatLinkItem } from './store-share-link';
|
||||
|
||||
|
||||
export function ChatLinkDetails(props: {
|
||||
|
||||
@@ -15,7 +15,7 @@ import { getConversation } from '~/common/stores/chat/store-chats';
|
||||
|
||||
import type { StoragePutSchema, StorageUpdateDeletionKeySchema } from '../server/link';
|
||||
import { ChatLinkDetails } from './ChatLinkDetails';
|
||||
import { rememberChatLinkItem, updateChatLinkDeletionKey, useLinkStorageOwnerId } from './store-link';
|
||||
import { rememberChatLinkItem, updateChatLinkDeletionKey, useLinkStorageOwnerId } from './store-share-link';
|
||||
|
||||
|
||||
export function ChatLinkExport(props: {
|
||||
|
||||
@@ -25,7 +25,7 @@ interface LinkStore {
|
||||
|
||||
}
|
||||
|
||||
const useLinkStore = create<LinkStore>()(
|
||||
const useShareLinkStore = create<LinkStore>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
|
||||
@@ -52,18 +52,18 @@ const useLinkStore = create<LinkStore>()(
|
||||
|
||||
|
||||
// by AppChatLink
|
||||
export const useSharedChatLinkItems = () => useLinkStore(useShallow(state => state.chatLinkItems));
|
||||
export const useSharedChatLinkItems = () => useShareLinkStore(useShallow(state => state.chatLinkItems));
|
||||
|
||||
// by ChatLinkExport/ChatLinkDetails
|
||||
export const rememberChatLinkItem = useLinkStore.getState().chatLinkItemAdd;
|
||||
export const updateChatLinkDeletionKey = useLinkStore.getState().chatLinkItemChangeDeletionKey;
|
||||
export const forgetChatLinkItem = useLinkStore.getState().chatLinkItemRemove;
|
||||
export const useLinkStorageOwnerId = () => useLinkStore(useShallow(state => ({
|
||||
export const rememberChatLinkItem = useShareLinkStore.getState().chatLinkItemAdd;
|
||||
export const updateChatLinkDeletionKey = useShareLinkStore.getState().chatLinkItemChangeDeletionKey;
|
||||
export const forgetChatLinkItem = useShareLinkStore.getState().chatLinkItemRemove;
|
||||
export const useLinkStorageOwnerId = () => useShareLinkStore(useShallow(state => ({
|
||||
linkStorageOwnerId: state.linkStorageOwnerId,
|
||||
setLinkStorageOwnerId: state.setLinkStorageOwnerId,
|
||||
})));
|
||||
|
||||
// by Nav
|
||||
export function hasNoChatLinkItems() {
|
||||
return !useLinkStore.getState().chatLinkItems.length;
|
||||
return !useShareLinkStore.getState().chatLinkItems.length;
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { messageFragmentsReduceText } from '~/common/stores/chat/chat.message';
|
||||
import { prettyShortChatModelName } from '~/common/util/dMessageUtils';
|
||||
import { prettyTimestampForFilenames } from '~/common/util/timeUtils';
|
||||
import { useChatStore } from '~/common/stores/chat/store-chats';
|
||||
import { useFolderStore } from '~/common/state/store-folders';
|
||||
import { useFolderStore } from '~/common/stores/folders/store-chat-folders';
|
||||
|
||||
import type { ImportedOutcome } from './ImportOutcomeModal';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user