Started on environment edit dialog

This commit is contained in:
Gregory Schier
2023-10-23 21:00:36 -07:00
parent 83e2cab1b6
commit fa16e1f957
9 changed files with 125 additions and 50 deletions

View File

@@ -343,6 +343,22 @@ async fn create_workspace(
emit_and_return(&window, "created_model", created_workspace)
}
#[tauri::command]
async fn create_environment(
workspace_id: &str,
name: &str,
window: Window<Wry>,
db_instance: State<'_, Mutex<Pool<Sqlite>>>,
) -> Result<models::Environment, String> {
let pool = &*db_instance.lock().await;
let data: HashMap<String, JsonValue> = HashMap::new();
let created_environment = models::create_environment(workspace_id, name, data, pool)
.await
.expect("Failed to create environment");
emit_and_return(&window, "created_model", created_environment)
}
#[tauri::command]
async fn create_request(
workspace_id: &str,
@@ -639,6 +655,7 @@ fn main() {
})
})
.invoke_handler(tauri::generate_handler![
create_environment,
create_request,
create_workspace,
delete_all_responses,

View File

@@ -5,7 +5,6 @@ import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { HelmetProvider } from 'react-helmet-async';
import { AppRouter } from './AppRouter';
import { DialogProvider } from './DialogContext';
const queryClient = new QueryClient({
logger: undefined,
@@ -24,12 +23,10 @@ export function App() {
<MotionConfig transition={{ duration: 0.1 }}>
<HelmetProvider>
<DndProvider backend={HTML5Backend}>
<DialogProvider>
<Suspense>
<AppRouter />
{/*<ReactQueryDevtools initialIsOpen={false} />*/}
</Suspense>
</DialogProvider>
</DndProvider>
</HelmetProvider>
</MotionConfig>

View File

@@ -6,6 +6,7 @@ import { GlobalHooks } from './GlobalHooks';
import RouteError from './RouteError';
import Workspace from './Workspace';
import Workspaces from './Workspaces';
import { DialogProvider } from './DialogContext';
const router = createBrowserRouter([
{
@@ -59,9 +60,9 @@ function WorkspaceOrRedirect() {
function Layout() {
return (
<>
<DialogProvider>
<Outlet />
<GlobalHooks />
</>
</DialogProvider>
);
}

View File

@@ -1,6 +1,8 @@
import React, { createContext, useContext, useMemo, useState } from 'react';
import type { DialogProps } from './core/Dialog';
import { Dialog } from './core/Dialog';
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
type DialogEntry = {
id: string;
@@ -54,9 +56,11 @@ export const DialogProvider = ({ children }: { children: React.ReactNode }) => {
function DialogInstance({ id, render, ...props }: DialogEntry) {
const { actions } = useContext(DialogContext);
const children = render({ hide: () => actions.hide(id) });
console.log("ACITEV WORKSPAXCE ID 2", useActiveWorkspaceId());
return (
<Dialog open onClose={() => actions.hide(id)} {...props}>
{render({ hide: () => actions.hide(id) })}
{children}
</Dialog>
);
}

View File

@@ -0,0 +1,69 @@
import { useState } from 'react';
import { useCreateEnvironment } from '../hooks/useCreateEnvironment';
import { useEnvironments } from '../hooks/useEnvironments';
import { usePrompt } from '../hooks/usePrompt';
import { useUpdateEnvironment } from '../hooks/useUpdateEnvironment';
import type { Environment } from '../lib/models';
import { Button } from './core/Button';
import { Editor } from './core/Editor';
import classnames from 'classnames';
export const EnvironmentEditDialog = function () {
const prompt = usePrompt();
const environments = useEnvironments();
const createEnvironment = useCreateEnvironment();
const [activeEnvironment, setActiveEnvironment] = useState<Environment | null>(null);
return (
<div className="h-full grid gap-3 grid-cols-[auto_minmax(0,1fr)]">
<aside className="h-full min-w-[120px] pr-3 border-r border-gray-200">
{environments.map((e) => (
<Button
className={classnames('w-full', activeEnvironment?.id === e.id && 'bg-highlight')}
justify="start"
key={e.id}
onClick={() => {
setActiveEnvironment(e);
}}
>
{e.name}
</Button>
))}
<Button
color="gray"
onClick={async () => {
const name = await prompt({
title: 'Environment Name',
defaultValue: 'My Env',
label: 'Name',
name: 'environment',
});
createEnvironment.mutate({ name });
}}
>
Create Environment
</Button>
</aside>
{activeEnvironment != null && <EnvironmentEditor environment={activeEnvironment} />}
</div>
);
};
const EnvironmentEditor = function ({ environment }: { environment: Environment }) {
const updateEnvironment = useUpdateEnvironment(environment.id);
return (
<Editor
contentType="application/json"
className="w-full min-h-[40px] !bg-gray-50"
defaultValue={JSON.stringify(environment.data, null, 2)}
forceUpdateKey={environment.id}
onChange={(data) => {
try {
updateEnvironment.mutate({ data: JSON.parse(data) });
} catch (err) {
// That's okay
}
}}
/>
);
};

View File

@@ -40,7 +40,7 @@ export function Overlay({ zIndex = 30, open, onClose, portalName, children }: Pr
{children}
</motion.div>
</FocusTrap>
)}
)}
</Portal>
);
}

View File

@@ -9,17 +9,13 @@ import { SidebarActions } from './SidebarActions';
import { WorkspaceActionsDropdown } from './WorkspaceActionsDropdown';
import { Button } from './core/Button';
import { useDialog } from './DialogContext';
import { useEnvironments } from '../hooks/useEnvironments';
import type { Environment } from '../lib/models';
import { Editor } from './core/Editor';
import { useUpdateEnvironment } from '../hooks/useUpdateEnvironment';
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
interface Props {
className?: string;
}
export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Props) {
const environments = useEnvironments();
const activeRequest = useActiveRequest();
const dialog = useDialog();
@@ -35,14 +31,8 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
<Button onClick={() => {
dialog.show({
title: 'Environments',
render: () => <div>
{environments.map(e => (
<EnvironmentList
key={e.id}
environment={e}
/>
))}
</div>
size: 'full',
render: () => <EnvironmentEditDialog />,
})
}}>
Environments
@@ -66,28 +56,3 @@ export const WorkspaceHeader = memo(function WorkspaceHeader({ className }: Prop
</HStack>
);
});
interface EnvironmentListProps {
environment: Environment;
}
const EnvironmentList = function({ environment }: EnvironmentListProps) {
const updateEnvironment = useUpdateEnvironment(environment.id)
return (
<div>
<h1>{environment.name}</h1>
<Editor
contentType="application/json"
className='w-full h-[400px] !bg-gray-50'
defaultValue={JSON.stringify(environment.data, null, 2)}
onChange={data => {
try {
updateEnvironment.mutate({ data: JSON.parse(data) });
} catch (err) {
// That's okay
}
}}
/>
</div>
);
};

View File

@@ -54,11 +54,11 @@ export function Dialog({
className={classnames(
className,
'relative bg-gray-50 pointer-events-auto',
'max-h-[80vh] p-5 rounded-lg overflow-auto',
'p-5 rounded-lg overflow-auto',
'dark:border border-highlight shadow shadow-black/10',
size === 'sm' && 'w-[25rem]',
size === 'md' && 'w-[45rem]',
size === 'full' && 'w-[80vw]',
size === 'sm' && 'w-[25rem] max-h-[80vh]',
size === 'md' && 'w-[45rem] max-h-[80vh]',
size === 'full' && 'w-[calc(100vw-8em)] h-[calc(100vh-8em)]',
size === 'dynamic' && 'min-w-[30vw] max-w-[80vw]',
)}
>
@@ -66,7 +66,7 @@ export function Dialog({
{title}
</Heading>
{description && <p id={descriptionId}>{description}</p>}
<div className="mt-4">{children}</div>
<div className="h-full w-full mt-4">{children}</div>
{/*Put close at the end so that it's the last thing to be tabbed to*/}
{!hideX && (

View File

@@ -0,0 +1,22 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { invoke } from '@tauri-apps/api';
import type { Environment } from '../lib/models';
import { environmentsQueryKey } from './useEnvironments';
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
export function useCreateEnvironment() {
const workspaceId = useActiveWorkspaceId();
const queryClient = useQueryClient();
return useMutation<Environment, unknown, Pick<Environment, 'name'>>({
mutationFn: (patch) => {
return invoke('create_environment', { ...patch, workspaceId });
},
onSuccess: async (environment) => {
if (workspaceId == null) return;
queryClient.setQueryData<Environment[]>(environmentsQueryKey({ workspaceId }), (environments) => [
...(environments ?? []),
environment,
]);
},
});
}