feat: implement basic archive ui to make archiving failed versions easy (#10182)

* feat: implement basic archive ui to make archiving failed versions easy.
This commit is contained in:
Steven Masley
2023-10-11 15:06:10 +00:00
committed by GitHub
parent 1e950fa9a8
commit ac623b4717
8 changed files with 105 additions and 10 deletions
+6
View File
@@ -2294,6 +2294,12 @@ const docTemplate = `{
"name": "after_id",
"in": "query"
},
{
"type": "boolean",
"description": "Include archived versions in the list",
"name": "include_archived",
"in": "query"
},
{
"type": "integer",
"description": "Page limit",
+6
View File
@@ -2002,6 +2002,12 @@
"name": "after_id",
"in": "query"
},
{
"type": "boolean",
"description": "Include archived versions in the list",
"name": "include_archived",
"in": "query"
},
{
"type": "integer",
"description": "Page limit",
+1
View File
@@ -704,6 +704,7 @@ func (api *API) fetchTemplateVersionDryRunJob(rw http.ResponseWriter, r *http.Re
// @Tags Templates
// @Param template path string true "Template ID" format(uuid)
// @Param after_id query string false "After ID" format(uuid)
// @Param include_archived query bool false "Include archived versions in the list"
// @Param limit query int false "Page limit"
// @Param offset query int false "Page offset"
// @Success 200 {array} codersdk.TemplateVersion
+7 -6
View File
@@ -827,12 +827,13 @@ curl -X GET http://coder-server:8080/api/v2/templates/{template}/versions \
### Parameters
| Name | In | Type | Required | Description |
| ---------- | ----- | ------------ | -------- | ----------- |
| `template` | path | string(uuid) | true | Template ID |
| `after_id` | query | string(uuid) | false | After ID |
| `limit` | query | integer | false | Page limit |
| `offset` | query | integer | false | Page offset |
| Name | In | Type | Required | Description |
| ------------------ | ----- | ------------ | -------- | ------------------------------------- |
| `template` | path | string(uuid) | true | Template ID |
| `after_id` | query | string(uuid) | false | After ID |
| `include_archived` | query | boolean | false | Include archived versions in the list |
| `limit` | query | integer | false | Page limit |
| `offset` | query | integer | false | Page offset |
### Example responses
+14
View File
@@ -387,6 +387,20 @@ export const patchTemplateVersion = async (
return response.data;
};
export const archiveTemplateVersion = async (templateVersionId: string) => {
const response = await axios.post<TypesGen.TemplateVersion>(
`/api/v2/templateversions/${templateVersionId}/archive`,
);
return response.data;
};
export const unarchiveTemplateVersion = async (templateVersionId: string) => {
const response = await axios.post<TypesGen.TemplateVersion>(
`/api/v2/templateversions/${templateVersionId}/unarchive`,
);
return response.data;
};
export const updateTemplateMeta = async (
templateId: string,
data: TypesGen.UpdateTemplateMeta,
@@ -1,5 +1,9 @@
import { useMutation, useQuery } from "react-query";
import { getTemplateVersions, updateActiveTemplateVersion } from "api/api";
import {
archiveTemplateVersion,
getTemplateVersions,
updateActiveTemplateVersion,
} from "api/api";
import { getErrorMessage } from "api/errors";
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
@@ -34,9 +38,31 @@ const TemplateVersionsPage = () => {
displayError(getErrorMessage(error, "Failed to promote version"));
},
});
const { mutate: archiveVersion, isLoading: isArchiving } = useMutation({
mutationFn: (templateVersionId: string) => {
return archiveTemplateVersion(templateVersionId);
},
onSuccess: async () => {
// The reload is unfortunate. When a version is archived, we should hide
// the row. I do not know an easy way to do that, so a reload makes the API call
// resend and now the version is omitted.
// TODO: Improve this to not reload the page.
location.reload();
setSelectedVersionIdToArchive(undefined);
displaySuccess("Version archived successfully");
},
onError: (error) => {
displayError(getErrorMessage(error, "Failed to archive version"));
},
});
const [selectedVersionIdToPromote, setSelectedVersionIdToPromote] = useState<
string | undefined
>();
const [selectedVersionIdToArchive, setSelectedVersionIdToArchive] = useState<
string | undefined
>();
return (
<>
@@ -50,8 +76,14 @@ const TemplateVersionsPage = () => {
? setSelectedVersionIdToPromote
: undefined
}
onArchiveClick={
permissions.canUpdateTemplate
? setSelectedVersionIdToArchive
: undefined
}
activeVersionId={latestActiveVersion}
/>
{/* Promote confirm */}
<ConfirmDialog
type="info"
hideCancel={false}
@@ -65,6 +97,20 @@ const TemplateVersionsPage = () => {
confirmText="Promote"
description="Are you sure you want to promote this version? Workspaces will be prompted to “Update” to this version once promoted."
/>
{/* Archive Confirm */}
<ConfirmDialog
type="info"
hideCancel={false}
open={selectedVersionIdToArchive !== undefined}
onConfirm={() => {
archiveVersion(selectedVersionIdToArchive as string);
}}
onClose={() => setSelectedVersionIdToArchive(undefined)}
title="Archive version"
confirmLoading={isArchiving}
confirmText="Archive"
description="Are you sure you want to archive this version (this is reversible)? Archived versions cannot be used by workspaces."
/>
</>
);
};
@@ -17,6 +17,7 @@ export interface VersionRowProps {
isActive: boolean;
isLatest: boolean;
onPromoteClick?: (templateVersionId: string) => void;
onArchiveClick?: (templateVersionId: string) => void;
}
export const VersionRow: React.FC<VersionRowProps> = ({
@@ -24,6 +25,7 @@ export const VersionRow: React.FC<VersionRowProps> = ({
isActive,
isLatest,
onPromoteClick,
onArchiveClick,
}) => {
const styles = useStyles();
const navigate = useNavigate();
@@ -90,14 +92,30 @@ export const VersionRow: React.FC<VersionRowProps> = ({
<Pill text="Canceled" type="neutral" lightBorder />
)}
{jobStatus === "failed" && <Pill text="Failed" type="error" />}
{onPromoteClick && (
{jobStatus === "failed" ? (
<Button
className={styles.promoteButton}
disabled={isActive || version.archived}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
if (onArchiveClick) {
onArchiveClick(version.id);
}
}}
>
Archive&hellip;
</Button>
) : (
<Button
className={styles.promoteButton}
disabled={isActive || jobStatus !== "succeeded"}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
onPromoteClick(version.id);
if (onPromoteClick) {
onPromoteClick(version.id);
}
}}
>
Promote&hellip;
@@ -21,11 +21,13 @@ export const Language = {
export interface VersionsTableProps {
activeVersionId: string;
onPromoteClick?: (templateVersionId: string) => void;
onArchiveClick?: (templateVersionId: string) => void;
versions?: TypesGen.TemplateVersion[];
}
export const VersionsTable: FC<VersionsTableProps> = (props) => {
const { versions, onPromoteClick, activeVersionId } = props;
const { versions, onArchiveClick, onPromoteClick, activeVersionId } = props;
const latestVersionId = versions?.reduce(
(latestSoFar, against) => {
@@ -55,6 +57,7 @@ export const VersionsTable: FC<VersionsTableProps> = (props) => {
getDate={(version) => new Date(version.created_at)}
row={(version) => (
<VersionRow
onArchiveClick={onArchiveClick}
onPromoteClick={onPromoteClick}
version={version}
key={version.id}