diff --git a/.vscode/recommendations.json b/.vscode/recommendations.json index 240711a5c..4a33a343e 100644 --- a/.vscode/recommendations.json +++ b/.vscode/recommendations.json @@ -5,6 +5,7 @@ "ms-vscode.vscode-typescript-next", "dbaeumer.vscode-eslint", "antfu.vite", + "DavidAnson.vscode-markdownlint", "ms-playwright.playwright" ] } diff --git a/CHANGELOG.md b/CHANGELOG.md index c0c999c13..22a9869b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ By far most changes relate to `atomic-server`, so if not specified, assume the c **Changes to JS assets (including the front-end and JS libraries) are not shown here**, but in [`/browser/CHANGELOG`](/browser/CHANGELOG.md). See [STATUS.md](server/STATUS.md) to learn more about which features will remain stable. +## [UNRELEASED] + +- Remove `process-management` feature #324 #334 + ## [v0.37.0] - 2024-02-01 - Refactor `atomic_lib::Resource` propval methods (e.g. `set_propval` => `set`), make them chainable. #822 diff --git a/Cargo.lock b/Cargo.lock index c4c7d1857..d78ffc38d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -500,7 +500,6 @@ dependencies = [ "serde_with", "simple-server-timing-header", "static-files", - "sysinfo", "tantivy", "tokio", "tracing", @@ -1493,7 +1492,7 @@ dependencies = [ "libc", "log", "rustversion", - "windows 0.32.0", + "windows", ] [[package]] @@ -2237,15 +2236,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "ntapi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" -dependencies = [ - "winapi", -] - [[package]] name = "ntest" version = "0.9.0" @@ -3624,21 +3614,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sysinfo" -version = "0.30.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb4f3438c8f6389c864e61221cbc97e9bca98b4daf39a5beb7bea660f528bb2" -dependencies = [ - "cfg-if", - "core-foundation-sys", - "libc", - "ntapi", - "once_cell", - "rayon", - "windows 0.52.0", -] - [[package]] name = "tantivy" version = "0.21.1" @@ -4483,25 +4458,6 @@ dependencies = [ "windows_x86_64_msvc 0.32.0", ] -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core", - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.0", -] - [[package]] name = "windows-sys" version = "0.36.1" diff --git a/browser/CHANGELOG.md b/browser/CHANGELOG.md index 3b9412360..c87180931 100644 --- a/browser/CHANGELOG.md +++ b/browser/CHANGELOG.md @@ -11,13 +11,36 @@ This changelog covers all three packages, as they are (for now) updated as a who - [#850](https://github.com/atomicdata-dev/atomic-server/issues/850) Add drag & drop sorting to ResourceArray inputs. - [#757](https://github.com/atomicdata-dev/atomic-server/issues/757) Add drag & drop sorting to sidebar. +### @tomic/lib + +- Deprecated `resource.getSubject()` in favor of `resource.subject`. +- Deprecated `store.getResouceAsync()` in favor of `store.getResource()`. +- Deprecated `resource.pushPropval()` in favor of `resource.push()`. +- Deprecated `resource.removePropval()` in favor of `resource.remove()`. +- Added `resource.matchClass()` method. +- Added `resource.setVersion()` method. +- Added `collection.getMembersOnPage()` method. +- Added `collection.numberOfPages`. +- BREAKING CHANGE: Renamed `resource.getCommitsCollection` to `resource.getCommitsCollectionSubject`. +- BREAKING CHANGE: `resource.getChildrenCollection()` now returns a `Promise` instead of a subject. +- BREAKING CHANGE: Resource now keeps a reference to store internally, therefore all methods that required you to pass a store have been changed to not require a store. + These methods are: + - `resource.canWrite()` + - `resource.getHistory()` + - `resource.getRights()` + - `resource.destroy()` + - `resource.save()` + - `resource.set()` + - `resource.removeClasses()` + - `resource.addClasses()` + ## v0.37.0 ### Atomic Browser -- [#747](https://github.com/atomicdata-dev/atomic-server/issues/747) Show ontology classes on new resource page. -- [#770](https://github.com/atomicdata-dev/atomic-server/issues/770) Display more info on search result page. -- [#771](https://github.com/atomicdata-dev/atomic-server/issues/771) Tables: Don't paste in multiple rows when focussed on an input +- [#747](https://github.com/atomicdata-dev/atomic-server/issues/747) Show ontology classes on the new resource page. +- [#770](https://github.com/atomicdata-dev/atomic-server/issues/770) Display more info on the search result page. +- [#771](https://github.com/atomicdata-dev/atomic-server/issues/771) Tables: Don't paste in multiple rows when focused on an input - [#758](https://github.com/atomicdata-dev/atomic-server/issues/758) Fix Relation column forms to close when clicking on the searchbox - [#780](https://github.com/atomicdata-dev/atomic-server/issues/780) Use tags in ontology editor to create enum properties. - [#810](https://github.com/atomicdata-dev/atomic-server/issues/810) Add button to resource selectors to navigate to the selected resource. diff --git a/browser/data-browser/src/components/InviteForm.tsx b/browser/data-browser/src/components/InviteForm.tsx index 8d7b1e52e..f34bdde9b 100644 --- a/browser/data-browser/src/components/InviteForm.tsx +++ b/browser/data-browser/src/components/InviteForm.tsx @@ -1,10 +1,11 @@ import { useResource, useStore, - properties, Resource, urls, useCurrentAgent, + core, + server, } from '@tomic/react'; import { useCallback, useState } from 'react'; import toast from 'react-hot-toast'; @@ -35,41 +36,41 @@ export function InviteForm({ target }: InviteFormProps) { /** Stores the Invite, sends it to the server, shows the Subject to the User */ const createInvite = useCallback(async () => { - await invite.set(properties.isA, [urls.classes.invite], store); - await invite.set(properties.read, [urls.instances.publicAgent], store); - await invite.set(properties.invite.target, target.getSubject(), store); + await invite.set(core.properties.isA, [server.classes.invite]); + await invite.set(core.properties.read, [urls.instances.publicAgent]); + await invite.set(server.properties.target, target.subject); try { if (!agent) { throw new Error('No agent found'); } - await invite.set(properties.parent, agent.subject, store); - await invite.save(store); - await navigator.clipboard.writeText(invite.getSubject()); + await invite.set(core.properties.parent, agent.subject); + await invite.save(); + await navigator.clipboard.writeText(invite.subject); toast.success('Copied to clipboard'); setSaved(true); } catch (e) { setErr(e); } - }, [invite, store, agent, target]); + }, [invite, agent, target]); if (!saved) { return ( @@ -84,7 +85,7 @@ export function InviteForm({ target }: InviteFormProps) { return (

