Skip to content

Commit

Permalink
Update dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
mustard-mh committed Nov 23, 2023
1 parent b897f2c commit a8c3b73
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 179 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
* See License.AGPL.txt in the project root for license information.
*/

import { SupportedWorkspaceClass } from "@gitpod/gitpod-protocol/lib/workspace-class";
import { FC, useCallback, useEffect, useMemo } from "react";
import WorkspaceClass from "../icons/WorkspaceClass.svg";
import WorkspaceClassIcon from "../icons/WorkspaceClass.svg";
import { Combobox, ComboboxElement, ComboboxSelectedItem } from "./podkit/combobox/Combobox";
import { useWorkspaceClasses } from "../data/workspaces/workspace-classes-query";
import { WorkspaceClass } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";

interface SelectWorkspaceClassProps {
selectedWorkspaceClass?: string;
Expand Down Expand Up @@ -78,7 +78,7 @@ export default function SelectWorkspaceClassComponent({
}

type WorkspaceClassDropDownElementSelectedProps = {
wsClass?: SupportedWorkspaceClass;
wsClass?: WorkspaceClass;
loading?: boolean;
};

Expand All @@ -90,7 +90,7 @@ const WorkspaceClassDropDownElementSelected: FC<WorkspaceClassDropDownElementSel

return (
<ComboboxSelectedItem
icon={WorkspaceClass}
icon={WorkspaceClassIcon}
loading={loading}
htmlTitle={title}
title={<div className="truncate">{title}</div>}
Expand All @@ -106,7 +106,7 @@ const WorkspaceClassDropDownElementSelected: FC<WorkspaceClassDropDownElementSel
);
};

function WorkspaceClassDropDownElement(props: { wsClass: SupportedWorkspaceClass }): JSX.Element {
function WorkspaceClassDropDownElement(props: { wsClass: WorkspaceClass }): JSX.Element {
const c = props.wsClass;
return (
<div className="flex ml-1 mt-1 flex-grow">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* See License.AGPL.txt in the project root for license information.
*/

import { useQuery } from "@tanstack/react-query";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { useCurrentOrg } from "../organizations/orgs-query";
import { workspaceClient } from "../../service/public-api";
import { Workspace } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
Expand Down Expand Up @@ -57,3 +57,19 @@ export function getListWorkspacesQueryKey(orgId?: string) {
}
return ["workspaces", "list", orgId];
}

export const useUpdateWorkspaceInCache = () => {
const queryClient = useQueryClient();
const org = useCurrentOrg();
return (newWorkspace: Workspace) => {
const queryKey = getListWorkspacesQueryKey(org.data?.id);
queryClient.setQueryData<ListWorkspacesQueryResult>(queryKey, (oldWorkspacesData) => {
return oldWorkspacesData?.map((info) => {
if (info.id !== newWorkspace.id) {
return info;
}
return newWorkspace;
});
});
};
};

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License.AGPL.txt in the project root for license information.
*/

import { useMutation } from "@tanstack/react-query";
import { useUpdateWorkspaceInCache } from "./list-workspaces-query";
import { UpdateWorkspaceRequest } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
import { PartialMessage } from "@bufbuild/protobuf";
import { workspaceClient } from "../../service/public-api";

export const useUpdateWorkspaceMutation = () => {
const updateWorkspace = useUpdateWorkspaceInCache();

return useMutation({
mutationFn: async (data: PartialMessage<UpdateWorkspaceRequest>) => {
return await workspaceClient.updateWorkspace(data);
},
onSuccess: (data) => {
if (data.workspace) {
updateWorkspace(data.workspace);
}
},
});
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
* See License.AGPL.txt in the project root for license information.
*/

import { SupportedWorkspaceClass } from "@gitpod/gitpod-protocol/lib/workspace-class";
import { useQuery } from "@tanstack/react-query";
import { getGitpodService } from "../../service/service";
import { workspaceClient } from "../../service/public-api";
import { WorkspaceClass } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";

export const useWorkspaceClasses = () => {
return useQuery<SupportedWorkspaceClass[]>({
return useQuery<WorkspaceClass[]>({
queryKey: ["workspace-classes"],
queryFn: async () => {
return getGitpodService().server.getSupportedWorkspaceClasses();
const response = await workspaceClient.listWorkspaceClasses({});
return response.workspaceClasses;
},
cacheTime: 1000 * 60 * 60, // 1h
staleTime: 1000 * 60 * 60, // 1h
Expand Down
24 changes: 12 additions & 12 deletions components/dashboard/src/workspaces/RenameWorkspaceModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,42 @@

import { FunctionComponent, useCallback, useState } from "react";
import Modal, { ModalBody, ModalFooter, ModalHeader } from "../components/Modal";
import { useUpdateWorkspaceDescriptionMutation } from "../data/workspaces/update-workspace-description-mutation";
import { Button } from "../components/Button";
import { Workspace } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
import { useUpdateWorkspaceMutation } from "../data/workspaces/update-workspace-mutation";

type Props = {
workspace: Workspace;
onClose(): void;
};
export const RenameWorkspaceModal: FunctionComponent<Props> = ({ workspace, onClose }) => {
const [errorMessage, setErrorMessage] = useState("");
const [description, setDescription] = useState(workspace.name || "");
const updateDescription = useUpdateWorkspaceDescriptionMutation();
const [name, setName] = useState(workspace.name || "");
const updateWorkspace = useUpdateWorkspaceMutation();

const updateWorkspaceDescription = useCallback(async () => {
try {
if (description.length === 0) {
if (name.length === 0) {
setErrorMessage("Description cannot not be empty.");
return;
}

if (description.length > 250) {
if (name.length > 250) {
setErrorMessage("Description is too long for readability.");
return;
}

setErrorMessage("");

// Using mutateAsync here so we can close the modal after it completes successfully
await updateDescription.mutateAsync({ workspaceId: workspace.id, newDescription: description });
await updateWorkspace.mutateAsync({ workspaceId: workspace.id, name });

// Close the modal
onClose();
} catch (error) {
setErrorMessage("Something went wrong. Please try renaming again.");
}
}, [description, onClose, updateDescription, workspace.id]);
}, [name, onClose, updateWorkspace, workspace.id]);

return (
<Modal visible onClose={onClose} onSubmit={updateWorkspaceDescription}>
Expand All @@ -54,20 +54,20 @@ export const RenameWorkspaceModal: FunctionComponent<Props> = ({ workspace, onCl
autoFocus
className="w-full truncate"
type="text"
value={description}
disabled={updateDescription.isLoading}
onChange={(e) => setDescription(e.target.value)}
value={name}
disabled={updateWorkspace.isLoading}
onChange={(e) => setName(e.target.value)}
/>
<div className="mt-1">
<p className="text-gray-500">Change the description to make it easier to go back to a workspace.</p>
<p className="text-gray-500">Workspace URLs and endpoints will remain the same.</p>
</div>
</ModalBody>
<ModalFooter>
<Button type="secondary" disabled={updateDescription.isLoading} onClick={onClose}>
<Button type="secondary" disabled={updateWorkspace.isLoading} onClick={onClose}>
Cancel
</Button>
<Button htmlType="submit" loading={updateDescription.isLoading}>
<Button htmlType="submit" loading={updateWorkspace.isLoading}>
Update Description
</Button>
</ModalFooter>
Expand Down
17 changes: 8 additions & 9 deletions components/dashboard/src/workspaces/WorkspaceOverflowMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import { FunctionComponent, useCallback, useMemo, useState } from "react";
import { ContextMenuEntry } from "../components/ContextMenu";
import { ItemFieldContextMenu } from "../components/ItemsList";
import { useStopWorkspaceMutation } from "../data/workspaces/stop-workspace-mutation";
import { useToggleWorkspacedPinnedMutation } from "../data/workspaces/toggle-workspace-pinned-mutation";
import { useToggleWorkspaceSharedMutation } from "../data/workspaces/toggle-workspace-shared-mutation";
import { getGitpodService } from "../service/service";
import ConnectToSSHModal from "./ConnectToSSHModal";
import { DeleteWorkspaceModal } from "./DeleteWorkspaceModal";
import { useToast } from "../components/toasts/Toasts";
import { RenameWorkspaceModal } from "./RenameWorkspaceModal";
import { AdmissionLevel, Workspace, WorkspacePhase_Phase } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
import { useUpdateWorkspaceMutation } from "../data/workspaces/update-workspace-mutation";

type WorkspaceEntryOverflowMenuProps = {
info: Workspace;
Expand All @@ -34,8 +33,7 @@ export const WorkspaceEntryOverflowMenu: FunctionComponent<WorkspaceEntryOverflo
const { toast } = useToast();

const stopWorkspace = useStopWorkspaceMutation();
const toggleWorkspaceShared = useToggleWorkspaceSharedMutation();
const toggleWorkspacePinned = useToggleWorkspacedPinnedMutation();
const updateWorkspace = useUpdateWorkspaceMutation();

const workspace = info;
const state: WorkspacePhase_Phase = info?.status?.phase?.name || WorkspacePhase_Phase.STOPPED;
Expand Down Expand Up @@ -64,17 +62,18 @@ export const WorkspaceEntryOverflowMenu: FunctionComponent<WorkspaceEntryOverflo
? AdmissionLevel.OWNER_ONLY
: AdmissionLevel.EVERYONE;

toggleWorkspaceShared.mutate({
updateWorkspace.mutate({
workspaceId: workspace.id,
level: newLevel,
admission: newLevel,
});
}, [toggleWorkspaceShared, workspace.id, workspace.status?.admission]);
}, [updateWorkspace, workspace.id, workspace.status?.admission]);

const togglePinned = useCallback(() => {
toggleWorkspacePinned.mutate({
updateWorkspace.mutate({
workspaceId: workspace.id,
pinned: !workspace.pinned,
});
}, [toggleWorkspacePinned, workspace.id]);
}, [updateWorkspace, workspace.id, workspace.pinned]);

// Can we use `/start#${workspace.id}` instead?
const startUrl = useMemo(
Expand Down

0 comments on commit a8c3b73

Please sign in to comment.