Skip to content

Commit

Permalink
Documentation, add Collections new form #747
Browse files Browse the repository at this point in the history
  • Loading branch information
joepio committed Jan 8, 2024
1 parent dffb202 commit bb690f4
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { dataBrowser, core, classes, server } from '@tomic/react';
import { registerBasicInstanceHandler } from '../useNewResourceUI';

/**
* These handlers do not show any UI / inputs when creating new instances.
* This is where they can have hardcoded default values or custom logic.
*/
export const registerBasicInstanceHandlers = () => {
registerBasicInstanceHandler(
dataBrowser.classes.folder,
Expand Down Expand Up @@ -29,20 +33,6 @@ export const registerBasicInstanceHandlers = () => {
},
);

registerBasicInstanceHandler(
dataBrowser.classes.folder,
async (parent, createAndNavigate) => {
await createAndNavigate(
dataBrowser.classes.folder,
{
[core.properties.name]: 'Untitled Folder',
[dataBrowser.properties.displayStyle]: classes.displayStyles.list,
},
parent,
);
},
);

registerBasicInstanceHandler(
dataBrowser.classes.document,
async (parent, createAndNavigate) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { JSONValue, collections, core } from '@tomic/react';
import { useState, useCallback, FormEvent, useEffect, FC } from 'react';
import { Button } from '../../../../Button';
import {
useDialog,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
} from '../../../../Dialog';
import Field from '../../../Field';
import { InputWrapper, InputStyled } from '../../../InputStyles';
import { CustomResourceDialogProps } from '../../useNewResourceUI';
import { useCreateAndNavigate } from '../../../../../hooks/useCreateAndNavigate';
import { ResourceSelector } from '../../../ResourceSelector';

export const NewCollectionDialog: FC<CustomResourceDialogProps> = ({
parent,
onClose,
}) => {
const [name, setName] = useState('New Collection');
const [valueFilter, setValue] = useState<string | undefined>();
const [propertyFilter, setProperty] = useState<string | undefined>();

const [dialogProps, show, hide] = useDialog({ onCancel: onClose });

const createResourceAndNavigate = useCreateAndNavigate();

const onDone = useCallback(
(e: FormEvent) => {
e.preventDefault();

createResourceAndNavigate(
collections.classes.collection,
{
[core.properties.name]: name,
[collections.properties.value]: valueFilter,
[collections.properties.property]: propertyFilter,
[collections.properties.pageSize]: 30,
[collections.properties.currentPage]: 0,
},
parent,
);

onClose();
},
[valueFilter, onClose, propertyFilter],
);

useEffect(() => {
show();
}, []);

return (
<Dialog {...dialogProps}>
<DialogTitle>
<h1>New Collection</h1>
</DialogTitle>
<DialogContent>
<form onSubmit={onDone}>
<Field required label='name'>
<InputWrapper>
<InputStyled
placeholder='Name your Collection'
value={name}
autoFocus={true}
onChange={e => setName(e.target.value)}
/>
</InputWrapper>
</Field>
<Field label='property'>
<div>
<ResourceSelector
isA={core.classes.property}
setSubject={setProperty}
value={propertyFilter}
/>
</div>
</Field>
<Field label='value'>
<InputWrapper>
<InputStyled
placeholder='Set a value filter (optional)'
value={valueFilter}
onChange={e => setValue(e.target.value)}
/>
</InputWrapper>
</Field>
</form>
</DialogContent>
<DialogActions>
<Button onClick={() => hide(false)} subtle>
Cancel
</Button>
<Button onClick={onDone} disabled={!propertyFilter && !valueFilter}>
Ok
</Button>
</DialogActions>
</Dialog>
);
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { dataBrowser, core } from '@tomic/react';
import { dataBrowser, core, collections } from '@tomic/react';
import { registerNewResourceDialog } from '../../useNewResourceUI';
import { NewBookmarkDialog } from './NewBookmarkDialog';
import { NewOntologyDialog } from './NewOntologyDialog';
import { NewTableDialog } from './NewTableDialog';
import { NewCollectionDialog } from './NewCollectionDialog';

export const registerCustomForms = () => {
registerNewResourceDialog(dataBrowser.classes.bookmark, NewBookmarkDialog);
registerNewResourceDialog(core.classes.ontology, NewOntologyDialog);
registerNewResourceDialog(dataBrowser.classes.table, NewTableDialog);
registerNewResourceDialog(
collections.classes.collection,
NewCollectionDialog,
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { properties, useResource, useString, useTitle } from '@tomic/react';
import { useState } from 'react';
import { FaInfo } from 'react-icons/fa';
import { AtomicLink } from '../../AtomicLink';
import { Button } from '../../Button';
import Markdown from '../../datatypes/Markdown';
import { Column, Row } from '../../Row';
import styled from 'styled-components';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface CustomResourceDialogProps {
onClose: () => void;
}

/** When creating a new resource, the matched handler is called */
export type BasicInstanceHandler = (
parent: string,
createAndNavigate: CreateAndNavigate,
Expand All @@ -37,19 +38,28 @@ interface NewResourceUIContext {
const dialogs = new Map<string, FC<CustomResourceDialogProps>>();
const basicNewInstanceHandlers = new Map<string, BasicInstanceHandler>();

/**
* Returns a function that when called, renders UI to create a new Resource of the given class.
*
* Use {@link registerNewResourceDialog} to register a custom dialog for a given class.
*/
export function useNewResourceUI() {
const { showNewResourceUI } = useContext(NewResourceUIContext);

return showNewResourceUI;
}

/** Call this when adding a new custom New Resource Form / Dialog. */
export const registerNewResourceDialog = (
classSubject: string,
component: FC<CustomResourceDialogProps>,
) => {
dialogs.set(classSubject, component);
};

/** Call this when adding a new custom action for a New Resource that does _not_ require inputs.
* For example, creating a new Folder does not require any inputs, so it can be handled without any UI.
*/
export const registerBasicInstanceHandler = (
classSubject: string,
handler: BasicInstanceHandler,
Expand All @@ -61,6 +71,7 @@ const NewResourceUIContext = createContext<NewResourceUIContext>({
showNewResourceUI: () => undefined,
});

/** Renders the Dialog used when creating new resources. */
export function NewResourceUIProvider({ children }: PropsWithChildren) {
const store = useStore();
const settings = useSettings();
Expand Down
2 changes: 1 addition & 1 deletion browser/data-browser/src/hooks/useCreateAndNavigate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type CreateAndNavigate = (
* Hook that builds a function that will create a new resource with the given
* properties and then navigate to it.
*
* @returns A createAndNavigate function.
* @returns A {@link CreateAndNavigate} function.
*/
export function useCreateAndNavigate(): CreateAndNavigate {
const store = useStore();
Expand Down

0 comments on commit bb690f4

Please sign in to comment.