Skip to content

Commit 39ebf1d

Browse files
authored
Revert Refine workspace and fix bugs (#19178)
* Revert "Revert "Refine workspace API (#19138)" (#19172)" This reverts commit a6f4722. * Update to workspace cases * Add new cases and fix * Add timeout * fixup * Remove requirement of editor * Update cases * Bump version * Update dashboard
1 parent 5f73ddf commit 39ebf1d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+6988
-2007
lines changed

components/dashboard/src/data/setup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import * as SSHClasses from "@gitpod/public-api/lib/gitpod/v1/ssh_pb";
3232
// This is used to version the cache
3333
// If data we cache changes in a non-backwards compatible way, increment this version
3434
// That will bust any previous cache versions a client may have stored
35-
const CACHE_VERSION = "13";
35+
const CACHE_VERSION = "14";
3636

3737
export function noPersistence(queryKey: QueryKey): QueryKey {
3838
return [...queryKey, "no-persistence"];

components/dashboard/src/data/workspaces/toggle-workspace-pinned-mutation.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
88
import { getGitpodService } from "../../service/service";
99
import { getListWorkspacesQueryKey, ListWorkspacesQueryResult } from "./list-workspaces-query";
1010
import { useCurrentOrg } from "../organizations/orgs-query";
11-
import { Workspace } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
11+
import { Workspace, WorkspaceMetadata } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
1212

1313
type ToggleWorkspacePinnedArgs = {
1414
workspaceId: string;
@@ -33,7 +33,10 @@ export const useToggleWorkspacedPinnedMutation = () => {
3333
return info;
3434
}
3535
const workspace = new Workspace(info);
36-
workspace.pinned = !workspace.pinned;
36+
if (!workspace.metadata) {
37+
workspace.metadata = new WorkspaceMetadata();
38+
}
39+
workspace.metadata.pinned = !workspace.metadata.pinned;
3740
return workspace;
3841
});
3942
});

components/dashboard/src/data/workspaces/toggle-workspace-shared-mutation.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
88
import { getGitpodService } from "../../service/service";
99
import { getListWorkspacesQueryKey, ListWorkspacesQueryResult } from "./list-workspaces-query";
1010
import { useCurrentOrg } from "../organizations/orgs-query";
11-
import { AdmissionLevel, Workspace } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
11+
import { AdmissionLevel, Workspace, WorkspaceSpec } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
1212

1313
type ToggleWorkspaceSharedArgs = {
1414
workspaceId: string;
@@ -44,9 +44,10 @@ export const useToggleWorkspaceSharedMutation = () => {
4444
}
4545

4646
const workspace = new Workspace(info);
47-
if (workspace.status) {
48-
workspace.status.admission = level;
47+
if (!workspace.spec) {
48+
workspace.spec = new WorkspaceSpec();
4949
}
50+
workspace.spec.admission = level;
5051
return workspace;
5152
});
5253
});

components/dashboard/src/data/workspaces/update-workspace-description-mutation.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
88
import { getGitpodService } from "../../service/service";
99
import { getListWorkspacesQueryKey, ListWorkspacesQueryResult } from "./list-workspaces-query";
1010
import { useCurrentOrg } from "../organizations/orgs-query";
11-
import { Workspace } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
11+
import { Workspace, WorkspaceMetadata } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
1212

1313
type UpdateWorkspaceDescriptionArgs = {
1414
workspaceId: string;
@@ -36,7 +36,10 @@ export const useUpdateWorkspaceDescriptionMutation = () => {
3636
// TODO: Once the update description response includes an updated record,
3737
// we can return that instead of having to know what to merge manually (same for other mutations)
3838
const workspace = new Workspace(info);
39-
workspace.name = newDescription;
39+
if (!workspace.metadata) {
40+
workspace.metadata = new WorkspaceMetadata();
41+
}
42+
workspace.metadata.name = newDescription;
4043
return workspace;
4144
});
4245
});

