Environments data routing (#6127)

* update environments to use data routing

* upgrade react-router for json api in actions

* check for the proper route in the modal

* remove ?

* fix git url construction

* fix lint issues

* logs
This commit is contained in:
James Gatz
2023-07-11 12:47:39 +02:00
committed by GitHub
parent da13df909a
commit 64fe218c2e
9 changed files with 318 additions and 166 deletions

View File

@@ -140,7 +140,7 @@
"react-dnd-html5-backend": "^7.4.4",
"react-dom": "^18.2.0",
"react-redux": "^7.2.6",
"react-router-dom": "^6.4.2",
"react-router-dom": "^6.14.1",
"react-stately": "3.21.0",
"react-use": "^17.4.0",
"redux": "^4.1.2",
@@ -4471,9 +4471,10 @@
}
},
"node_modules/@remix-run/router": {
"version": "1.0.2",
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.7.1.tgz",
"integrity": "sha512-bgVQM4ZJ2u2CM8k1ey70o1ePFXsEzYVZoWghh6WjM8p59jQ7HxzbHW4SbnWFG7V9ig9chLawQxDTZ3xzOF8MkQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
}
@@ -15958,11 +15959,12 @@
}
},
"node_modules/react-router": {
"version": "6.4.2",
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.14.1.tgz",
"integrity": "sha512-U4PfgvG55LdvbQjg5Y9QRWyVxIdO1LlpYT7x+tMAxd9/vmiPuJhIwdxZuIQLN/9e3O4KFDHYfR9gzGeYMasW8g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@remix-run/router": "1.0.2"
"@remix-run/router": "1.7.1"
},
"engines": {
"node": ">=14"
@@ -15972,12 +15974,13 @@
}
},
"node_modules/react-router-dom": {
"version": "6.4.2",
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.14.1.tgz",
"integrity": "sha512-ssF6M5UkQjHK70fgukCJyjlda0Dgono2QGwqGvuk7D+EDGHdacEN3Yke2LTMjkrpHuFwBfDFsEjGVXBDmL+bWw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@remix-run/router": "1.0.2",
"react-router": "6.4.2"
"@remix-run/router": "1.7.1",
"react-router": "6.14.1"
},
"engines": {
"node": ">=14"

View File

@@ -189,7 +189,7 @@
"react-dnd-html5-backend": "^7.4.4",
"react-dom": "^18.2.0",
"react-redux": "^7.2.6",
"react-router-dom": "^6.4.2",
"react-router-dom": "^6.14.1",
"react-stately": "3.21.0",
"react-use": "^17.4.0",
"redux": "^4.1.2",

View File

@@ -30,8 +30,8 @@ export const httpClient = {
}
return {
url: response.request.res.responseUrl,
method: response.request.method,
url: config.url,
method: config.method,
headers: response.headers,
body: [response.data],
statusCode: response.status,

View File

@@ -1,9 +1,10 @@
import React, { FC, useCallback, useRef } from 'react';
import { useSelector } from 'react-redux';
import { useFetcher, useParams, useRouteLoaderData } from 'react-router-dom';
import * as models from '../../../models';
import type { Environment } from '../../../models/environment';
import { selectActiveWorkspaceMeta, selectEnvironments, selectHotKeyRegistry } from '../../redux/selectors';
import { selectHotKeyRegistry } from '../../redux/selectors';
import { WorkspaceLoaderData } from '../../routes/workspace';
import { Dropdown, DropdownButton, type DropdownHandle, DropdownItem, DropdownSection, ItemContent } from '../base/dropdown';
import { useDocBodyKeyboardShortcuts } from '../keydown-binder';
import { showModal } from '../modals/index';
@@ -15,13 +16,17 @@ interface Props {
workspaceId: string;
}
export const EnvironmentsDropdown: FC<Props> = ({
activeEnvironment,
workspaceId,
}) => {
const environments = useSelector(selectEnvironments);
export const EnvironmentsDropdown: FC<Props> = () => {
const { organizationId, projectId, workspaceId } = useParams<{ organizationId: string; projectId: string; workspaceId: string}>();
const {
baseEnvironment,
activeEnvironment,
subEnvironments,
} = useRouteLoaderData(
':workspaceId'
) as WorkspaceLoaderData;
const hotKeyRegistry = useSelector(selectHotKeyRegistry);
const activeWorkspaceMeta = useSelector(selectActiveWorkspaceMeta);
const setActiveEnvironmentFetcher = useFetcher();
const dropdownRef = useRef<DropdownHandle>(null);
const toggleSwitchMenu = useCallback(() => {
@@ -33,10 +38,6 @@ export const EnvironmentsDropdown: FC<Props> = ({
});
// NOTE: Base environment might not exist if the users hasn't managed environments yet.
const baseEnvironment = environments.find(environment => environment.parentId === workspaceId);
const subEnvironments = environments
.filter(environment => environment.parentId === (baseEnvironment && baseEnvironment._id))
.sort((e1, e2) => e1.metaSortKey - e2.metaSortKey);
const description = (!activeEnvironment || activeEnvironment === baseEnvironment) ? 'No Environment' : activeEnvironment.name;
return (
@@ -83,9 +84,13 @@ export const EnvironmentsDropdown: FC<Props> = ({
...(environment.color ? { color: environment.color } : {}),
}}
onClick={() => {
if (activeWorkspaceMeta) {
models.workspaceMeta.update(activeWorkspaceMeta, { activeEnvironmentId: environment._id });
}
setActiveEnvironmentFetcher.submit({
environmentId: environment._id,
},
{
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/environment/set-active`,
});
}}
/>
</DropdownItem>
@@ -97,9 +102,13 @@ export const EnvironmentsDropdown: FC<Props> = ({
icon="empty"
label="No Environment"
onClick={() => {
if (activeWorkspaceMeta) {
models.workspaceMeta.update(activeWorkspaceMeta, { activeEnvironmentId: null });
}
setActiveEnvironmentFetcher.submit({
environmentId: baseEnvironment._id,
},
{
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/environment/set-active`,
});
}}
/>
</DropdownItem>

View File

@@ -1,13 +1,14 @@
import classnames from 'classnames';
import React, { FC, forwardRef, Fragment, useImperativeHandle, useRef, useState } from 'react';
import React, { FC, forwardRef, Fragment, useImperativeHandle, useRef } from 'react';
import { ListDropTargetDelegate, ListKeyboardDelegate, mergeProps, useDraggableCollection, useDraggableItem, useDropIndicator, useDroppableCollection, useDroppableItem, useFocusRing, useListBox, useOption } from 'react-aria';
import { useSelector } from 'react-redux';
import { useFetcher, useParams, useRouteLoaderData } from 'react-router-dom';
import { DraggableCollectionState, DroppableCollectionState, Item, ListState, useDraggableCollectionState, useDroppableCollectionState, useListState } from 'react-stately';
import { docsTemplateTags } from '../../../common/documentation';
import * as models from '../../../models';
import type { Environment } from '../../../models/environment';
import { selectActiveWorkspace, selectActiveWorkspaceMeta, selectEnvironments } from '../../redux/selectors';
import { selectActiveWorkspaceMeta } from '../../redux/selectors';
import { WorkspaceLoaderData } from '../../routes/workspace';
import { Dropdown, DropdownButton, DropdownItem, ItemContent } from '../base/dropdown';
import { Editable } from '../base/editable';
import { Link } from '../base/link';
@@ -224,107 +225,83 @@ const ReorderableListBox = props => {
</ul>
);
};
interface State {
baseEnvironment: Environment | null;
selectedEnvironmentId: string | null;
}
export interface WorkspaceEnvironmentsEditModalHandle {
show: () => void;
hide: () => void;
}
export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEditModalHandle, ModalProps>((props, ref) => {
const { organizationId, projectId, workspaceId } = useParams<{ organizationId: string; projectId: string; workspaceId: string}>();
const routeData = useRouteLoaderData(
':workspaceId'
) as WorkspaceLoaderData;
const modalRef = useRef<ModalHandle>(null);
const environmentEditorRef = useRef<EnvironmentEditorHandle>(null);
const inputRef = useRef<HTMLInputElement>(null);
const [state, setState] = useState<State>({
baseEnvironment: null,
selectedEnvironmentId: null,
});
const createEnvironmentFetcher = useFetcher();
const deleteEnvironmentFetcher = useFetcher();
const updateEnvironmentFetcher = useFetcher();
const setActiveEnvironmentFetcher = useFetcher();
const duplicateEnvironmentFetcher = useFetcher();
const workspace = useSelector(selectActiveWorkspace);
const workspaceMeta = useSelector(selectActiveWorkspaceMeta);
const environments = useSelector(selectEnvironments);
useImperativeHandle(ref, () => ({
hide: () => {
modalRef.current?.hide();
},
show: async () => {
if (!workspace) {
return;
}
const baseEnvironment = await models.environment.getOrCreateForParentId(workspace._id);
setState(state => ({
...state,
baseEnvironment,
selectedEnvironmentId: workspaceMeta?.activeEnvironmentId || baseEnvironment._id,
}));
modalRef.current?.show();
},
}), [workspace, workspaceMeta?.activeEnvironmentId]);
}), []);
if (!routeData) {
return null;
}
const {
baseEnvironment,
activeWorkspaceMeta,
activeEnvironment,
subEnvironments,
} = routeData;
function onSelectionChange(e: any) {
const environmentId = e.anchorKey;
// Only switch if valid
if (environmentEditorRef.current?.isValid() && e.anchorKey) {
const environment = subEnvironments.filter(evt => evt._id === e.anchorKey)[0];
setState(state => ({
...state,
selectedEnvironmentId: environment._id || null,
}));
if (workspaceMeta?.activeEnvironmentId !== environment._id && workspaceMeta) {
models.workspaceMeta.update(workspaceMeta, { activeEnvironmentId: environment._id });
}
if (environmentEditorRef.current?.isValid() && activeWorkspaceMeta?.activeEnvironmentId !== environmentId) {
setActiveEnvironmentFetcher.submit({
environmentId,
},
{
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/environment/set-active`,
});
}
}
async function handleDeleteEnvironment(environmentId: string | null) {
// Don't delete the root environment
if (!environmentId || environmentId === state.baseEnvironment?._id) {
return;
}
// Unset active environment if it's being deleted
if (workspaceMeta?.activeEnvironmentId === environmentId && workspaceMeta) {
models.workspaceMeta.update(workspaceMeta, { activeEnvironmentId: null });
}
// Delete the current one
const current = environments.find(e => e._id === environmentId);
current && models.environment.remove(current);
setState(state => ({
...state,
selectedEnvironmentId: state.baseEnvironment?._id || null,
}));
async function handleDeleteEnvironment(environmentId: string) {
deleteEnvironmentFetcher.submit({
environmentId,
},
{
encType: 'application/json',
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/environment/delete`,
});
}
const updateEnvironment = async (environmentId: string | null, patch: Partial<Environment>) => {
if (environmentId === null) {
return;
}
// NOTE: Fetch the environment first because it might not be up to date.
const realEnvironment = await models.environment.getById(environmentId);
if (realEnvironment) {
const updated = await models.environment.update(realEnvironment, patch);
// reload the root environment if it changed since its not updated by redux
const isBaseEnvironment = realEnvironment?.parentId === workspace?._id;
if (isBaseEnvironment) {
setState({ ...state, baseEnvironment: updated });
}
}
const updateEnvironment = async (environmentId: string, patch: Partial<Environment>) => {
updateEnvironmentFetcher.submit({
patch,
environmentId,
},
{
encType: 'application/json',
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/environment/update`,
});
};
const { baseEnvironment, selectedEnvironmentId } = state;
const selectedEnvironment = baseEnvironment?._id === selectedEnvironmentId
? baseEnvironment
: environments.filter(e => e.parentId === baseEnvironment?._id).find(subEnvironment => subEnvironment._id === selectedEnvironmentId) || null;
const selectedEnvironmentName = selectedEnvironment?.name || '';
const selectedEnvironmentColor = selectedEnvironment?.color || null;
const subEnvironments = environments
.filter(environment => environment.parentId === (baseEnvironment && baseEnvironment._id))
.sort((e1, e2) => e1.metaSortKey - e2.metaSortKey);
if (inputRef.current && selectedEnvironmentColor) {
inputRef.current.value = selectedEnvironmentColor;
}
function onReorder(e: any) {
const source = [...e.keys][0];
const sourceEnv = subEnvironments.find(evt => evt._id === source);
@@ -349,16 +326,19 @@ export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEd
<div className="env-modal__sidebar">
<div
className={classnames('env-modal__sidebar-root-item', {
'env-modal__sidebar-item--active': selectedEnvironmentId === baseEnvironment?._id,
'env-modal__sidebar-item--active': activeEnvironment._id === baseEnvironment._id,
})}
>
<button
onClick={() => {
if (environmentEditorRef.current?.isValid() && selectedEnvironmentId !== baseEnvironment?._id) {
baseEnvironment?._id && setState(state => ({
...state,
selectedEnvironmentId: baseEnvironment?._id,
}));
if (environmentEditorRef.current?.isValid() && activeEnvironment._id !== baseEnvironment._id) {
setActiveEnvironmentFetcher.submit({
environmentId: baseEnvironment._id,
},
{
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/environment/set-active`,
});
}
}}
>
@@ -387,16 +367,14 @@ export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEd
icon="eye"
label="Environment"
onClick={async () => {
if (baseEnvironment) {
const environment = await models.environment.create({
parentId: baseEnvironment._id,
isPrivate: false,
});
setState(state => ({
...state,
selectedEnvironmentId: environment._id,
}));
}
createEnvironmentFetcher.submit({
isPrivate: false,
},
{
encType: 'application/json',
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/environment/create`,
});
}}
/>
</DropdownItem>
@@ -405,16 +383,14 @@ export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEd
icon="eye-slash"
label="Private Environment"
onClick={async () => {
if (baseEnvironment) {
const environment = await models.environment.create({
parentId: baseEnvironment._id,
isPrivate: true,
});
setState(state => ({
...state,
selectedEnvironmentId: environment._id,
}));
}
createEnvironmentFetcher.submit({
isPrivate: true,
},
{
encType: 'application/json',
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/environment/create`,
});
}}
/>
</DropdownItem>
@@ -438,29 +414,29 @@ export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEd
<div className="env-modal__main">
<div className="env-modal__main__header">
<h1>
{baseEnvironment?._id === selectedEnvironmentId ? (
{baseEnvironment._id === activeEnvironment._id ? (
ROOT_ENVIRONMENT_NAME
) : (
<Editable
singleClick
className="wide"
onSubmit={name => {
if (selectedEnvironmentId && name) {
updateEnvironment(selectedEnvironmentId, { name });
if (activeEnvironment._id && name) {
updateEnvironment(activeEnvironment._id, { name });
}
}}
value={selectedEnvironmentName}
value={activeEnvironment.name}
/>
)}
</h1>
{selectedEnvironmentId && baseEnvironment?._id !== selectedEnvironmentId ? (
{baseEnvironment._id !== activeEnvironment._id ? (
<Fragment>
<input
className="hidden"
type="color"
ref={inputRef}
onChange={event => updateEnvironment(selectedEnvironmentId, { color: event.target.value })}
onChange={event => updateEnvironment(activeEnvironment._id, { color: event.target.value })}
/>
<Dropdown
@@ -471,11 +447,11 @@ export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEd
className="btn btn--clicky"
disableHoverBehavior={false}
>
{selectedEnvironmentColor && (
{activeEnvironment.color && (
<i
className="fa fa-circle space-right"
style={{
color: selectedEnvironmentColor,
color: activeEnvironment.color,
}}
/>
)}
@@ -483,18 +459,18 @@ export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEd
</DropdownButton>
}
>
<DropdownItem aria-label={selectedEnvironmentColor ? 'Change Color' : 'Assign Color'}>
<DropdownItem aria-label={activeEnvironment.color ? 'Change Color' : 'Assign Color'}>
<ItemContent
icon="circle"
label={selectedEnvironmentColor ? 'Change Color' : 'Assign Color'}
label={activeEnvironment.color ? 'Change Color' : 'Assign Color'}
iconStyle={{
...(selectedEnvironmentColor ? { color: selectedEnvironmentColor } : {}),
...(activeEnvironment.color ? { color: activeEnvironment.color } : {}),
}}
onClick={() => {
if (!selectedEnvironmentColor) {
if (!activeEnvironment.color) {
// TODO: fix magic-number. Currently this is the `surprise` background color for the default theme,
// but we should be grabbing the actual value from the user's actual theme instead.
updateEnvironment(selectedEnvironmentId, { color: '#7d69cb' });
updateEnvironment(activeEnvironment._id, { color: '#7d69cb' });
}
inputRef.current?.click();
}}
@@ -503,22 +479,24 @@ export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEd
<DropdownItem aria-label='Unset Color'>
<ItemContent
isDisabled={!selectedEnvironmentColor}
isDisabled={!activeEnvironment.color}
icon="minus-circle"
label="Unset Color"
onClick={() => updateEnvironment(selectedEnvironmentId, { color: null })}
onClick={() => updateEnvironment(activeEnvironment._id, { color: null })}
/>
</DropdownItem>
</Dropdown>
<button
onClick={async () => {
if (selectedEnvironment) {
const newEnvironment = await models.environment.duplicate(selectedEnvironment);
setState(state => ({
...state,
selectedEnvironmentId: newEnvironment._id,
}));
if (activeEnvironment) {
duplicateEnvironmentFetcher.submit({
environmentId: activeEnvironment._id,
}, {
encType: 'application/json',
method: 'post',
action: `/organization/${organizationId}/project/${projectId}/workspace/${workspaceId}/environment/duplicate`,
});
}
}}
className="btn btn--clicky space-right"
@@ -526,22 +504,22 @@ export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEd
<i className="fa fa-copy" /> Duplicate
</button>
<PromptButton
onClick={() => handleDeleteEnvironment(selectedEnvironmentId)}
{activeEnvironment._id !== baseEnvironment._id && <PromptButton
onClick={() => handleDeleteEnvironment(activeEnvironment._id)}
className="btn btn--clicky"
>
<i className="fa fa-trash-o" />
</PromptButton>
</PromptButton>}
</Fragment>
) : null}
</div>
<div className="env-modal__editor">
<EnvironmentEditor
ref={environmentEditorRef}
key={`${selectedEnvironmentId || 'n/a'}`}
key={`${activeEnvironment._id}`}
environmentInfo={{
object: selectedEnvironment?.data || {},
propertyOrder: selectedEnvironment?.dataPropertyOrder || null,
object: activeEnvironment.data,
propertyOrder: activeEnvironment.dataPropertyOrder,
}}
onBlur={() => {
// Only save if it's valid
@@ -549,8 +527,8 @@ export const WorkspaceEnvironmentsEditModal = forwardRef<WorkspaceEnvironmentsEd
return;
}
const data = environmentEditorRef.current?.getValue();
if (selectedEnvironment && data) {
updateEnvironment(selectedEnvironmentId, {
if (activeEnvironment && data) {
updateEnvironment(activeEnvironment._id, {
data: data.object,
dataPropertyOrder: data.propertyOrder,
});

View File

@@ -166,6 +166,31 @@ const router = createMemoryRouter(
},
],
},
{
path: 'environment',
children: [
{
path: 'update',
action: async (...args) => (await import('./routes/actions')).updateEnvironment(...args),
},
{
path: 'delete',
action: async (...args) => (await import('./routes/actions')).deleteEnvironmentAction(...args),
},
{
path: 'create',
action: async (...args) => (await import('./routes/actions')).createEnvironmentAction(...args),
},
{
path: 'duplicate',
action: async (...args) => (await import('./routes/actions')).duplicateEnvironmentAction(...args),
},
{
path: 'set-active',
action: async (...args) => (await import('./routes/actions')).setActiveEnvironmentAction(...args),
},
],
},
{
path: 'test/*',
loader: async (...args) => (await import('./routes/unit-test')).loader(...args),

View File

@@ -778,3 +778,111 @@ export const accessAIApiAction: ActionFunction = async ({ params }) => {
return { enabled: false };
}
};
export const createEnvironmentAction: ActionFunction = async ({
params,
request,
}) => {
const { workspaceId } = params;
invariant(typeof workspaceId === 'string', 'Workspace ID is required');
const { isPrivate } = await request.json();
const baseEnvironment = await models.environment.getByParentId(workspaceId);
invariant(baseEnvironment, 'Base environment not found');
const environment = await models.environment.create({
parentId: baseEnvironment._id,
isPrivate,
});
return environment;
};
export const updateEnvironment: ActionFunction = async ({ request, params }) => {
const { workspaceId } = params;
invariant(typeof workspaceId === 'string', 'Workspace ID is required');
const { environmentId, patch } = await request.json();
invariant(typeof environmentId === 'string', 'Environment ID is required');
const environment = await models.environment.getById(environmentId);
invariant(environment, 'Environment not found');
invariant(typeof name === 'string', 'Name is required');
const baseEnvironment = await models.environment.getByParentId(workspaceId);
invariant(baseEnvironment, 'Base environment not found');
const updatedEnvironment = await models.environment.update(environment, patch);
return updatedEnvironment;
};
export const deleteEnvironmentAction: ActionFunction = async ({
request, params,
}) => {
const { workspaceId } = params;
invariant(typeof workspaceId === 'string', 'Workspace ID is required');
const formData = await request.formData();
const environmentId = formData.get('environmentId');
invariant(typeof environmentId === 'string', 'Environment ID is required');
const environment = await models.environment.getById(environmentId);
const baseEnvironment = await models.environment.getByParentId(workspaceId);
invariant(environment?._id !== baseEnvironment?._id, 'Cannot delete base environment');
invariant(environment, 'Environment not found');
await models.environment.remove(environment);
return null;
};
export const duplicateEnvironmentAction: ActionFunction = async ({
request, params,
}) => {
const { workspaceId } = params;
invariant(typeof workspaceId === 'string', 'Workspace ID is required');
const { environmentId } = await request.json();
invariant(typeof environmentId === 'string', 'Environment ID is required');
const environment = await models.environment.getById(environmentId);
invariant(environment, 'Environment not found');
const newEnvironment = await models.environment.duplicate(environment);
return newEnvironment;
};
export const setActiveEnvironmentAction: ActionFunction = async ({
request, params,
}) => {
const { workspaceId } = params;
invariant(typeof workspaceId === 'string', 'Workspace ID is required');
const formData = await request.formData();
const environmentId = formData.get('environmentId');
console.log('environmentId', environmentId);
invariant(typeof environmentId === 'string', 'Environment ID is required');
const workspaceMeta = await models.workspaceMeta.getOrCreateByParentId(workspaceId);
invariant(workspaceMeta, 'Workspace meta not found');
// @TODO - Null vs undefined vs empty string
await models.workspaceMeta.update(workspaceMeta, { activeEnvironmentId: environmentId || null });
return null;
};

View File

@@ -658,6 +658,16 @@ export const loader: LoaderFunction = async ({
const project = await models.project.getById(projectId);
console.log({
project,
});
const allProjects = await models.project.all();
console.log({
allProjects,
});
invariant(project, 'Project was not found');
const projectWorkspaces = await models.workspace.findByParentId(project._id);
@@ -752,7 +762,7 @@ export const loader: LoaderFunction = async ({
)?.indexes) : true)
.sort((a, b) => sortMethodMap[sortOrder as DashboardSortOrder](a, b));
const allProjects = await models.project.all();
// const allProjects = await models.project.all();
const organizationProjects =
organizationId === DEFAULT_ORGANIZATION_ID

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { LoaderFunction, Outlet, useLoaderData } from 'react-router-dom';
import * as models from '../../models';
import { Environment } from '../../models/environment';
import { GitRepository } from '../../models/git-repository';
import { Project } from '../../models/project';
import { Workspace } from '../../models/workspace';
@@ -12,6 +13,9 @@ export interface WorkspaceLoaderData {
activeWorkspaceMeta?: WorkspaceMeta;
activeProject: Project;
gitRepository: GitRepository | null;
activeEnvironment: Environment;
baseEnvironment: Environment;
subEnvironments: Environment[];
}
export const workspaceLoader: LoaderFunction = async ({
@@ -31,14 +35,29 @@ export const workspaceLoader: LoaderFunction = async ({
const activeProject = await models.project.getById(projectId);
invariant(activeProject, 'Project not found');
const activeWorkspaceMeta = await models.workspaceMeta.getOrCreateByParentId(workspaceId);
const gitRepository = await models.gitRepository.getById(activeWorkspaceMeta.gitRepositoryId || '');
const activeWorkspaceMeta = await models.workspaceMeta.getOrCreateByParentId(
workspaceId,
);
const gitRepository = await models.gitRepository.getById(
activeWorkspaceMeta.gitRepositoryId || '',
);
const baseEnvironment = await models.environment.getByParentId(workspaceId);
invariant(baseEnvironment, 'Base environment not found');
const subEnvironments = (await models.environment.findByParentId(baseEnvironment._id))
.sort((e1, e2) => e1.metaSortKey - e2.metaSortKey);
const activeEnvironment = subEnvironments.find(({ _id }) => activeWorkspaceMeta.activeEnvironmentId === _id) || baseEnvironment;
return {
activeWorkspace,
activeProject,
gitRepository,
activeWorkspaceMeta,
activeEnvironment,
subEnvironments,
baseEnvironment,
};
};