Skip to content

Commit

Permalink
Merge pull request #3931 from signalco-io/feat/doprocess/public-access
Browse files Browse the repository at this point in the history
feat(doprocess): Public access to entities
  • Loading branch information
AleksandarDev authored Nov 24, 2023
2 parents 2f46df9 + 7af6ed7 commit 1135064
Show file tree
Hide file tree
Showing 36 changed files with 394 additions and 83 deletions.
9 changes: 6 additions & 3 deletions web/apps/doprocess/app/api/documents/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { documentDelete, documentGet, documentRename, documentSetData, getDocumentIdByPublicId } from '../../../../src/lib/repo/documentsRepository';
import { ensureUserId } from '../../../../src/lib/auth/apiAuth';
import { documentDelete, documentGet, documentRename, documentSetData, documentSetSharedWithUsers, getDocumentIdByPublicId } from '../../../../src/lib/repo/documentsRepository';
import { ensureUserId, optionalUserId } from '../../../../src/lib/auth/apiAuth';
import { requiredParamString } from '../../../../src/lib/api/apiParam';

export async function GET(_request: Request, { params }: { params: { id: string } }) {
const documentPublicId = requiredParamString(params.id);
const { userId } = ensureUserId();
const { userId } = optionalUserId();

const documentId = await getDocumentIdByPublicId(documentPublicId);
if (documentId == null)
Expand All @@ -31,6 +31,9 @@ export async function PUT(request: Request, { params }: { params: { id: string }
if ('data' in data && typeof data.data === 'string') {
await documentSetData(userId, documentId, data.data);
}
if ('sharedWithUsers' in data && Array.isArray(data.sharedWithUsers) && data.sharedWithUsers.every(x => typeof x === 'string')) {
await documentSetSharedWithUsers(userId, documentId, data.sharedWithUsers as string[]);
}
}
return Response.json(null);
}
Expand Down
9 changes: 6 additions & 3 deletions web/apps/doprocess/app/api/processes/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { deleteProcess, getProcess, getProcessIdByPublicId, renameProcess } from '../../../../src/lib/repo/processesRepository';
import { ensureUserId } from '../../../../src/lib/auth/apiAuth';
import { deleteProcess, getProcess, getProcessIdByPublicId, processShareWithUsers, renameProcess } from '../../../../src/lib/repo/processesRepository';
import { ensureUserId, optionalUserId } from '../../../../src/lib/auth/apiAuth';
import { requiredParamString } from '../../../../src/lib/api/apiParam';

export async function GET(_request: Request, { params }: { params: { id: string } }) {
const processPublicId = requiredParamString(params.id);

const { userId } = ensureUserId();
const { userId } = optionalUserId();

const processId = await getProcessIdByPublicId(processPublicId);
if (processId == null)
Expand All @@ -32,6 +32,9 @@ export async function PUT(request: Request, { params }: { params: { id: string }
if (data != null && typeof data === 'object' && 'name' in data && typeof data.name === 'string') {
await renameProcess(userId, processId, data.name);
}
if (data != null && typeof data === 'object' && 'sharedWithUsers' in data && Array.isArray(data.sharedWithUsers) && data.sharedWithUsers.every(x => typeof x === 'string')) {
await processShareWithUsers(userId, processId, data.sharedWithUsers as string[]);
}

return Response.json(null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { deleteProcessRun, getProcessIdByPublicId, getProcessRun, getProcessRunIdByPublicId, renameProcessRun } from '../../../../../../src/lib/repo/processesRepository';
import { ensureUserId } from '../../../../../../src/lib/auth/apiAuth';
import { ensureUserId, optionalUserId } from '../../../../../../src/lib/auth/apiAuth';
import { requiredParamString } from '../../../../../../src/lib/api/apiParam';

export async function GET(_request: Request, { params }: { params: { id: string, runId: string } }) {
const processPublicId = requiredParamString(params.id);
const runPublicId = requiredParamString(params.runId);

const { userId } = ensureUserId();
const { userId } = optionalUserId();

const processId = await getProcessIdByPublicId(processPublicId);
if (processId == null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { getProcessIdByPublicId, getProcessRunIdByPublicId, getTaskDefinitionIdByPublicId, getTaskDefinitions, getTasks, setTaskState } from '../../../../../../../src/lib/repo/processesRepository';
import { ensureUserId } from '../../../../../../../src/lib/auth/apiAuth';
import { ensureUserId, optionalUserId } from '../../../../../../../src/lib/auth/apiAuth';
import { requiredParamString } from '../../../../../../../src/lib/api/apiParam';

export async function GET(_request: Request, { params }: { params: { id: string, runId: string } }) {
const processPublicId = requiredParamString(params.id);
const runPublicId = requiredParamString(params.runId);
const { userId } = ensureUserId();
const { userId } = optionalUserId();

const processId = await getProcessIdByPublicId(processPublicId);
if (processId == null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { changeTaskDefinitionOrder, changeTaskDefinitionText, changeTaskDefinitionType, deleteTaskDefinition, getProcess, getProcessIdByPublicId, getTaskDefinition, getTaskDefinitionIdByPublicId } from '../../../../../../src/lib/repo/processesRepository';
import { documentCreate, documentGet } from '../../../../../../src/lib/repo/documentsRepository';
import { ensureUserId } from '../../../../../../src/lib/auth/apiAuth';
import { ensureUserId, optionalUserId } from '../../../../../../src/lib/auth/apiAuth';
import { requiredParamString } from '../../../../../../src/lib/api/apiParam';

export async function GET(_request: Request, { params }: { params: { id: string, taskDefinitionId: string } }) {
const processPublicId = requiredParamString(params.id);
const taskDefinitionPublicId = requiredParamString(params.taskDefinitionId);

const { userId } = ensureUserId();
const { userId } = optionalUserId();

const processId = await getProcessIdByPublicId(processPublicId);
if (processId == null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { createTaskDefinition, getProcessIdByPublicId, getTaskDefinition, getTaskDefinitions } from '../../../../../src/lib/repo/processesRepository';
import { ensureUserId } from '../../../../../src/lib/auth/apiAuth';
import { ensureUserId, optionalUserId } from '../../../../../src/lib/auth/apiAuth';
import { requiredParamString } from '../../../../../src/lib/api/apiParam';

export async function GET(_request: Request, { params }: { params: { id: string } }) {
const processPublicId = requiredParamString(params.id);

const { userId } = ensureUserId();
const { userId } = optionalUserId();

const processId = await getProcessIdByPublicId(processPublicId);
if (processId == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Tooltip } from '@signalco/ui-primitives/Tooltip';
import { Stack } from '@signalco/ui-primitives/Stack';
import { Input } from '@signalco/ui-primitives/Input';
import { Button } from '@signalco/ui-primitives/Button';
import { showNotification } from '@signalco/ui-notifications';
import { Add } from '@signalco/ui-icons';
import { KnownPages } from '../../../src/knownPages';
import { useDocumentCreate } from '../../../src/hooks/useDocumentCreate';
Expand All @@ -15,11 +16,16 @@ export function DocumentCreateForm({ redirect }: { redirect: boolean; }) {
const createProcess = useDocumentCreate();

const handleDocumentCreate = async () => {
const response = await createProcess.mutateAsync({
name,
});
if (redirect && response?.id)
router.push(KnownPages.Document(response.id));
try {
const response = await createProcess.mutateAsync({
name,
});
if (redirect && response?.id)
router.push(KnownPages.Document(response.id));
} catch (error) {
console.error(error);
showNotification('Failed to create document', 'error');
}
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import { useState } from 'react';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@signalco/ui-primitives/Menu';
import { IconButton } from '@signalco/ui-primitives/IconButton';
import { cx } from '@signalco/ui-primitives/cx';
import { Delete, Embed, MoreHorizontal } from '@signalco/ui-icons';
import { Delete, Embed, Globe, MoreHorizontal } from '@signalco/ui-icons';
import { Toolbar } from '../../shared/Toolbar';
import { ShareModal } from '../../shared/ShareModal';
import { SavingIndicator } from '../../shared/SavingIndicator';
import { EmbedModal } from '../../shared/EmbedModal';
import { ShareableEntity } from '../../../src/types/ShareableEntity';
import { KnownPages } from '../../../src/knownPages';
import { useDocumentUpdate } from '../../../src/hooks/useDocumentUpdate';
import { useDocument } from '../../../src/hooks/useDocument';
import { DocumentDeleteModal } from './DocumentDeleteModal';

Expand All @@ -21,11 +24,31 @@ export function DocumentDetailsToolbar({ id, saving }: DocumentDetailsToolbarPro
const { data: document } = useDocument(id);
const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const [embedOpen, setEmbedOpen] = useState(false);
const [sharePublicOpen, setSharePublicOpen] = useState(false);

const isPublic = document && document.sharedWithUsers.includes('public');
const documentUpdate = useDocumentUpdate();
const handleShare = async (shareableEntity: ShareableEntity) => {
await documentUpdate.mutateAsync({
id,
sharedWithUsers: shareableEntity.sharedWithUsers
});
};

return (
<>
<Toolbar>
<SavingIndicator saving={saving} />
{document && (
<ShareModal
header={`Share ${document.name}`}
shareableEntity={document}
open={sharePublicOpen}
src={`https://doprocess.app${KnownPages.Document(id)}`}
hideTrigger={!isPublic}
onOpenChange={setSharePublicOpen}
onShareChange={handleShare} />
)}
<DropdownMenu>
<DropdownMenuTrigger
asChild
Expand All @@ -37,8 +60,13 @@ export function DocumentDetailsToolbar({ id, saving }: DocumentDetailsToolbarPro
</IconButton>
</DropdownMenuTrigger>
<DropdownMenuContent>
{!isPublic && (
<DropdownMenuItem startDecorator={<Globe />} onClick={() => setSharePublicOpen(true)}>
Make public...
</DropdownMenuItem>
)}
<DropdownMenuItem startDecorator={<Embed />} onClick={() => setEmbedOpen(true)}>
Embed...
Embed...
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem startDecorator={<Delete />} onClick={() => setDeleteModalOpen(true)}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
'use client';

import { SignedIn, SignedOut } from '@clerk/nextjs';
import { List } from '../../shared/List';
import { InAppCtaSignUp } from '../../shared/InAppCtaSignUp';
import { useDocuments } from '../../../src/hooks/useDocuments';
import { DocumentsListItem } from './DocumentsListItem';
import { DocumentCreateForm } from './DocumentCreateForm';

export function DocumentsList() {
return (
<List
query={useDocuments}
itemRender={(item) => (<DocumentsListItem document={item} />)}
editable
itemCreateLabel="New document"
createForm={<DocumentCreateForm redirect />}
/>
<>
<SignedIn>
<List
query={useDocuments}
itemRender={(item) => (<DocumentsListItem document={item} />)}
editable
itemCreateLabel="New document"
createForm={<DocumentCreateForm redirect />}
/>
</SignedIn>
<SignedOut>
<InAppCtaSignUp />
</SignedOut>
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Row } from '@signalco/ui-primitives/Row';
import { FileText, Navigate } from '@signalco/ui-icons';
import { SharedWithIndicator } from '../../shared/SharedWithIndicator';
import { ListItem } from '../../shared/ListItem';
import { KnownPages } from '../../../src/knownPages';
import { DocumentDto } from '../../../app/api/dtos/dtos';
Expand All @@ -12,7 +14,12 @@ export function DocumentsListItem({ document }: DocumentsListItemProps) {
<ListItem
label={document.name}
startDecorator={<FileText />}
endDecorator={<Navigate className="opacity-0 group-hover:opacity-100" />}
endDecorator={(
<Row spacing={1}>
<SharedWithIndicator shareableEntity={document} />
<Navigate className="opacity-0 group-hover:opacity-100" />
</Row>
)}
className="group w-full"
href={KnownPages.Document(document.id)} />
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type ProcessDetailsProps = {
export function ProcessDetails({ id, runId, editable }: ProcessDetailsProps) {
return (
<>
<Stack spacing={2}>
<Stack spacing={1}>
<ProcessDetailsHeader
processId={id}
runId={runId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ import { Row } from '@signalco/ui-primitives/Row';
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@signalco/ui-primitives/Menu';
import { IconButton } from '@signalco/ui-primitives/IconButton';
import { cx } from '@signalco/ui-primitives/cx';
import { Delete, Embed, ListChecks, MoreHorizontal, Play } from '@signalco/ui-icons';
import { Delete, Embed, Globe, ListChecks, MoreHorizontal, Play } from '@signalco/ui-icons';
import { Loadable } from '@signalco/ui/Loadable';
import { ShareModal } from '../../shared/ShareModal';
import { SharedWithIndicator } from '../../shared/SharedWithIndicator';
import { ListHeader } from '../../shared/ListHeader';
import { EmbedModal } from '../../shared/EmbedModal';
import { ShareableEntity } from '../../../src/types/ShareableEntity';
import { KnownPages } from '../../../src/knownPages';
import { useProcessUpdate } from '../../../src/hooks/useProcessUpdate';
import { useProcess } from '../../../src/hooks/useProcess';
import { TypographyProcessRunName } from './TypographyProcessRunName';
import { TypographyProcessName } from './TypographyProcessName';
Expand All @@ -30,9 +34,19 @@ export function ProcessDetailsHeader({
const { data: process, isLoading: isLoadingProcess, error: errorProcess } = useProcess(processId);
const [deleteOpen, setDeleteOpen] = useState(false);
const [embedOpen, setEmbedOpen] = useState(false);
const [shareOpen, setShareOpen] = useState(false);

const isRun = Boolean(runId);

const isPublic = process && process.sharedWithUsers.includes('public');
const processUpdate = useProcessUpdate();
const handleShare = async (shareableEntity: ShareableEntity) => {
await processUpdate.mutateAsync({
processId,
sharedWithUsers: shareableEntity.sharedWithUsers
});
};

return (
<Loadable
isLoading={isLoadingProcess}
Expand All @@ -59,8 +73,13 @@ export function ProcessDetailsHeader({
</IconButton>
</DropdownMenuTrigger>
<DropdownMenuContent>
{!isPublic && (
<DropdownMenuItem startDecorator={<Globe />} onClick={() => setShareOpen(true)}>
Make public...
</DropdownMenuItem>
)}
<DropdownMenuItem startDecorator={<Embed />} onClick={() => setEmbedOpen(true)}>
Embed...
Embed...
</DropdownMenuItem>
{!isRun && (
<DropdownMenuItem startDecorator={<Play />} href={KnownPages.ProcessRuns(processId)}>
Expand All @@ -74,13 +93,27 @@ export function ProcessDetailsHeader({
</DropdownMenuContent>
</DropdownMenu>
)
]} />
{runId && (
<Row spacing={1} className="self-end">
<Typography level="body3">Progress:</Typography>
<RunProgress processId={processId} runId={runId} />
</Row>
)}
]}
/>
<Row spacing={1} justifyContent="end">
{process && (
<ShareModal
header={`Share ${process.name}`}
tertiary
hideTrigger={!isPublic}
shareableEntity={process}
open={shareOpen}
onOpenChange={setShareOpen}
onShareChange={handleShare}
src={`https://doprocess.app/${KnownPages.Process(processId)}`} />
)}
{runId && (
<Row spacing={0.5}>
<Typography level="body3">Progress:</Typography>
<RunProgress processId={processId} runId={runId} />
</Row>
)}
</Row>
</Stack>
<ProcessOrRunDeleteModal
processId={processId}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
'use client';

import { SignedIn, SignedOut } from '@clerk/nextjs';
import { List } from '../../shared/List';
import { InAppCtaSignUp } from '../../shared/InAppCtaSignUp';
import { useProcesses } from '../../../src/hooks/useProcesses';
import { ProcessesListItem } from './ProcessesListItem';
import { ProcessCreateForm } from './ProcessCreateForm';

export function ProcessesList() {
return (
<List
query={useProcesses}
itemRender={(item) => (<ProcessesListItem process={item} />)}
editable
itemCreateLabel="New process"
createForm={<ProcessCreateForm redirect />} />
<>
<SignedIn>
<List
query={useProcesses}
itemRender={(item) => (<ProcessesListItem process={item} />)}
editable
itemCreateLabel="New process"
createForm={<ProcessCreateForm redirect />} />
</SignedIn>
<SignedOut>
<InAppCtaSignUp />
</SignedOut>
</>
);
}
Loading

0 comments on commit 1135064

Please sign in to comment.