components/dashboard/src/service/json-rpc-workspace-client.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ import {
2828
SendHeartBeatResponse,
2929
WorkspacePhase_Phase,
3030
GetWorkspaceDefaultImageResponse_Source,
31+
ParseContextURLRequest,
32+
ParseContextURLResponse,
33+
UpdateWorkspaceRequest,
34+
UpdateWorkspaceResponse,
3135
} from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
3236
import { converter } from "./public-api";
3337
import { getGitpodService } from "./service";
@@ -131,25 +135,24 @@ export class JsonRpcWorkspaceClient implements PromiseClient<typeof WorkspaceSer
131135
if (request.source?.case !== "contextUrl") {
132136
throw new ApplicationError(ErrorCodes.UNIMPLEMENTED, "not implemented");
133137
}
134-
if (!request.organizationId || !uuidValidate(request.organizationId)) {
138+
if (!request.metadata || !request.metadata.organizationId || !uuidValidate(request.metadata.organizationId)) {
135139
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "organizationId is required");
136140
}
137-
if (!request.editor) {
138-
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "editor is required");
139-
}
140-
if (!request.source.value) {
141+
if (!request.source.value.url) {
141142
throw new ApplicationError(ErrorCodes.BAD_REQUEST, "source is required");
142143
}
143144
const response = await getGitpodService().server.createWorkspace({
144-
organizationId: request.organizationId,
145+
organizationId: request.metadata.organizationId,
145146
ignoreRunningWorkspaceOnSameCommit: true,
146-
contextUrl: request.source.value,
147+
contextUrl: request.source.value.url,
147148
forceDefaultConfig: request.forceDefaultConfig,
148-
workspaceClass: request.workspaceClass,
149-
projectId: request.configurationId,
149+
workspaceClass: request.source.value.workspaceClass,
150+
projectId: request.metadata.configurationId,
150151
ideSettings: {
151-
defaultIde: request.editor.name,
152-
useLatestVersion: request.editor.version === "latest",
152+
defaultIde: request.source.value.editor?.name,
153+
useLatestVersion: request.source.value.editor?.version
154+
? request.source.value.editor?.version === "latest"
155+
: undefined,
153156
},
154157
});
155158
const workspace = await this.getWorkspace({ workspaceId: response.createdWorkspaceId });
@@ -240,4 +243,18 @@ export class JsonRpcWorkspaceClient implements PromiseClient<typeof WorkspaceSer
240243
result.editorCredentials = credentials;
241244
return result;
242245
}
246+
247+
async updateWorkspace(
248+
request: PartialMessage<UpdateWorkspaceRequest>,
249+
_options?: CallOptions | undefined,
250+
): Promise<UpdateWorkspaceResponse> {
251+
throw new ApplicationError(ErrorCodes.UNIMPLEMENTED, "not implemented");
252+
}
253+
254+
async parseContextURL(
255+
request: PartialMessage<ParseContextURLRequest>,
256+
_options?: CallOptions | undefined,
257+
): Promise<ParseContextURLResponse> {
258+
throw new ApplicationError(ErrorCodes.UNIMPLEMENTED, "not implemented");
259+
}
243260
}

components/dashboard/src/start/StartWorkspace.tsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
StartWorkspaceResponse,
2929
Workspace,
3030
WorkspacePhase_Phase,
31+
WorkspaceSpec_WorkspaceType,
3132
} from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
3233
import { PartialMessage } from "@bufbuild/protobuf";
3334

