refactor(site): Remove change version from the UI (#6621)

This commit is contained in:
Bruno Quaresma
2023-03-16 13:07:33 -03:00
committed by GitHub
parent ab90651a7e
commit 95177ad0e5
16 changed files with 0 additions and 558 deletions
-7
View File
@@ -43,9 +43,6 @@ const WorkspaceBuildPage = lazy(
() => import("./pages/WorkspaceBuildPage/WorkspaceBuildPage"),
)
const WorkspacePage = lazy(() => import("./pages/WorkspacePage/WorkspacePage"))
const WorkspaceChangeVersionPage = lazy(
() => import("./pages/WorkspaceChangeVersionPage/WorkspaceChangeVersionPage"),
)
const WorkspaceSchedulePage = lazy(
() => import("./pages/WorkspaceSchedulePage/WorkspaceSchedulePage"),
)
@@ -235,10 +232,6 @@ export const AppRouter: FC = () => {
path="builds/:buildNumber"
element={<WorkspaceBuildPage />}
/>
<Route
path="change-version"
element={<WorkspaceChangeVersionPage />}
/>
<Route path="settings" element={<WorkspaceSettingsPage />} />
</Route>
</Route>
@@ -3,7 +3,6 @@ import Button from "@material-ui/core/Button"
import { makeStyles } from "@material-ui/core/styles"
import BlockIcon from "@material-ui/icons/Block"
import CloudQueueIcon from "@material-ui/icons/CloudQueue"
import UpdateOutlined from "@material-ui/icons/UpdateOutlined"
import SettingsOutlined from "@material-ui/icons/SettingsOutlined"
import CropSquareIcon from "@material-ui/icons/CropSquare"
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"
@@ -36,24 +35,6 @@ export const UpdateButton: FC<React.PropsWithChildren<WorkspaceAction>> = ({
)
}
export const ChangeVersionButton: FC<
React.PropsWithChildren<WorkspaceAction>
> = ({ handleAction }) => {
const styles = useStyles()
const { t } = useTranslation("workspacePage")
return (
<Button
variant="outlined"
className={styles.actionButton}
startIcon={<UpdateOutlined />}
onClick={handleAction}
>
{t("actionButton.changeVersion")}
</Button>
)
}
export const SettingsButton: FC<React.PropsWithChildren<WorkspaceAction>> = ({
handleAction,
}) => {
@@ -42,7 +42,6 @@ export interface WorkspaceProps {
handleDelete: () => void
handleUpdate: () => void
handleCancel: () => void
handleChangeVersion: () => void
handleSettings: () => void
isUpdating: boolean
workspace: TypesGen.Workspace
@@ -68,7 +67,6 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
handleDelete,
handleUpdate,
handleCancel,
handleChangeVersion,
handleSettings,
workspace,
isUpdating,
@@ -130,7 +128,6 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
handleDelete={handleDelete}
handleUpdate={handleUpdate}
handleCancel={handleCancel}
handleChangeVersion={handleChangeVersion}
handleSettings={handleSettings}
isUpdating={isUpdating}
/>
@@ -18,7 +18,6 @@ const renderComponent = async (props: Partial<WorkspaceActionsProps> = {}) => {
handleDelete={jest.fn()}
handleUpdate={jest.fn()}
handleCancel={jest.fn()}
handleChangeVersion={jest.fn()}
handleSettings={jest.fn()}
isUpdating={false}
/>,
@@ -37,7 +36,6 @@ const renderAndClick = async (props: Partial<WorkspaceActionsProps> = {}) => {
handleDelete={jest.fn()}
handleUpdate={jest.fn()}
handleCancel={jest.fn()}
handleChangeVersion={jest.fn()}
handleSettings={jest.fn()}
isUpdating={false}
/>,
@@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next"
import { WorkspaceStatus } from "../../api/typesGenerated"
import {
ActionLoadingButton,
ChangeVersionButton,
DeleteButton,
DisabledButton,
SettingsButton,
@@ -22,7 +21,6 @@ export interface WorkspaceActionsProps {
handleDelete: () => void
handleUpdate: () => void
handleCancel: () => void
handleChangeVersion: () => void
handleSettings: () => void
isUpdating: boolean
children?: ReactNode
@@ -36,7 +34,6 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
handleDelete,
handleUpdate,
handleCancel,
handleChangeVersion,
handleSettings,
isUpdating,
}) => {
@@ -50,9 +47,6 @@ export const WorkspaceActions: FC<WorkspaceActionsProps> = ({
[ButtonTypesEnum.updating]: (
<ActionLoadingButton label={t("actionButton.updating")} />
),
[ButtonTypesEnum.changeVersion]: (
<ChangeVersionButton handleAction={handleChangeVersion} />
),
[ButtonTypesEnum.settings]: (
<SettingsButton handleAction={handleSettings} />
),
@@ -11,7 +11,6 @@ export enum ButtonTypesEnum {
deleting = "deleting",
update = "update",
updating = "updating",
changeVersion = "changeVersion",
settings = "settings",
// disabled buttons
canceling = "canceling",
@@ -45,7 +44,6 @@ const statusToAbilities: Record<WorkspaceStatus, WorkspaceAbilities> = {
actions: [
ButtonTypesEnum.stop,
ButtonTypesEnum.settings,
ButtonTypesEnum.changeVersion,
ButtonTypesEnum.delete,
],
canCancel: false,
@@ -60,7 +58,6 @@ const statusToAbilities: Record<WorkspaceStatus, WorkspaceAbilities> = {
actions: [
ButtonTypesEnum.start,
ButtonTypesEnum.settings,
ButtonTypesEnum.changeVersion,
ButtonTypesEnum.delete,
],
canCancel: false,
@@ -71,7 +68,6 @@ const statusToAbilities: Record<WorkspaceStatus, WorkspaceAbilities> = {
ButtonTypesEnum.start,
ButtonTypesEnum.stop,
ButtonTypesEnum.settings,
ButtonTypesEnum.changeVersion,
ButtonTypesEnum.delete,
],
canCancel: false,
@@ -83,7 +79,6 @@ const statusToAbilities: Record<WorkspaceStatus, WorkspaceAbilities> = {
ButtonTypesEnum.start,
ButtonTypesEnum.stop,
ButtonTypesEnum.settings,
ButtonTypesEnum.changeVersion,
ButtonTypesEnum.delete,
],
canCancel: false,
-2
View File
@@ -12,7 +12,6 @@ import templateSettingsPage from "./templateSettingsPage.json"
import templateVariablesPage from "./templateVariablesPage.json"
import templateVersionPage from "./templateVersionPage.json"
import loginPage from "./loginPage.json"
import workspaceChangeVersionPage from "./workspaceChangeVersionPage.json"
import workspaceSchedulePage from "./workspaceSchedulePage.json"
import appearanceSettings from "./appearanceSettings.json"
import starterTemplatesPage from "./starterTemplatesPage.json"
@@ -37,7 +36,6 @@ export const en = {
templateVariablesPage,
templateVersionPage,
loginPage,
workspaceChangeVersionPage,
workspaceSchedulePage,
appearanceSettings,
starterTemplatesPage,
@@ -1,9 +0,0 @@
{
"title": "",
"labels": {
"workspaceVersion": "Workspace version",
"submit": "Update version",
"createdBy": "Created by",
"active": "Active"
}
}
-1
View File
@@ -28,7 +28,6 @@
"starting": "Starting...",
"stopping": "Stopping...",
"deleting": "Deleting...",
"changeVersion": "Change version",
"settings": "Settings"
},
"disabledButton": {
@@ -1,150 +0,0 @@
import { makeStyles } from "@material-ui/core/styles"
import TextField from "@material-ui/core/TextField"
import Autocomplete from "@material-ui/lab/Autocomplete"
import { Template, TemplateVersion, Workspace } from "api/typesGenerated"
import { FormFooter } from "components/FormFooter/FormFooter"
import { Pill } from "components/Pill/Pill"
import { Stack } from "components/Stack/Stack"
import { useFormik } from "formik"
import { FC } from "react"
import { useTranslation } from "react-i18next"
import { createDayString } from "util/createDayString"
import * as Yup from "yup"
const validationSchema = Yup.object({
versionId: Yup.string().required(),
})
export const WorkspaceChangeVersionForm: FC<{
isLoading: boolean
workspace: Workspace
template: Template
versions: TemplateVersion[]
onSubmit: (versionId: string) => void
onCancel: () => void
}> = ({ isLoading, workspace, template, versions, onSubmit, onCancel }) => {
const styles = useStyles()
const { t } = useTranslation("workspaceChangeVersionPage")
const formik = useFormik({
initialValues: {
versionId: workspace.latest_build.template_version_id,
},
validationSchema,
onSubmit: ({ versionId }) => onSubmit(versionId),
})
const autocompleteValue = versions.find(
(version) => version.id === formik.values.versionId,
)
return (
<form onSubmit={formik.handleSubmit}>
<Stack direction="column" spacing={3}>
<Stack direction="row" className={styles.workspace} alignItems="center">
<div className={styles.workspaceIcon}>
<img src={workspace.template_icon} alt="" />
</div>
<Stack direction="column" spacing={0.5}>
<span className={styles.workspaceName}>{workspace.name}</span>
<span className={styles.workspaceDescription}>
{workspace.template_display_name.length > 0
? workspace.template_display_name
: workspace.template_name}
</span>
</Stack>
</Stack>
<Autocomplete
id="workspaceVersion"
disableClearable
options={versions.slice().reverse()}
value={autocompleteValue}
onChange={async (_event, value) => {
if (value) {
await formik.setFieldValue("versionId", value.id)
}
}}
renderInput={(params) => (
<TextField
{...params}
label={t("labels.workspaceVersion")}
variant="outlined"
fullWidth
/>
)}
getOptionLabel={(version: TemplateVersion) => version.name}
renderOption={(version: TemplateVersion) => (
<div className={styles.menuItem}>
<div>
<div>{version.name}</div>
<div className={styles.versionDescription}>
{t("labels.createdBy")} {version.created_by.username}{" "}
{createDayString(version.created_at)}
</div>
</div>
{template.active_version_id === version.id && (
<Pill
type="success"
text={t("labels.active")}
className={styles.activePill}
/>
)}
</div>
)}
/>
</Stack>
<FormFooter
onCancel={onCancel}
isLoading={isLoading}
submitLabel={t("labels.submit")}
/>
</form>
)
}
const useStyles = makeStyles((theme) => ({
workspace: {
padding: theme.spacing(2.5, 3),
borderRadius: theme.shape.borderRadius,
backgroundColor: theme.palette.background.paper,
border: `1px solid ${theme.palette.divider}`,
},
workspaceName: {
fontSize: theme.spacing(2),
},
workspaceDescription: {
fontSize: theme.spacing(1.75),
color: theme.palette.text.secondary,
},
workspaceIcon: {
width: theme.spacing(5),
lineHeight: 1,
"& img": {
width: "100%",
},
},
menuItem: {
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
position: "relative",
width: "100%",
},
versionDescription: {
fontSize: theme.spacing(1.5),
color: theme.palette.text.secondary,
},
activePill: {
position: "absolute",
top: theme.spacing(2),
right: theme.spacing(2),
},
}))
@@ -1,64 +0,0 @@
import {
MockTemplateVersion2,
MockUser,
MockWorkspace,
renderWithAuth,
waitForLoaderToBeRemoved,
} from "testHelpers/renderHelpers"
import WorkspaceChangeVersionPage from "./WorkspaceChangeVersionPage"
import { screen, waitFor } from "@testing-library/react"
import * as API from "api/api"
import userEvent from "@testing-library/user-event"
import * as CreateDayString from "util/createDayString"
import i18next from "i18next"
const t = (path: string) => {
return i18next.t(path, { ns: "workspaceChangeVersionPage" })
}
const renderPage = async () => {
renderWithAuth(<WorkspaceChangeVersionPage />, {
path: "/@:username/:workspace/change-version",
route: `/@${MockUser.username}/${MockWorkspace.name}/change-version`,
})
await waitForLoaderToBeRemoved()
}
describe("WorkspaceChangeVersionPage", () => {
beforeEach(() => {
jest
.spyOn(CreateDayString, "createDayString")
.mockImplementation(() => "a minute ago")
})
it("sends the update request with the right version", async () => {
const user = userEvent.setup()
const updateSpy = jest.spyOn(API, "startWorkspace")
await renderPage()
// Type the version name and select it
const autocompleteInput = screen.getByLabelText(
t("labels.workspaceVersion"),
)
await user.clear(autocompleteInput)
await user.type(autocompleteInput, MockTemplateVersion2.name)
const newOption = screen.getByRole("option", {
// Using RegExp so we can match a substring
name: new RegExp(MockTemplateVersion2.name),
})
await user.click(newOption)
// Submit the form
const submitButton = screen.getByRole("button", {
name: t("labels.submit"),
})
await user.click(submitButton)
await waitFor(() => {
expect(updateSpy).toBeCalledWith(
MockWorkspace.id,
MockTemplateVersion2.id,
)
})
})
})
@@ -1,48 +0,0 @@
import { useMachine } from "@xstate/react"
import { FC } from "react"
import { Helmet } from "react-helmet-async"
import { useTranslation } from "react-i18next"
import { useNavigate, useParams } from "react-router-dom"
import { changeWorkspaceVersionMachine } from "xServices/workspace/changeWorkspaceVersionXService"
import { WorkspaceChangeVersionPageView } from "./WorkspaceChangeVersionPageView"
export const WorkspaceChangeVersionPage: FC = () => {
const navigate = useNavigate()
const { t } = useTranslation("workspaceChangeVersionPage")
const { username: owner, workspace: workspaceName } = useParams() as {
username: string
workspace: string
}
const [state, send] = useMachine(changeWorkspaceVersionMachine, {
context: {
owner,
workspaceName,
},
actions: {
onUpdateVersion: () => {
navigate(-1)
},
},
})
return (
<>
<Helmet>
<title>{`${t("title")} · ${workspaceName}`}</title>
</Helmet>
<WorkspaceChangeVersionPageView
isUpdating={state.matches("updatingVersion")}
context={state.context}
onSubmit={(versionId) => {
send({
type: "UPDATE_VERSION",
versionId,
})
}}
/>
</>
)
}
export default WorkspaceChangeVersionPage
@@ -1,51 +0,0 @@
import { action } from "@storybook/addon-actions"
import { ComponentMeta, Story } from "@storybook/react"
import {
makeMockApiError,
MockTemplate,
MockTemplateVersion,
MockTemplateVersion2,
MockUser,
MockWorkspace,
} from "testHelpers/entities"
import {
WorkspaceChangeVersionPageView,
WorkspaceChangeVersionPageViewProps,
} from "./WorkspaceChangeVersionPageView"
export default {
title: "pages/WorkspaceChangeVersionPageView",
component: WorkspaceChangeVersionPageView,
} as ComponentMeta<typeof WorkspaceChangeVersionPageView>
const Template: Story<WorkspaceChangeVersionPageViewProps> = (args) => (
<WorkspaceChangeVersionPageView {...args} />
)
export const Example = Template.bind({})
Example.args = {
isUpdating: false,
onSubmit: action("submit"),
context: {
error: undefined,
owner: MockUser.username,
workspaceName: MockWorkspace.name,
template: MockTemplate,
templateVersions: [MockTemplateVersion2, MockTemplateVersion],
workspace: MockWorkspace,
},
}
export const Error = Template.bind({})
Error.args = {
isUpdating: false,
onSubmit: action("submit"),
context: {
error: makeMockApiError({ message: "Error on updating the version." }),
owner: MockUser.username,
workspaceName: MockWorkspace.name,
template: MockTemplate,
templateVersions: [MockTemplateVersion2, MockTemplateVersion],
workspace: MockWorkspace,
},
}
@@ -1,46 +0,0 @@
import { AlertBanner } from "components/AlertBanner/AlertBanner"
import { Maybe } from "components/Conditionals/Maybe"
import { FullPageForm } from "components/FullPageForm/FullPageForm"
import { Loader } from "components/Loader/Loader"
import { Stack } from "components/Stack/Stack"
import { FC } from "react"
import { useNavigate } from "react-router-dom"
import { ChangeWorkspaceVersionContext } from "xServices/workspace/changeWorkspaceVersionXService"
import { WorkspaceChangeVersionForm } from "./WorkspaceChangeVersionForm"
export interface WorkspaceChangeVersionPageViewProps {
isUpdating: boolean
context: ChangeWorkspaceVersionContext
onSubmit: (versionId: string) => void
}
export const WorkspaceChangeVersionPageView: FC<
WorkspaceChangeVersionPageViewProps
> = ({ context, onSubmit, isUpdating }) => {
const navigate = useNavigate()
const { workspace, templateVersions, template, error } = context
return (
<FullPageForm title="Change version">
<Stack>
<Maybe condition={Boolean(error)}>
<AlertBanner severity="error" error={error} />
</Maybe>
{workspace && template && templateVersions ? (
<WorkspaceChangeVersionForm
isLoading={isUpdating}
versions={templateVersions}
workspace={workspace}
template={template}
onSubmit={onSubmit}
onCancel={() => {
navigate(-1)
}}
/>
) : (
<Loader />
)}
</Stack>
</FullPageForm>
)
}
@@ -111,7 +111,6 @@ export const WorkspaceReadyPage = ({
handleDelete={() => workspaceSend({ type: "ASK_DELETE" })}
handleUpdate={() => workspaceSend({ type: "UPDATE" })}
handleCancel={() => workspaceSend({ type: "CANCEL" })}
handleChangeVersion={() => navigate("change-version")}
handleSettings={() => navigate("settings")}
resources={workspace.latest_build.resources}
builds={builds}
@@ -1,144 +0,0 @@
import {
getTemplate,
getTemplateVersions,
getWorkspaceByOwnerAndName,
startWorkspace,
} from "api/api"
import {
Template,
TemplateVersion,
Workspace,
WorkspaceBuild,
} from "api/typesGenerated"
import { assign, createMachine } from "xstate"
export interface ChangeWorkspaceVersionContext {
owner: string
workspaceName: string
workspace?: Workspace
template?: Template
templateVersions?: TemplateVersion[]
error?: unknown
}
interface ChangeWorkspaceVersionSchema {
context: ChangeWorkspaceVersionContext
services: {
getWorkspace: {
data: Workspace
}
getTemplateData: {
data: {
template: Template
versions: TemplateVersion[]
}
}
updateVersion: {
data: WorkspaceBuild
}
}
events: {
type: "UPDATE_VERSION"
versionId: string
}
}
export const changeWorkspaceVersionMachine = createMachine(
{
id: "changeWorkspaceVersion",
predictableActionArguments: true,
schema: {} as ChangeWorkspaceVersionSchema,
tsTypes: {} as import("./changeWorkspaceVersionXService.typegen").Typegen0,
initial: "loadingWorkspace",
states: {
loadingWorkspace: {
invoke: {
src: "getWorkspace",
onDone: {
target: "loadingTemplateData",
actions: "assignWorkspace",
},
onError: {
target: "idle",
actions: "assignError",
},
},
},
loadingTemplateData: {
invoke: {
src: "getTemplateData",
onDone: {
target: "idle",
actions: "assignTemplateData",
},
onError: {
target: "idle",
actions: "assignError",
},
},
},
idle: {
on: {
UPDATE_VERSION: "updatingVersion",
},
},
updatingVersion: {
invoke: {
src: "updateVersion",
onDone: {
target: "idle",
actions: "onUpdateVersion",
},
onError: {
target: "idle",
actions: "assignError",
},
},
},
},
},
{
services: {
getWorkspace: ({ owner, workspaceName }) =>
getWorkspaceByOwnerAndName(owner, workspaceName),
getTemplateData: async ({ workspace }) => {
if (!workspace) {
throw new Error("Workspace not defined.")
}
const [template, versions] = await Promise.all([
getTemplate(workspace.template_id),
getTemplateVersions(workspace.template_id),
])
return { template, versions }
},
updateVersion: ({ workspace }, { versionId }) => {
if (!workspace) {
throw new Error("Workspace not defined.")
}
return startWorkspace(workspace.id, versionId)
},
},
actions: {
assignError: assign({
error: (_, { data }) => data,
}),
assignWorkspace: assign({
workspace: (_, { data }) => data,
}),
assignTemplateData: assign({
template: (_, { data }) => data.template,
templateVersions: (_, { data }) => data.versions,
}),
},
},
)