From bdf1deef18646e11c8e2b2b0fd17fb870909a716 Mon Sep 17 00:00:00 2001 From: blam Date: Fri, 11 Feb 2022 03:46:30 +0100 Subject: [PATCH] chore: added a sample frontend Signed-off-by: blam Signed-off-by: blam --- packages/app/src/components/Root/Root.tsx | 15 +- plugins/scaffolder/package.json | 1 + plugins/scaffolder/src/api.ts | 12 ++ .../src/components/MyTasksPage/MyTaskPage.tsx | 135 ++++++++++++++++++ .../src/components/MyTasksPage/index.tsx | 16 +++ yarn.lock | 19 +++ 6 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 plugins/scaffolder/src/components/MyTasksPage/MyTaskPage.tsx create mode 100644 plugins/scaffolder/src/components/MyTasksPage/index.tsx diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 30da01841c..ff8a260540 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -23,6 +23,8 @@ import MapIcon from '@material-ui/icons/MyLocation'; import LayersIcon from '@material-ui/icons/Layers'; import LibraryBooks from '@material-ui/icons/LibraryBooks'; import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; +import Add from '@material-ui/icons/Add'; +import List from '@material-ui/icons/List'; import SearchIcon from '@material-ui/icons/Search'; import MenuIcon from '@material-ui/icons/Menu'; import MoneyIcon from '@material-ui/icons/MonetizationOn'; @@ -46,6 +48,8 @@ import { SidebarScrollWrapper, SidebarSpace, useSidebarOpenState, + SidebarSubmenu, + SidebarSubmenuItem, } from '@backstage/core-components'; import { MyGroupsSidebarItem } from '@backstage/plugin-org'; import GroupIcon from '@material-ui/icons/People'; @@ -106,7 +110,16 @@ export const Root = ({ children }: PropsWithChildren<{}>) => ( - + + + + + + {/* End global nav */} diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index edc9185488..bb69adfe16 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -56,6 +56,7 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@rjsf/core": "^3.2.1", + "@material-table/core": "^4.3.29", "@rjsf/material-ui": "^3.2.1", "@types/json-schema": "^7.0.9", "@uiw/react-codemirror": "^4.7.0", diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index 04103b9f8a..40c88ba68d 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -70,6 +70,18 @@ export class ScaffolderClient implements ScaffolderApi { this.useLongPollingLogs = options.useLongPollingLogs ?? false; } + async listTasks(): Promise { + const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); + const url = `${baseUrl}/v2/tasks`; + + const response = await this.fetchApi.fetch(url); + if (!response.ok) { + throw await ResponseError.fromResponse(response); + } + + return await response.json(); + } + async getIntegrationsList( options: ScaffolderGetIntegrationsListOptions, ): Promise { diff --git a/plugins/scaffolder/src/components/MyTasksPage/MyTaskPage.tsx b/plugins/scaffolder/src/components/MyTasksPage/MyTaskPage.tsx new file mode 100644 index 0000000000..36f7a68616 --- /dev/null +++ b/plugins/scaffolder/src/components/MyTasksPage/MyTaskPage.tsx @@ -0,0 +1,135 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { + Content, + Header, + Lifecycle, + Link, + Page, + Progress, +} from '@backstage/core-components'; +import { useApi, useRouteRef } from '@backstage/core-plugin-api'; +import { Grid } from '@material-ui/core'; +import React from 'react'; +import { scaffolderApiRef } from '../../api'; +import useAsync from 'react-use/lib/useAsync'; +import MaterialTable, { Column } from '@material-table/core'; +import { rootRouteRef } from '../../routes'; +import { Duration, Interval, DateTime } from 'luxon'; +import humanizeDuration from 'humanize-duration'; +import { + StatusError, + StatusPending, + StatusOK, +} from '@backstage/core-components'; + +const CreatedAtColumn = ({ createdAt }: { createdAt: string }) => { + const createdAtTime = DateTime.fromISO(createdAt); + const formatted = Interval.fromDateTimes(createdAtTime, DateTime.local()) + .toDuration() + .valueOf(); + + return

{humanizeDuration(formatted, { round: true })} ago

; +}; + +const TemplateTitle = ({ templateName }: { templateName?: string }) => { + const scaffolder = useApi(scaffolderApiRef); + const { value, loading, error } = useAsync( + () => + scaffolder.getTemplateParameterSchema({ + kind: 'Template', + namespace: 'default', + name: templateName, + }), + [scaffolder, templateName], + ); + + if (loading) { + return null; + } + + return

{value?.title}

; +}; + +const Status = ({ status }) => { + switch (status) { + case 'processing': + return {status}; + case 'completed': + return {status}; + case 'error': + default: + return {status}; + } +}; +export const MyTaskPage = () => { + const scaffolderApi = useApi(scaffolderApiRef); + const { value, loading, error } = useAsync( + () => scaffolderApi.listTasks(), + [scaffolderApi], + ); + + const rootLink = useRouteRef(rootRouteRef); + + return ( + +
+ All my tasks + + } + subtitle="All tasks that have been started by me" + /> + + {loading ? ( + + ) : ( + ( + {row.id} + ), + }, + { + title: 'Name', + render: row => ( + + ), + }, + { + title: 'Created', + field: 'createdAt', + render: row => , + }, + { + title: 'Status', + field: 'status', + render: row => , + }, + ]} + /> + )} + + + ); +}; diff --git a/plugins/scaffolder/src/components/MyTasksPage/index.tsx b/plugins/scaffolder/src/components/MyTasksPage/index.tsx new file mode 100644 index 0000000000..2535904349 --- /dev/null +++ b/plugins/scaffolder/src/components/MyTasksPage/index.tsx @@ -0,0 +1,16 @@ +/* + * Copyright 2022 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { MyTaskPage } from './MyTaskPage'; diff --git a/yarn.lock b/yarn.lock index 4ed8ee03bf..71c81d03e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3988,6 +3988,25 @@ react-beautiful-dnd "^13.0.0" react-double-scrollbar "0.0.15" +"@material-table/core@^4.3.29": + version "4.3.29" + resolved "https://registry.npmjs.org/@material-table/core/-/core-4.3.29.tgz#7f60fe4fc191e016d9be663fa437e00b012eae05" + integrity sha512-7vz1oc3bo1eSzk450NgpA61xQjlgCBg7q1TDGrB8ZDMyx2NvLRxTyNBtW8JEPLaQLoCWoDFK7F/VHOYRN1fKuQ== + dependencies: + "@babel/runtime" "^7.12.5" + "@date-io/date-fns" "^1.3.13" + "@material-ui/icons" "^4.11.2" + "@material-ui/pickers" "^3.2.10" + "@material-ui/styles" "^4.11.4" + classnames "^2.2.6" + date-fns "^2.16.1" + debounce "^1.2.0" + fast-deep-equal "^3.1.3" + prop-types "^15.7.2" + react-beautiful-dnd "^13.0.0" + react-double-scrollbar "0.0.15" + uuid "^3.4.0" + "@material-ui/core@^4.11.0", "@material-ui/core@^4.11.3", "@material-ui/core@^4.12.1", "@material-ui/core@^4.12.2", "@material-ui/core@^4.9.10", "@material-ui/core@^4.9.13": version "4.12.4" resolved "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz#4ac17488e8fcaf55eb6a7f5efb2a131e10138a73"