@@ -169,7 +170,7 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps,
169170
componentDidUpdate(prevPros: StartWorkspaceProps, prevState: StartWorkspaceState) {
170171
const newPhase = this.state?.workspace?.status?.phase?.name;
171172
const oldPhase = prevState.workspace?.status?.phase?.name;
172-
const type = !!this.state.workspace?.prebuild ? "prebuild" : "regular";
173+
const type = this.state.workspace?.spec?.type === WorkspaceSpec_WorkspaceType.PREBUILD ? "prebuild" : "regular";
173174
if (newPhase !== oldPhase) {
174175
getGitpodService().server.trackEvent({
175176
event: "status_rendered",
@@ -373,10 +374,10 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps,
373374
if (
374375
!error &&
375376
workspace.status.phase?.name === WorkspacePhase_Phase.STOPPED &&
376-
!!this.state.workspace?.prebuild
377+
this.state.workspace?.spec?.type === WorkspaceSpec_WorkspaceType.PREBUILD
377378
) {
378379
// here we want to point to the original context, w/o any modifiers "workspace" was started with (as this might have been a manually triggered prebuild!)
379-
const contextURL = this.state.workspace.contextUrl;
380+
const contextURL = this.state.workspace.metadata?.originalContextUrl;
380381
if (contextURL) {
381382
this.redirectTo(gitpodHostUrl.withContext(contextURL.toString()).toString());
382383
} else {
@@ -457,15 +458,20 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps,
457458

458459
render() {
459460
const { error } = this.state;
460-
const isPrebuild = this.state.workspace?.prebuild;
461-
const withPrebuild = !!this.state.workspace?.prebuildId;
461+
const isPrebuild = this.state.workspace?.spec?.type === WorkspaceSpec_WorkspaceType.PREBUILD;
462+
let withPrebuild = false;
463+
for (const initializer of this.state.workspace?.spec?.initializer?.specs ?? []) {
464+
if (initializer.spec.case === "prebuild") {
465+
withPrebuild = !!initializer.spec.value.prebuildId;
466+
}
467+
}
462468
let phase: StartPhase | undefined = StartPhase.Preparing;
463469
let title = undefined;
464470
let isStoppingOrStoppedPhase = false;
465471
let isError = error ? true : false;
466472
let statusMessage = !!error ? undefined : <p className="text-base text-gray-400">Preparing workspace …</p>;
467-
const contextURL = this.state.workspace?.contextUrl;
468-
const useLatest = this.state.workspace?.editor?.version === "latest";
473+
const contextURL = this.state.workspace?.metadata?.originalContextUrl;
474+
const useLatest = this.state.workspace?.spec?.editor?.version === "latest";
469475

470476
switch (this.state?.workspace?.status?.phase?.name) {
471477
// unknown indicates an issue within the system in that it cannot determine the actual phase of

components/dashboard/src/workspaces/CreateWorkspacePage.tsx

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ import { SelectAccountModal } from "../user-settings/SelectAccountModal";
3737
import { settingsPathIntegrations } from "../user-settings/settings.routes";
3838
import { WorkspaceEntry } from "./WorkspaceEntry";
3939
import { AuthProviderType } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";
40-
import { WorkspacePhase_Phase } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
40+
import {
41+
CreateAndStartWorkspaceRequest_ContextURL,
42+
WorkspacePhase_Phase,
43+
} from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
4144
import { Button } from "@podkit/buttons/Button";
4245
import { LoadingButton } from "@podkit/buttons/LoadingButton";
4346
import { CreateAndStartWorkspaceRequest } from "@gitpod/public-api/lib/gitpod/v1/workspace_pb";
@@ -172,7 +175,14 @@ export function CreateWorkspacePage() {
172175
const [selectAccountError, setSelectAccountError] = useState<SelectAccountPayload | undefined>(undefined);
173176

174177
const createWorkspace = useCallback(
175-
async (options?: Omit<PartialMessage<CreateAndStartWorkspaceRequest>, "contextUrl" | "organizationId">) => {
178+
/**
179+
* options will omit
180+
* - source.url
181+
* - source.workspaceClass
182+
* - metadata.organizationId
183+
* - metadata.configurationId
184+
*/
185+
async (options?: PartialMessage<CreateAndStartWorkspaceRequest>) => {
176186
// add options from search params
177187
const opts = options || {};
178188

@@ -192,16 +202,6 @@ export function CreateWorkspacePage() {
192202
opts.forceDefaultConfig = true;
193203
}
194204

195-
if (!opts.workspaceClass) {
196-
opts.workspaceClass = selectedWsClass;
197-
}
198-
if (!opts.editor) {
199-
opts.editor = {
200-
name: selectedIde,
201-
version: useLatestIde ? "latest" : undefined,
202-
};
203-
}
204-
205205
try {
206206
if (createWorkspaceMutation.isStarting) {
207207
console.log("Skipping duplicate createWorkspace call.");
@@ -210,15 +210,27 @@ export function CreateWorkspacePage() {
210210
// we wait at least 5 secs
211211
const timeout = new Promise((resolve) => setTimeout(resolve, 5000));
212212

213-
const result = await createWorkspaceMutation.createWorkspace({
214-
source: {
215-
case: "contextUrl",
216-
value: contextURL,
217-
},
218-
...opts,
219-
organizationId,
220-
configurationId: selectedProjectID,
221-
});
213+
if (!opts.metadata) {
214+
opts.metadata = {};
215+
}
216+
opts.metadata.organizationId = organizationId;
217+
opts.metadata.configurationId = selectedProjectID;
218+
219+
const contextUrlSource: PartialMessage<CreateAndStartWorkspaceRequest_ContextURL> =
220+
opts.source?.case === "contextUrl" ? opts.source?.value ?? {} : {};
221+
contextUrlSource.url = contextURL;
222+
contextUrlSource.workspaceClass = selectedWsClass;
223+
if (!contextUrlSource.editor || !contextUrlSource.editor.name) {
224+
contextUrlSource.editor = {
225+
name: selectedIde,
226+
version: useLatestIde ? "latest" : undefined,
227+
};
228+
}
229+
opts.source = {
230+
case: "contextUrl",
231+
value: contextUrlSource,
232+
};
233+
const result = await createWorkspaceMutation.createWorkspace(opts);
222234
await storeAutoStartOptions();
223235
await timeout;
224236
if (result.workspace?.status?.workspaceUrl) {

components/dashboard/src/workspaces/DeleteWorkspaceModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const DeleteWorkspaceModal: FunctionComponent<Props> = ({ workspace, onCl
3333
areYouSureText="Are you sure you want to delete this workspace?"
3434
children={{
3535
name: workspace.id,
36-
description: workspace.name,
36+
description: workspace.metadata?.name,
3737
}}
3838
buttonText="Delete Workspace"
3939
warningText={deleteWorkspace.isError ? "There was a problem deleting your workspace." : undefined}

components/dashboard/src/workspaces/RenameWorkspaceModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type Props = {
1616
};
1717
export const RenameWorkspaceModal: FunctionComponent<Props> = ({ workspace, onClose }) => {
1818
const [errorMessage, setErrorMessage] = useState("");
19-
const [description, setDescription] = useState(workspace.name || "");
19+
const [description, setDescription] = useState(workspace.metadata?.name || "");
2020
const updateDescription = useUpdateWorkspaceDescriptionMutation();
2121

2222
const updateWorkspaceDescription = useCallback(async () => {

components/dashboard/src/workspaces/WorkspaceEntry.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ export const WorkspaceEntry: FunctionComponent<Props> = ({ info, shortVersion })
2727
const workspace = info;
2828
const currentBranch = gitStatus?.branch || "<unknown>";
2929
const project = getProjectPath(workspace);
30-
const normalizedContextUrl = workspace.contextUrl;
31-
const normalizedContextUrlDescription = workspace.contextUrl; // Instead of showing nothing, we prefer to show the raw content instead
30+
const normalizedContextUrl = workspace.metadata!.originalContextUrl;
31+
const normalizedContextUrlDescription = workspace.metadata!.originalContextUrl; // Instead of showing nothing, we prefer to show the raw content instead
3232

3333
const changeMenuState = (state: boolean) => {
3434
setMenuActive(state);
@@ -69,7 +69,7 @@ export const WorkspaceEntry: FunctionComponent<Props> = ({ info, shortVersion })
6969
<>
7070
<ItemField className="w-4/12 flex flex-col my-auto">
7171
<div className="text-gray-500 dark:text-gray-400 overflow-ellipsis truncate">
72-
{workspace.name}
72+
{workspace.metadata!.name}
7373
</div>
7474
<a href={normalizedContextUrl}>
7575
<div className="text-sm text-gray-400 dark:text-gray-500 overflow-ellipsis truncate hover:text-blue-600 dark:hover:text-blue-400">
@@ -105,5 +105,5 @@ export const WorkspaceEntry: FunctionComponent<Props> = ({ info, shortVersion })
105105

106106
export function getProjectPath(ws: Workspace) {
107107
// TODO: Remove and call papi ContextService
108-
return ws.contextUrl.replace("https://", "");
108+
return ws.metadata!.originalContextUrl.replace("https://", "");
109109
}

components/dashboard/src/workspaces/WorkspaceOverflowMenu.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,13 @@ export const WorkspaceEntryOverflowMenu: FunctionComponent<WorkspaceEntryOverflo
6262

6363
const toggleShared = useCallback(() => {
6464
const newLevel =
65-
workspace.status?.admission === AdmissionLevel.EVERYONE
66-
? AdmissionLevel.OWNER_ONLY
67-
: AdmissionLevel.EVERYONE;
65+
workspace.spec?.admission === AdmissionLevel.EVERYONE ? AdmissionLevel.OWNER_ONLY : AdmissionLevel.EVERYONE;
6866

6967
toggleWorkspaceShared.mutate({
7068
workspaceId: workspace.id,
7169
level: newLevel,
7270
});
73-
}, [toggleWorkspaceShared, workspace.id, workspace.status?.admission]);
71+
}, [toggleWorkspaceShared, workspace.id, workspace.spec?.admission]);
7472

7573
const togglePinned = useCallback(() => {
7674
toggleWorkspacePinned.mutate({
@@ -132,7 +130,7 @@ export const WorkspaceEntryOverflowMenu: FunctionComponent<WorkspaceEntryOverflo
132130
if (settings && !settings.workspaceSharingDisabled) {
133131
menuEntries.push({
134132
title: "Share",
135-
active: workspace.status?.admission === AdmissionLevel.EVERYONE,
133+
active: workspace.spec?.admission === AdmissionLevel.EVERYONE,
136134
onClick: toggleShared,
137135
});
138136
} else {
@@ -147,7 +145,7 @@ export const WorkspaceEntryOverflowMenu: FunctionComponent<WorkspaceEntryOverflo
147145
menuEntries.push(
148146
{
149147
title: "Pin",
150-
active: !!workspace.pinned,
148+
active: !!workspace.metadata?.pinned,
151149
separator: true,
152150
onClick: togglePinned,
153151
},

components/dashboard/src/workspaces/Workspaces.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,18 @@ const WorkspacesPage: FunctionComponent = () => {
4747
const { filteredActiveWorkspaces, filteredInactiveWorkspaces } = useMemo(() => {
4848
const filteredActiveWorkspaces = activeWorkspaces.filter(
4949
(info) =>
50-
`${info.name}${info.id}${info.contextUrl}${info.status?.gitStatus?.cloneUrl}${info.status?.gitStatus?.branch}`
50+
`${info.metadata!.name}${info.id}${info.metadata!.originalContextUrl}${
51+
info.status?.gitStatus?.cloneUrl
52+
}${info.status?.gitStatus?.branch}`
5153
.toLowerCase()
5254
.indexOf(searchTerm.toLowerCase()) !== -1,
5355
);
5456

5557
const filteredInactiveWorkspaces = inactiveWorkspaces.filter(
5658
(info) =>
57-
`${info.name}${info.id}${info.contextUrl}${info.status?.gitStatus?.cloneUrl}${info.status?.gitStatus?.branch}`
59+
`${info.metadata!.name}${info.id}${info.metadata!.originalContextUrl}${
60+
info.status?.gitStatus?.cloneUrl
61+
}${info.status?.gitStatus?.branch}`
5862
.toLowerCase()
5963
.indexOf(searchTerm.toLowerCase()) !== -1,
6064
);
@@ -201,5 +205,5 @@ function isWorkspaceActive(info: Workspace): boolean {
201205
const twentyfourHoursAgo = hoursBefore(new Date().toISOString(), 24);
202206

203207
const isStopped = info.status?.phase?.name === WorkspacePhase_Phase.STOPPED;
204-
return info.pinned || !isStopped || isDateSmallerOrEqual(twentyfourHoursAgo, lastSessionStart);
208+
return info.metadata!.pinned || !isStopped || isDateSmallerOrEqual(twentyfourHoursAgo, lastSessionStart);
205209
}

components/public-api/generate.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ protoc_buf_generate
3636
update_license
3737

3838
# Run end-of-file-fixer
39-
git ls-files -- 'typescript/*.ts' | xargs pre-commit run end-of-file-fixer --files
39+
git ls-files -- 'typescript/*.ts' | xargs pre-commit run end-of-file-fixer --files || true
4040

4141
yarn --cwd typescript build

0 commit comments

Comments
 (0)