Invite created and copied to clipboard! Send it to your buddy:

- +
); } diff --git a/browser/data-browser/src/components/ResourceContextMenu/index.tsx b/browser/data-browser/src/components/ResourceContextMenu/index.tsx index 0cfc7f4ad..b80a5247e 100644 --- a/browser/data-browser/src/components/ResourceContextMenu/index.tsx +++ b/browser/data-browser/src/components/ResourceContextMenu/index.tsx @@ -85,7 +85,7 @@ function ResourceContextMenu({ const parent = resource.get(core.properties.parent); try { - await resource.destroy(store); + await resource.destroy(); onAfterDelete?.(); toast.success('Resource deleted!'); diff --git a/browser/data-browser/src/components/SideBar/useSidebarDnd.ts b/browser/data-browser/src/components/SideBar/useSidebarDnd.ts index 3dca390ea..678302cc0 100644 --- a/browser/data-browser/src/components/SideBar/useSidebarDnd.ts +++ b/browser/data-browser/src/components/SideBar/useSidebarDnd.ts @@ -9,7 +9,7 @@ import { useSensor, useSensors, } from '@dnd-kit/core'; -import { Resource, Store, core, dataBrowser, useStore } from '@tomic/react'; +import { Resource, core, dataBrowser, useStore } from '@tomic/react'; import { useCallback, useState } from 'react'; import { getTransitionName } from '../../helpers/transitionName'; import { useSettings } from '../../helpers/AppSettings'; @@ -24,7 +24,6 @@ export type SideBarDragData = { }; async function moveItemInSameParent( - store: Store, parent: Resource, subject: string, toPosition: number, @@ -40,13 +39,12 @@ async function moveItemInSameParent( removed, ); - await parent.set(dataBrowser.properties.subResources, newArray, store); + await parent.set(dataBrowser.properties.subResources, newArray); - await parent.save(store); + await parent.save(); } async function moveItemBetweenParents( - store: Store, oldParent: Resource, newParent: Resource, resource: Resource, @@ -56,8 +54,7 @@ async function moveItemBetweenParents( oldParent.get(dataBrowser.properties.subResources) ?? []; await oldParent.set( dataBrowser.properties.subResources, - oldSubResources.filter(subject => subject !== resource.getSubject()), - store, + oldSubResources.filter(subject => subject !== resource.subject), ); const newSubResources = @@ -65,15 +62,14 @@ async function moveItemBetweenParents( await newParent.set( dataBrowser.properties.subResources, - newSubResources.toSpliced(position, 0, resource.getSubject()), - store, + newSubResources.toSpliced(position, 0, resource.subject), ); - await resource.set(core.properties.parent, newParent.getSubject(), store); + await resource.set(core.properties.parent, newParent.subject); - await oldParent.save(store); - await newParent.save(store); - await resource.save(store); + await oldParent.save(); + await newParent.save(); + await resource.save(); } export const useSidebarDnd = ( @@ -193,10 +189,9 @@ export const useSidebarDnd = ( let promise: Promise; if (renderedUnder === dropParent) { - promise = moveItemInSameParent(store, newParent, subject, position); + promise = moveItemInSameParent(newParent, subject, position); } else { promise = moveItemBetweenParents( - store, oldParent, newParent, resource, diff --git a/browser/data-browser/src/components/Tag/CreateTagRow.tsx b/browser/data-browser/src/components/Tag/CreateTagRow.tsx index 4684457c4..0e939f827 100644 --- a/browser/data-browser/src/components/Tag/CreateTagRow.tsx +++ b/browser/data-browser/src/components/Tag/CreateTagRow.tsx @@ -37,7 +37,7 @@ export function CreateTagRow({ parent, onNewTag }: CreateTagRowProps) { }); if (emoji) { - await tag.set(dataBrowser.properties.emoji, emoji, store); + await tag.set(dataBrowser.properties.emoji, emoji); } onNewTag(tag); diff --git a/browser/data-browser/src/components/forms/FilePicker/FilePicker.tsx b/browser/data-browser/src/components/forms/FilePicker/FilePicker.tsx index 52112ee84..c90a4c187 100644 --- a/browser/data-browser/src/components/forms/FilePicker/FilePicker.tsx +++ b/browser/data-browser/src/components/forms/FilePicker/FilePicker.tsx @@ -48,11 +48,11 @@ export function FilePicker({ const thisUnsub = store.on( StoreEvents.ResourceSaved, async savedResource => { - if (savedResource.getSubject() === resource.getSubject()) { + if (savedResource.subject === resource.subject) { thisUnsub(); const [subject] = await upload([selectedFile]); await setValue(subject); - resource.save(store); + resource.save(); } }, ); diff --git a/browser/data-browser/src/components/forms/NewForm/CustomCreateActions/BasicInstanceHandlers.ts b/browser/data-browser/src/components/forms/NewForm/CustomCreateActions/BasicInstanceHandlers.ts index 290153d1a..d7b2b7295 100644 --- a/browser/data-browser/src/components/forms/NewForm/CustomCreateActions/BasicInstanceHandlers.ts +++ b/browser/data-browser/src/components/forms/NewForm/CustomCreateActions/BasicInstanceHandlers.ts @@ -62,12 +62,13 @@ export const registerBasicInstanceHandlers = () => { [core.properties.read]: [agent.subject], }); - const agentResource = await store.getResourceAsync(agent.subject); - agentResource.pushPropVal(server.properties.drives, [ - newResource.getSubject(), - ]); - agentResource.save(store); - settings.setDrive(newResource.getSubject()); + // resources created with createAndNavigate have a parent by default which we don't want for drives. + newResource.remove(core.properties.parent); + + const agentResource = await store.getResource(agent.subject); + agentResource.push(server.properties.drives, [newResource.subject]); + agentResource.save(); + settings.setDrive(newResource.subject); }, ); }; diff --git a/browser/data-browser/src/components/forms/NewForm/CustomCreateActions/CustomForms/NewTableDialog.tsx b/browser/data-browser/src/components/forms/NewForm/CustomCreateActions/CustomForms/NewTableDialog.tsx index 2b961f893..5cf5eda33 100644 --- a/browser/data-browser/src/components/forms/NewForm/CustomCreateActions/CustomForms/NewTableDialog.tsx +++ b/browser/data-browser/src/components/forms/NewForm/CustomCreateActions/CustomForms/NewTableDialog.tsx @@ -36,33 +36,22 @@ export const NewTableDialog: FC = ({ const createResourceAndNavigate = useCreateAndNavigate(); const onCancel = useCallback(() => { - instanceResource.destroy(store); + instanceResource.destroy(); onClose(); - }, [onClose, instanceResource, store]); + }, [onClose, instanceResource]); const onSuccess = useCallback(async () => { - await instanceResource.set( - core.properties.shortname, - stringToSlug(name), - store, - ); + await instanceResource.set(core.properties.shortname, stringToSlug(name)); await instanceResource.set( core.properties.description, `Represents a row in the ${name} table`, - store, - ); - await instanceResource.set( - core.properties.isA, - [core.classes.class], - store, - ); - await instanceResource.set(core.properties.parent, parent, store); - await instanceResource.set( - core.properties.recommends, - [core.properties.name], - store, ); - await instanceResource.save(store); + await instanceResource.set(core.properties.isA, [core.classes.class]); + await instanceResource.set(core.properties.parent, parent); + await instanceResource.set(core.properties.recommends, [ + core.properties.name, + ]); + await instanceResource.save(); createResourceAndNavigate( dataBrowser.classes.table, @@ -74,7 +63,7 @@ export const NewTableDialog: FC = ({ ); onClose(); - }, [name, instanceResource, store, onClose, parent]); + }, [name, instanceResource, onClose, parent]); const [dialogProps, show, hide] = useDialog({ onCancel, onSuccess }); diff --git a/browser/data-browser/src/components/forms/NewForm/NewFormDialog.tsx b/browser/data-browser/src/components/forms/NewForm/NewFormDialog.tsx index e95539199..86cb8e95d 100644 --- a/browser/data-browser/src/components/forms/NewForm/NewFormDialog.tsx +++ b/browser/data-browser/src/components/forms/NewForm/NewFormDialog.tsx @@ -42,7 +42,7 @@ export const NewFormDialog = ({ }); const onResourceSave = useCallback(() => { - onSave(resource.getSubject()); + onSave(resource.subject); closeDialog(true); }, [onSave, closeDialog, resource]); @@ -59,7 +59,7 @@ export const NewFormDialog = ({ await setSubjectValue(uniqueSubject); for (const [prop, value] of Object.entries(initialProps ?? {})) { - await resource.set(prop, value, store); + await resource.set(prop, value); } })(); }); diff --git a/browser/data-browser/src/components/forms/NewForm/useNewForm.ts b/browser/data-browser/src/components/forms/NewForm/useNewForm.ts index daadd3a4c..b2ea3e70b 100644 --- a/browser/data-browser/src/components/forms/NewForm/useNewForm.ts +++ b/browser/data-browser/src/components/forms/NewForm/useNewForm.ts @@ -1,7 +1,6 @@ import { Resource, useString, - properties, useStore, useResource, useArray, @@ -36,18 +35,18 @@ export const useNewForm = (args: UseNewForm) => { const [subjectErr, setSubjectErr] = useState(undefined); const resource = useResource(subjectValue, resourseOpts); - const [parentVal] = useString(resource, properties.parent); - const [isAVal] = useArray(resource, properties.isA); + const [parentVal] = useString(resource, core.properties.parent); + const [isAVal] = useArray(resource, core.properties.isA); // When the resource is created or updated, make sure that the parent and class are present useEffect(() => { (async () => { if (parentVal !== parent) { - await resource.set(core.properties.parent, parent, store); + await resource.set(core.properties.parent, parent); } if (isAVal.length === 0) { - await resource.addClasses(store, klass.getSubject()); + await resource.addClasses(klass.getSubject()); } setInitialized(true); @@ -59,7 +58,7 @@ export const useNewForm = (args: UseNewForm) => { setSubjectErr(undefined); setSubject(newSubject); - if (resource.get(properties.parent) !== parent) { + if (resource.get(core.properties.parent) !== parent) { // This prevents that we move an empty temporary resource return; } diff --git a/browser/data-browser/src/components/forms/NewForm/useNewResourceUI.tsx b/browser/data-browser/src/components/forms/NewForm/useNewResourceUI.tsx index 714b26686..cc6fd967e 100644 --- a/browser/data-browser/src/components/forms/NewForm/useNewResourceUI.tsx +++ b/browser/data-browser/src/components/forms/NewForm/useNewResourceUI.tsx @@ -107,7 +107,7 @@ export function NewResourceUIProvider({ children }: PropsWithChildren) { } // Default behaviour. Navigate to a new resource form for the given class. - const classResource = await store.getResourceAsync(isA); + const classResource = await store.getResource(isA); navigate( newURL(isA, parent, store.createSubject(classResource.props.shortname)), ); diff --git a/browser/data-browser/src/components/forms/ResourceForm.tsx b/browser/data-browser/src/components/forms/ResourceForm.tsx index 223c059a8..16f69252c 100644 --- a/browser/data-browser/src/components/forms/ResourceForm.tsx +++ b/browser/data-browser/src/components/forms/ResourceForm.tsx @@ -163,7 +163,7 @@ export function ResourceForm({ } function handleDelete(propertyURL: string) { - resource.removePropVal(propertyURL); + resource.remove(propertyURL); setTempOtherProps(tempOtherProps.filter(prop => prop !== propertyURL)); } diff --git a/browser/data-browser/src/components/forms/ValueForm.tsx b/browser/data-browser/src/components/forms/ValueForm.tsx index 0864136ac..311d8f859 100644 --- a/browser/data-browser/src/components/forms/ValueForm.tsx +++ b/browser/data-browser/src/components/forms/ValueForm.tsx @@ -2,13 +2,7 @@ import { useState } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { FaEdit } from 'react-icons/fa'; import { styled } from 'styled-components'; -import { - useProperty, - useStore, - useValue, - Datatype, - Resource, -} from '@tomic/react'; +import { useProperty, useValue, Datatype, Resource } from '@tomic/react'; import { Button } from '../Button'; import ValueComp from '../ValueComp'; import { ErrMessage } from './InputStyles'; @@ -36,7 +30,6 @@ export function ValueForm({ resource, propertyURL, datatype }: ValueFormProps) { const [editMode, setEditMode] = useState(false); const property = useProperty(propertyURL); const [value] = useValue(resource, propertyURL); - const store = useStore(); const { agent } = useSettings(); useHotkeys( 'esc', @@ -59,7 +52,7 @@ export function ValueForm({ resource, propertyURL, datatype }: ValueFormProps) { async function handleSave() { try { - await resource.save(store); + await resource.save(); setEditMode(false); toast.success('Resource saved'); } catch (e) { diff --git a/browser/data-browser/src/components/forms/hooks/useSaveResource.ts b/browser/data-browser/src/components/forms/hooks/useSaveResource.ts index 35d9bd721..98dac9ee6 100644 --- a/browser/data-browser/src/components/forms/hooks/useSaveResource.ts +++ b/browser/data-browser/src/components/forms/hooks/useSaveResource.ts @@ -29,7 +29,7 @@ export const useSaveResource = ( setErr(undefined); try { - await resource.save(store); + await resource.save(); setSaving(false); onSaveSucces?.(); toast.success('Resource saved'); diff --git a/browser/data-browser/src/handlers/sideBarHandler.ts b/browser/data-browser/src/handlers/sideBarHandler.ts index b088e3161..9a2f4a7d2 100644 --- a/browser/data-browser/src/handlers/sideBarHandler.ts +++ b/browser/data-browser/src/handlers/sideBarHandler.ts @@ -1,53 +1,50 @@ -import { Resource, Store, urls, isString } from '@tomic/react'; +import { Resource, Store, isString, dataBrowser, core } from '@tomic/react'; export function buildSideBarNewResourceHandler(store: Store) { // When a resource is saved add it to the parents subResources list if it's not already there. return async (resource: Resource) => { - const parentSubject = resource.get(urls.properties.parent); + const parentSubject = resource.get(core.properties.parent); if (!isString(parentSubject)) { - throw new Error( - `Resource doesn't have a parent: ${resource.getSubject()} `, - ); + throw new Error(`Resource doesn't have a parent: ${resource.subject} `); } - const parent = await store.getResourceAsync(parentSubject); - const subResources = parent.getSubjects(urls.properties.subResources); + const parent = await store.getResource(parentSubject); + const subResources = parent.getSubjects( + dataBrowser.properties.subResources, + ); - if (subResources.includes(resource.getSubject())) { + if (subResources.includes(resource.subject)) { return; } - await parent.pushPropVal(urls.properties.subResources, [ - resource.getSubject(), - ]); + parent.push(dataBrowser.properties.subResources, [resource.subject]); - await parent.save(store); + await parent.save(); }; } export function buildSideBarRemoveResourceHandler(store: Store) { // When a resource is deleted remove it from the parents subResources list. return async (resource: Resource) => { - const parentSubject = resource.get(urls.properties.parent); + const parentSubject = resource.get(core.properties.parent); if (!isString(parentSubject)) { - throw new Error( - `Resource doesn't have a parent: ${resource.getSubject()} `, - ); + throw new Error(`Resource doesn't have a parent: ${resource.subject} `); } - const parent = await store.getResourceAsync(parentSubject); - const subResources = parent.getSubjects(urls.properties.subResources); + const parent = await store.getResource(parentSubject); + const subResources = parent.getSubjects( + dataBrowser.properties.subResources, + ); if (subResources.length > 0) { await parent.set( - urls.properties.subResources, - subResources.filter(r => r !== resource.getSubject()), - store, + dataBrowser.properties.subResources, + subResources.filter(r => r !== resource.subject), ); - await parent.save(store); + await parent.save(); } }; } diff --git a/browser/data-browser/src/hooks/useCreateAndNavigate.ts b/browser/data-browser/src/hooks/useCreateAndNavigate.ts index b10a77e49..fab8e55f3 100644 --- a/browser/data-browser/src/hooks/useCreateAndNavigate.ts +++ b/browser/data-browser/src/hooks/useCreateAndNavigate.ts @@ -1,4 +1,4 @@ -import { Core, JSONValue, Resource, core, useStore } from '@tomic/react'; +import { Core, JSONValue, Resource, useStore } from '@tomic/react'; import { useCallback } from 'react'; import toast from 'react-hot-toast'; import { useNavigate } from 'react-router-dom'; @@ -30,7 +30,7 @@ export function useCreateAndNavigate(): CreateAndNavigate { /** Query parameters for the resource / endpoint */ extraParams?: Record, ): Promise => { - const classResource = await store.getResourceAsync(isA); + const classResource = await store.getResource(isA); const namePart = getNamePartFromProps(propVals); const newSubject = await store.buildUniqueSubjectFromParts( @@ -38,19 +38,15 @@ export function useCreateAndNavigate(): CreateAndNavigate { parent, ); - const resource = new Resource(newSubject, true); - - await resource.addClasses(store, isA); - - await Promise.all([ - ...Object.entries(propVals).map(([key, val]) => - resource.set(key, val, store), - ), - !!parent && resource.set(core.properties.parent, parent, store), - ]); + const resource = await store.newResource({ + subject: newSubject, + isA, + parent, + propVals, + }); try { - await resource.save(store); + await resource.save(); navigate(constructOpenURL(newSubject, extraParams)); toast.success(`${classResource.title} created`); store.notifyResourceManuallyCreated(resource); diff --git a/browser/data-browser/src/hooks/useSavedDrives.ts b/browser/data-browser/src/hooks/useSavedDrives.ts index 849780773..a58e1b2eb 100644 --- a/browser/data-browser/src/hooks/useSavedDrives.ts +++ b/browser/data-browser/src/hooks/useSavedDrives.ts @@ -1,4 +1,4 @@ -import { urls, useArray, useResource, useStore } from '@tomic/react'; +import { urls, useArray, useResource } from '@tomic/react'; import { useCallback, useMemo } from 'react'; import { isDev } from '../config'; import { useSettings } from '../helpers/AppSettings'; @@ -19,7 +19,6 @@ export function useSavedDrives(): [ remove: (drive: string) => void, ] { const { agent } = useSettings(); - const store = useStore(); const agentResource = useResource(agent?.subject); const [drives, setDrives] = useArray( agentResource, @@ -38,7 +37,7 @@ export function useSavedDrives(): [ if (!drives.includes(drive)) { setDrives([...drives, drive]).then(() => { - agentResource.save(store); + agentResource.save(); }); } }, @@ -54,7 +53,7 @@ export function useSavedDrives(): [ if (drives.includes(drive)) { setDrives(drives.filter(d => d !== drive)).then(() => { - agentResource.save(store); + agentResource.save(); }); } }, diff --git a/browser/data-browser/src/routes/DataRoute.tsx b/browser/data-browser/src/routes/DataRoute.tsx index 46daf9129..65104187a 100644 --- a/browser/data-browser/src/routes/DataRoute.tsx +++ b/browser/data-browser/src/routes/DataRoute.tsx @@ -1,10 +1,5 @@ import { useState } from 'react'; -import { - useResource, - useStore, - signRequest, - HeadersObject, -} from '@tomic/react'; +import { useResource, signRequest, HeadersObject } from '@tomic/react'; import AllProps from '../components/AllProps'; import { ContainerNarrow } from '../components/Containers'; @@ -35,7 +30,6 @@ function Data(): JSX.Element { const [textResponseLoading, setTextResponseLoading] = useState(false); const [err, setErr] = useState(undefined); const { agent } = useSettings(); - const store = useStore(); const navigate = useNavigate(); if (!subject) { @@ -110,7 +104,7 @@ function Data(): JSX.Element { {resource.commitError && ( {resource.commitError.message} )} - + ) : null}

Code

diff --git a/browser/data-browser/src/routes/History/HistoryRoute.tsx b/browser/data-browser/src/routes/History/HistoryRoute.tsx index f0d6f0fc0..e6ce50758 100644 --- a/browser/data-browser/src/routes/History/HistoryRoute.tsx +++ b/browser/data-browser/src/routes/History/HistoryRoute.tsx @@ -1,12 +1,12 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; -import { useResource, useStore, Version } from '@tomic/react'; +import { useResource, Version } from '@tomic/react'; import { ContainerNarrow } from '../../components/Containers'; import { useCurrentSubject } from '../../helpers/useCurrentSubject'; import { ErrorLook } from '../../components/ErrorLook'; import { styled } from 'styled-components'; import { useVersions } from './useVersions'; -import { groupVersionsByMonth, setResourceToVersion } from './versionHelpers'; +import { groupVersionsByMonth } from './versionHelpers'; import { toast } from 'react-hot-toast'; import { useNavigateWithTransition } from '../../hooks/useNavigateWithTransition'; import { constructOpenURL } from '../../helpers/navigation'; @@ -18,7 +18,6 @@ import { ProgressBar } from '../../components/ProgressBar'; /** Shows an activity log of previous versions */ export function History(): JSX.Element { - const store = useStore(); const navigate = useNavigateWithTransition(); const isSmallScreen = useMediaQuery('(max-width: 500px)'); const [subject] = useCurrentSubject(); @@ -38,7 +37,8 @@ export function History(): JSX.Element { const setResourceToCurrentVersion = async () => { if (selectedVersion && subject) { - await setResourceToVersion(resource, selectedVersion, store); + await resource.setVersion(selectedVersion); + toast.success('Resource version updated'); navigate(constructOpenURL(subject)); } diff --git a/browser/data-browser/src/routes/History/useVersions.ts b/browser/data-browser/src/routes/History/useVersions.ts index 02b84363f..06a28d7b8 100644 --- a/browser/data-browser/src/routes/History/useVersions.ts +++ b/browser/data-browser/src/routes/History/useVersions.ts @@ -1,4 +1,4 @@ -import { Resource, Version, unknownSubject, useStore } from '@tomic/react'; +import { Resource, Version, unknownSubject } from '@tomic/react'; import { useState, useEffect, useRef, useTransition } from 'react'; import { dedupeVersions } from './versionHelpers'; @@ -13,7 +13,6 @@ export function useVersions(resource: Resource): UseVersionsResult { const [versions, setVersions] = useState([]); const [progress, setProgress] = useState(0); const isRunning = useRef(false); - const store = useStore(); const [_, startTransition] = useTransition(); const [loading, setLoading] = useState(true); const [error, setError] = useState(undefined); @@ -31,7 +30,7 @@ export function useVersions(resource: Resource): UseVersionsResult { (async () => { try { isRunning.current = true; - const history = await resource.getHistory(store, setProgress); + const history = await resource.getHistory(setProgress); const dedupedVersions = dedupeVersions(history); setVersions(dedupedVersions); } catch (e) { diff --git a/browser/data-browser/src/routes/History/versionHelpers.ts b/browser/data-browser/src/routes/History/versionHelpers.ts index e9aa89186..aee9cc92d 100644 --- a/browser/data-browser/src/routes/History/versionHelpers.ts +++ b/browser/data-browser/src/routes/History/versionHelpers.ts @@ -1,4 +1,4 @@ -import { Resource, Store, Version } from '@tomic/react'; +import { Version } from '@tomic/react'; const groupFormatter = new Intl.DateTimeFormat('default', { month: 'long', @@ -35,27 +35,6 @@ export function dedupeVersions(versions: Version[]): Version[] { return filtered; } -export async function setResourceToVersion( - resource: Resource, - version: Version, - store: Store, -): Promise { - const versionPropvals = version.resource.getPropVals(); - - // Remove any prop that doesn't exist in the version - for (const prop of resource.getPropVals().keys()) { - if (!versionPropvals.has(prop)) { - resource.removePropVal(prop); - } - } - - for (const [key, value] of versionPropvals.entries()) { - await resource.set(key, value, store); - } - - await resource.save(store); -} - export function groupVersionsByMonth( versions: Version[], ): Record { diff --git a/browser/data-browser/src/routes/ShareRoute.tsx b/browser/data-browser/src/routes/ShareRoute.tsx index 5a28e8e6b..ee7c80356 100644 --- a/browser/data-browser/src/routes/ShareRoute.tsx +++ b/browser/data-browser/src/routes/ShareRoute.tsx @@ -1,12 +1,5 @@ import { useEffect, useState } from 'react'; -import { - Right, - urls, - useArray, - useCanWrite, - useResource, - useStore, -} from '@tomic/react'; +import { Right, urls, useArray, useCanWrite, useResource } from '@tomic/react'; import { ContainerNarrow } from '../components/Containers'; import { useCurrentSubject } from '../helpers/useCurrentSubject'; import { ResourceInline } from '../views/ResourceInline'; @@ -27,7 +20,6 @@ import { Main } from '../components/Main'; export function ShareRoute(): JSX.Element { const [subject] = useCurrentSubject(); const resource = useResource(subject); - const store = useStore(); const [canWrite] = useCanWrite(resource); const [showInviteForm, setShowInviteForm] = useState(false); const [err, setErr] = useState(undefined); @@ -53,7 +45,7 @@ export function ShareRoute(): JSX.Element { useEffect(() => { async function getTheRights() { - const allRights = await resource.getRights(store); + const allRights = await resource.getRights(); const inherited = allRights.filter(r => r.setIn !== subject); // Make sure the public agent is always the top of the list @@ -130,7 +122,7 @@ export function ShareRoute(): JSX.Element { async function handleSave() { try { - await resource.save(store); + await resource.save(); toast.success('Share settings saved'); navigate(constructOpenURL(subject!)); } catch (e) { diff --git a/browser/data-browser/src/views/Article/ArticleDescription.tsx b/browser/data-browser/src/views/Article/ArticleDescription.tsx index 0ad90d596..44032c941 100644 --- a/browser/data-browser/src/views/Article/ArticleDescription.tsx +++ b/browser/data-browser/src/views/Article/ArticleDescription.tsx @@ -1,4 +1,4 @@ -import { Resource, useString, properties, useStore } from '@tomic/react'; +import { Resource, useString, core } from '@tomic/react'; import { useState } from 'react'; import toast from 'react-hot-toast'; @@ -22,13 +22,12 @@ export function ArticleDescription({ resource, canEdit, }: ArticleDescriptionProps): JSX.Element { - const store = useStore(); - const [description] = useString(resource, properties.description); + const [description] = useString(resource, core.properties.description); const [editMode, setEditMode] = useState(false); const saveContent = async () => { try { - await resource.save(store); + await resource.save(); setEditMode(false); toast.success('Content saved'); } catch (e) { @@ -67,7 +66,7 @@ export function ArticleDescription({ <>
diff --git a/browser/data-browser/src/views/BookmarkPage/usePreview.ts b/browser/data-browser/src/views/BookmarkPage/usePreview.ts index 376947549..394d3f726 100644 --- a/browser/data-browser/src/views/BookmarkPage/usePreview.ts +++ b/browser/data-browser/src/views/BookmarkPage/usePreview.ts @@ -1,5 +1,5 @@ import { AtomicError, ErrorType } from './../../../../lib/src/error'; -import { Resource, Store, urls, useStore, useString } from '@tomic/react'; +import { Resource, urls, useStore, useString } from '@tomic/react'; import { startTransition, useCallback, useEffect, useState } from 'react'; import { debounce } from '../../helpers/debounce'; import { paths } from '../../routes/paths'; @@ -12,8 +12,8 @@ type UsePreviewReturnType = { loading: boolean; }; -async function fetchBookmarkData(url: string, name = '', store: Store) { - const bookmarkRoute = new URL(paths.fetchBookmark, store.getServerUrl()); +async function fetchBookmarkData(url: string, name = '', baseUrl: string) { + const bookmarkRoute = new URL(paths.fetchBookmark, baseUrl); const searchParams = new URLSearchParams({ name, @@ -42,7 +42,7 @@ const debouncedFetch = debounce( ( url: string, name: string | undefined, - store: Store, + baseUrl: string, resource: Resource, setPreview: AtomicSetter, setName: AtomicSetter, @@ -52,7 +52,7 @@ const debouncedFetch = debounce( setDescription: AtomicSetter, ) => { startTransition(() => { - fetchBookmarkData(url, name, store) + fetchBookmarkData(url, name, baseUrl) .then(async res => { await Promise.all([ setPreview(res.preview), @@ -63,7 +63,7 @@ const debouncedFetch = debounce( setError(undefined); setLoading(false); - resource.save(store); + resource.save(); }) .catch(err => { console.error(err); @@ -107,7 +107,7 @@ export function usePreview(resource: Resource): UsePreviewReturnType { debouncedFetch( websiteURL, name, - store, + store.getServerUrl(), resource, setPreview, setName, diff --git a/browser/data-browser/src/views/ChatRoomPage.tsx b/browser/data-browser/src/views/ChatRoomPage.tsx index 533ad532a..8468f8cf0 100644 --- a/browser/data-browser/src/views/ChatRoomPage.tsx +++ b/browser/data-browser/src/views/ChatRoomPage.tsx @@ -1,8 +1,8 @@ import { - classes, + commits, + core, + dataBrowser, getTimestampNow, - properties, - Resource, useArray, useResource, useStore, @@ -28,7 +28,7 @@ import { ResourcePageProps } from './ResourcePage'; /** Full page ChatRoom that shows a message list and a form to add Messages. */ export function ChatRoomPage({ resource }: ResourcePageProps) { - const [messages] = useArray(resource, properties.chatRoom.messages); + const [messages] = useArray(resource, dataBrowser.properties.messages); const [newMessageVal, setNewMessage] = useState(''); const store = useStore(); const [isReplyTo, setReplyTo] = useState(undefined); @@ -75,37 +75,21 @@ export function ChatRoomPage({ resource }: ResourcePageProps) { if (!disableSend) { const subject = store.createSubject('messages', resource.getSubject()); - const msgResource = new Resource(subject, true); - await msgResource.set( - properties.parent, - resource.getSubject(), - store, - false, - ); - await msgResource.set(properties.isA, [classes.message], store, false); - await msgResource.set( - properties.description, - newMessageVal, - store, - false, - ); - await msgResource.set( - properties.commit.createdAt, - getTimestampNow(), - store, - false, - ); - - if (isReplyTo) { - await msgResource.set( - properties.chatRoom.replyTo, - isReplyTo, - store, - false, - ); - } - - await msgResource.save(store); + + const msgResource = await store.newResource({ + subject, + parent: resource.subject, + isA: dataBrowser.classes.message, + propVals: { + [core.properties.description]: newMessageVal, + [commits.properties.createdAt]: getTimestampNow(), + ...(isReplyTo && { + [dataBrowser.properties.replyTo]: isReplyTo, + }), + }, + }); + + await msgResource.save(); setReplyTo(undefined); } } catch (err) { @@ -200,9 +184,9 @@ const MESSAGE_MAX_LEN = 500; /** Single message shown in a ChatRoom */ const Message = memo(function Message({ subject, setReplyTo }: MessageProps) { const resource = useResource(subject); - const [description] = useString(resource, properties.description); - const [lastCommit] = useSubject(resource, properties.commit.lastCommit); - const [replyTo] = useSubject(resource, properties.chatRoom.replyTo); + const [description] = useString(resource, core.properties.description); + const [lastCommit] = useSubject(resource, commits.properties.lastCommit); + const [replyTo] = useSubject(resource, dataBrowser.properties.replyTo); const navigate = useNavigate(); function handleCopyUrl() { @@ -255,7 +239,7 @@ const Message = memo(function Message({ subject, setReplyTo }: MessageProps) { - + ); }); @@ -269,12 +253,12 @@ const MESSAGE_LINE_MAX_LEN = 50; /** Small single line preview of a message, useful in replies */ function MessageLine({ subject }: MessageLineProps) { const resource = useResource(subject); - const [description] = useString(resource, properties.description); - const [lastCommit] = useSubject(resource, properties.commit.lastCommit); + const [description] = useString(resource, core.properties.description); + const [lastCommit] = useSubject(resource, commits.properties.lastCommit); // Traverse path to find the author const commitResource = useResource(lastCommit); - const [signer] = useSubject(commitResource, properties.commit.signer); + const [signer] = useSubject(commitResource, commits.properties.signer); if (!resource.isReady() || !commitResource.isReady()) { return loading...; @@ -408,8 +392,8 @@ interface MessagesPageProps { /** Shows Messages for this page. Recursively fetches the next page, if in view */ function MessagesPage({ subject, setReplyTo }: MessagesPageProps) { const resource = useResource(subject); - const [messages] = useArray(resource, properties.chatRoom.messages); - const [nextPage] = useString(resource, properties.chatRoom.nextPage); + const [messages] = useArray(resource, dataBrowser.properties.messages); + const [nextPage] = useString(resource, dataBrowser.properties.nextPage); if (!resource.isReady()) { return <>loading...; diff --git a/browser/data-browser/src/views/DocumentPage.tsx b/browser/data-browser/src/views/DocumentPage.tsx index 916aaaf34..547b5c081 100644 --- a/browser/data-browser/src/views/DocumentPage.tsx +++ b/browser/data-browser/src/views/DocumentPage.tsx @@ -3,12 +3,11 @@ import { useState } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; import { Resource, - properties, - classes, useArray, useCanWrite, useStore, - useString, + dataBrowser, + core, } from '@tomic/react'; import { styled } from 'styled-components'; import { FaEdit, FaEye, FaGripVertical } from 'react-icons/fa'; @@ -71,7 +70,7 @@ function DocumentPageEdit({ }: DocumentSubPageProps): JSX.Element { const [elements, setElements] = useArray( resource, - properties.document.elements, + dataBrowser.properties.elements, { commit: false, validate: false, commitDebounce: 0 }, ); @@ -187,24 +186,24 @@ function DocumentPageEdit({ async function addElement(position: number) { // When an element is created, it should be a Resource that has this document as its parent. // or maybe a nested resource? - const elementSubject = store.createSubject( - 'element', - resource.getSubject(), - ); + const elementSubject = store.createSubject('element', resource.subject); const newElements = [...elements]; newElements.splice(position, 0, elementSubject); try { - const newElement = new Resource(elementSubject, true); - await Promise.all([ - newElement.set(properties.isA, [classes.elements.paragraph], store), - newElement.set(properties.parent, resource.getSubject(), store), - newElement.set(properties.description, '', store), - ]); + const newElement = await store.newResource({ + subject: elementSubject, + isA: dataBrowser.classes.paragraph, + parent: resource.subject, + propVals: { + [core.properties.description]: '', + }, + }); + await setElements(newElements); focusElement(position); - await newElement.save(store); - await resource.save(store); + await newElement.save(); + await resource.save(); } catch (e) { setErr(e); } @@ -237,7 +236,7 @@ function DocumentPageEdit({ if (elements.length === 1) { setElements([]); focusElement(0); - resource.save(store); + resource.save(); return; } @@ -245,7 +244,7 @@ function DocumentPageEdit({ elements.splice(number, 1); setElements([...elements]); focusElement(number - 1); - resource.save(store); + resource.save(); } /** Sets the subject for a specific element and moves to the next element */ @@ -257,7 +256,7 @@ function DocumentPageEdit({ addElement(index + 1); } else { focusElement(index + 1); - resource.save(store); + resource.save(); } } @@ -267,7 +266,7 @@ function DocumentPageEdit({ elements.splice(to, 0, element); setElements([...elements]); focusElement(to); - resource.save(store); + resource.save(); } function handleSortEnd(event: DragEndEvent): void { @@ -290,15 +289,15 @@ function DocumentPageEdit({ toast.success('Upload succeeded!'); fileSubjects.map(subject => elements.push(subject)); setElements([...elements]); - resource.save(store); + resource.save(); } /** Add a new line, or move to the last line if it is empty */ async function handleNewLineMaybe() { const lastSubject = elements[elements.length - 1]; - const lastElem = await store.getResourceAsync(lastSubject); + const lastElem = await store.getResource(lastSubject); - if (lastElem.get(properties.description)?.toString()?.length === 0) { + if (lastElem.get(core.properties.description)?.toString()?.length === 0) { focusElement(elements.length - 1); } else { addElement(elements.length); @@ -361,13 +360,12 @@ function DocumentPageShow({ resource, setEditMode, }: DocumentSubPageProps): JSX.Element { - const [elements] = useArray(resource, properties.document.elements); - const [title] = useString(resource, properties.name); + const [elements] = useArray(resource, dataBrowser.properties.elements); return ( <>
-

{title}

+

{resource.title}