import CompoundPredicateBuilder from '@/Components/SmartViewBuilder/CompoundPredicateBuilder' import Icon from '@/Components/Icon/Icon' import IconPicker from '@/Components/Icon/IconPicker' import Popover from '@/Components/Popover/Popover' import Spinner from '@/Components/Spinner/Spinner' import { Platform, SmartViewDefaultIconName, VectorIconNameOrEmoji } from '@standardnotes/snjs' import { observer } from 'mobx-react-lite' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { AddSmartViewModalController } from './AddSmartViewModalController' import TabPanel from '../Tabs/TabPanel' import { useTabState } from '../Tabs/useTabState' import TabsContainer from '../Tabs/TabsContainer' import CopyableCodeBlock from '../Shared/CopyableCodeBlock' import { classNames } from '@standardnotes/utils' import Modal, { ModalAction } from '../Modal/Modal' import { Disclosure, DisclosureContent, useDisclosureStore } from '@ariakit/react' type Props = { controller: AddSmartViewModalController platform: Platform } const ConflictedNotesExampleCode = `{ "keypath": "content.conflict_of.length", "operator": ">", "value": 0 }` const ComplexCompoundExampleCode = `{ "operator": "and", "value": [ { "operator": "not", "value": { "keypath": "tags", "operator": "includes", "value": { "keypath": "title", "operator": "=", "value": "completed" } } }, { "keypath": "tags", "operator": "includes", "value": { "keypath": "title", "operator": "=", "value": "todo" } } ] } ` const AddSmartViewModal = ({ controller, platform }: Props) => { const { isSaving, title, setTitle, icon, setIcon, closeModal, saveCurrentSmartView, predicateController, customPredicateJson, setCustomPredicateJson, isCustomJsonValidPredicate, setIsCustomJsonValidPredicate, validateAndPrettifyCustomPredicate, } = controller const titleInputRef = useRef(null) const customJsonInputRef = useRef(null) const [shouldShowIconPicker, setShouldShowIconPicker] = useState(false) const iconPickerButtonRef = useRef(null) const jsonExamplesDisclosure = useDisclosureStore() const showingJsonExamples = jsonExamplesDisclosure.useState('open') const toggleIconPicker = () => { setShouldShowIconPicker((shouldShow) => !shouldShow) } const tabState = useTabState({ defaultTab: 'builder', }) const save = useCallback(() => { if (!title.length) { titleInputRef.current?.focus() return } if (tabState.activeTab === 'custom' && !isCustomJsonValidPredicate) { validateAndPrettifyCustomPredicate() return } void saveCurrentSmartView() }, [ isCustomJsonValidPredicate, saveCurrentSmartView, tabState.activeTab, title.length, validateAndPrettifyCustomPredicate, ]) const canSave = tabState.activeTab === 'builder' || isCustomJsonValidPredicate useEffect(() => { if (!customJsonInputRef.current) { return } if (tabState.activeTab === 'custom' && isCustomJsonValidPredicate === false) { customJsonInputRef.current.focus() } }, [isCustomJsonValidPredicate, tabState.activeTab]) const modalActions = useMemo( (): ModalAction[] => [ { label: 'Cancel', onClick: closeModal, disabled: isSaving, type: 'cancel', mobileSlot: 'left', }, { label: isSaving ? : canSave ? 'Save' : 'Validate', onClick: save, disabled: isSaving, mobileSlot: 'right', type: 'primary', }, ], [canSave, closeModal, isSaving, save], ) return (
Title:
{ setTitle(event.target.value) }} ref={titleInputRef} />
Icon:
{ setIcon(value ?? SmartViewDefaultIconName) toggleIconPicker() }} platform={platform} useIconGrid={true} />
Predicate: