Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #2

Merged
merged 3 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
756 changes: 712 additions & 44 deletions metal-ui/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions metal-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@types/react-dom": "^18.0.8",
"ajv": "^8.11.2",
"axios": "^1.1.3",
"cal-heatmap": "^4.1.0",
"elkjs": "^0.8.2",
"flexlayout-react": "^0.7.5",
"http-proxy-middleware": "^2.0.6",
Expand Down Expand Up @@ -67,6 +68,7 @@
]
},
"devDependencies": {
"@types/lodash-es": "^4.17.6",
"@types/react-syntax-highlighter": "^15.5.5",
"@types/uuid": "^8.3.4"
}
Expand Down
2 changes: 2 additions & 0 deletions metal-ui/src/App.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import "flexlayout-react/style/underline.css";
@import 'cal-heatmap/cal-heatmap.css';

.App {
left: 0px;
Expand All @@ -18,3 +19,4 @@
box-sizing: border-box;
overflow: hidden;
}

2 changes: 1 addition & 1 deletion metal-ui/src/api/ProjectApi.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import axios, { AxiosError } from "axios";
import axios from "axios";
import {ApiResponse, ApiResponseEntity, timeout} from "./APIs";
import {BackendStatus, Deploy, Project} from "../model/Project";
import _ from "lodash"
Expand Down
5 changes: 2 additions & 3 deletions metal-ui/src/api/UserApi.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios, {AxiosBasicCredentials} from "axios";
import {ApiResponse, ApiResponseEntity, ApiResponseStatus, timeout} from "./APIs";
import {ApiResponse, ApiResponseEntity, timeout} from "./APIs";
import {User} from "../model/User";

const instance = axios.create({
Expand Down Expand Up @@ -38,10 +38,9 @@ export async function sync(token: string): Promise<User> {
const user: User = resp.data
return user
} else {
if (resp.msg == undefined) {
if (resp.msg === undefined) {
throw new Error('Response is failure, and no msg found in response.')
}
const msg: string = resp.msg
throw new Error(resp.msg)
}
} catch (err) {
Expand Down
2 changes: 1 addition & 1 deletion metal-ui/src/features/designer/MetalView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ export function MetalNode(props: NodeProps<MetalNodeProps>) {
</div>
</Badge>
),
[badgeContent, isInputReady, isReadOnly, metal.id, metal.name, metal.props, metalPkg.class, msg, nodeView, onDelete, onEdit, props.data, status]
[badgeContent, isInputReady, isPropDefined, isReadOnly, metal.id, metal.name, metalPkg.class, msg, nodeView, onDelete, onEdit, props.data, status]
);
return (<>{view}</>)

Expand Down
2 changes: 1 addition & 1 deletion metal-ui/src/features/designer/backend/BackendBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ function BackendStatusBrief() {
startIcon={icon}
sx={{
borderRadius: "0px",
width: "15vw",
width: "20vw",
}}
>
{tip}
Expand Down
125 changes: 123 additions & 2 deletions metal-ui/src/features/home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,24 @@ import { FaStop } from "react-icons/fa";
import { ImDownload, ImUpload } from "react-icons/im";
import { AiOutlineFunction } from "react-icons/ai";
import { useAsync } from "../../api/Hooks";
import { useEffect, useRef } from "react";
import { useCallback, useEffect, useRef } from "react";
import { BackendState, Project } from "../../model/Project";
import { getAllProjectOfUser } from "../../api/ProjectApi";
import { MetalPkg } from "../../model/MetalPkg";
import { metalType, MetalTypes } from "../../model/Metal";
import { getAllMetalPkgsOfUserAccess } from "../../api/MetalPkgApi";
import { MainHandler } from "../main/Main";
import { useUIAsync } from "../ui/UIHooks";
import { Exec } from "../../model/Exec";
import { getAllExecsOfUser } from "../../api/ExecApi";
import moment from "moment";
import _ from "lodash";
import { State } from "../../api/State";
import CalHeatmap from 'cal-heatmap';


import { OptionsType } from "cal-heatmap/src/options/Options";


export interface HomeProps {
mainHandler: MainHandler;
Expand All @@ -59,7 +70,9 @@ export function Home(props: HomeProps) {
};

const onOpenMetalRepo = () => {
mainHandler.openMetalRepo({});
mainHandler.openMetalRepo({
mainHandler: mainHandler
});
};

const onOpenUserPage = () => {
Expand Down Expand Up @@ -107,12 +120,120 @@ export function Home(props: HomeProps) {
</Button>
</ListItem>
</List>
<ExecutionSummary token={token} />
<ProjectSummary token={token} />
<MetalRepoSummary token={token} />
</div>
);
}

interface ExecutionSummaryProps {
token: string | null
}

function useExecutionSummary(token: string | null): [
() => void,
{date: string, value: number}[]
] {
const [run, status, result] = useUIAsync<Exec[]>();
const fetch = useCallback(()=>{
if (token === null) {
return
}

run(getAllExecsOfUser(token));
}, [run, token]);

const summary = result === null
? []
: _.entries(
_.countBy(
result, exec => moment(exec?.createTime).format("YYYY-MM-DD")
)
).map(e => ({date: e[0], value: e[1]})) ;

useEffect(() => {
if (status === State.idle) {
fetch();
}
}, [fetch, status]);

return [fetch, summary];
}

function ExecutionSummary(props: ExecutionSummaryProps) {
const { token } = props;
const [, summary] = useExecutionSummary(token);
const start = moment().subtract(12, "month").format("YYYY-MM-DD");
return (
<Accordion defaultExpanded={true}>
<AccordionSummary expandIcon={<VscChevronDown size={"2em"} />}>
<Typography variant="h5">Executions</Typography>
</AccordionSummary>
<AccordionDetails>
<Divider orientation="horizontal" flexItem />
<Heatmap
data={{
source: summary,
x: 'date',
y: 'value'
}}
domain={{
type: 'month'
}}
subDomain={{
type: 'day',
radius: 2,
label: (timestamp: number, value: number) => (
value
)
}}
date={{
start: new Date(start)
}}
scale={{
color: {
range: ['yellow', 'red'],
interpolate: 'hsl',
type: 'linear',
domain: [0, 30]
}
}}
/>
</AccordionDetails>
</Accordion>
);
}

declare type HeatmapProps = CalHeatmap.DeepPartial<OptionsType>;

function Heatmap(props: HeatmapProps) {

useEffect(()=>{
const cal: CalHeatmap = new CalHeatmap();

cal.paint({
...props,
itemSelector: '#heat-map'
});

return () => {
cal.destroy();
}
}, [props]);

return (
<div id='heat-map' style={{
boxSizing: "border-box",
padding: "1em"
}}>

</div>
)
}



const ICON_SIZE = "4vw";
const CARD_H_PAD = "2vw";
const CARD_V_PAD = "2vh";
Expand Down
57 changes: 54 additions & 3 deletions metal-ui/src/features/main/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ import { Skeleton } from "@mui/material";
import { AiOutlineDeploymentUnit } from "react-icons/ai";
import { FaProjectDiagram } from "react-icons/fa";
import { RiFunctionLine } from "react-icons/ri";
import { VscAccount, VscBrowser, VscCircuitBoard, VscExtensions, VscHome, VscPreview } from "react-icons/vsc";
import { VscAccount, VscBrowser, VscCircuitBoard, VscExtensions, VscHome, VscPackage, VscPreview } from "react-icons/vsc";
import { GrTasks } from "react-icons/gr";
import { ProjectStarter, ProjectStarterProps } from "../project/ProjectStarter";
import { DesignerProvider } from "../designer/DesignerProvider";
import { Home, HomeProps } from "../home/Home";
import { MetalRepo, MetalRepoProps } from "../repository/MetalRepo";
import { MetalPkgPage, MetalPkgPageProps, MetalRepo, MetalRepoProps } from "../repository/MetalRepo";
import create from "zustand";
import { subscribeWithSelector } from "zustand/middleware";
import _ from "lodash";
import { Executions, ExecutionsProps } from "../execution/Executions";
import { Viewer, ViewerProps } from "../designer/Viewer";
import { ExecutionPage, ExecutionPageProps } from "../execution/ExecutionPage";
import { UserPage, UserPageProps } from "../user/UserPage";
import { MetalPkgProps } from "../designer/explorer/MetalExplorer";

interface Component {
id: string,
Expand Down Expand Up @@ -85,6 +86,8 @@ function iconFatory(node: TabNode) {
return <VscHome />;
case "metalRepoIcon":
return <VscExtensions />;
case "metalPkgPageIcon":
return <VscPackage />;
case "deploymentIcon":
return <AiOutlineDeploymentUnit />;
case "executionPageIcon":
Expand All @@ -111,11 +114,16 @@ export function execPageId(id: string) {
return `exec[${id}]`;
}

export function metalPkgPageId(id: string) {
return `metal pkg[${id}]`;
}

export interface MainHandler {
openProjectStarter: (props: ProjectStarterProps) => void;
openDesigner: (props: DesignerProps) => void;
openViewer: (props: ViewerProps) => void;
openMetalRepo: (props: MetalRepoProps) => void;
openMetalPkgPage: (props: MetalPkgPageProps) => void;
openExecutionPage: (props: ExecutionPageProps) => void;
openUserPage: (props: UserPageProps) => void;
select: (id: string) => void;
Expand Down Expand Up @@ -346,6 +354,35 @@ export function Main() {
}
};

const openMetalPkgPage = (props: MetalPkgPageProps) => {
const {id} = props.pkg;
const tab: IJsonTabNode = {
type: "tab",
id: metalPkgPageId(id),
name: `Metal[${props.pkg.class}]`,
icon: "metalPkgPageIcon",
component: "metalPkgPage",
config: props,
}

const action: Action = Actions.addNode(
tab,
"main",
DockLocation.CENTER,
1
);
try{
layoutModel.doAction(action);
}catch (error) {
console.error(error);
if (
(error as Error).message.startsWith('Error: each node must have a unique id') &&
tab.id !== undefined) {
select(tab.id);
}
}
};



const close = (id: string) => {
Expand Down Expand Up @@ -407,6 +444,7 @@ export function Main() {
openDesigner: openDesigner,
openViewer: openViewer,
openMetalRepo: openMetalRepo,
openMetalPkgPage: openMetalPkgPage,
openExecutionPage: openExecutionPage,
openUserPage: openUserPage,
select: select,
Expand Down Expand Up @@ -460,12 +498,25 @@ export function Main() {
}

case "metalRepo": {
const props: MetalRepoProps = config;
const props: MetalRepoProps = {
...config,
mainHandler: mainHandler
};
return memorizeCmps(component, props, ()=>(
<MetalRepo {...props} />
), id);
}

case "metalPkgPage": {
const props: MetalPkgPageProps = {
...config,
mainHandler: mainHandler
};
return memorizeCmps(component, props, ()=>(
<MetalPkgPage {...props} />
), id);
}

case "executionPage": {
const props: ExecutionPageProps = {
...config,
Expand Down
7 changes: 7 additions & 0 deletions metal-ui/src/features/project/ProjectProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,12 @@ export function BackendArgsProfile(props: BackendArgsProfileProps) {
type: "string",
},
};
const uiSchema = {
items: {
'ui:widget': 'textarea',
'ui:description': 'Item should be \'{string}\'. And " in {string} should be escape by \\.'
}
}

const onSubmit = (data: IChangeEvent<any, RJSFSchema, any>) => {
const newProfile: string[] = data.formData;
Expand All @@ -483,6 +489,7 @@ export function BackendArgsProfile(props: BackendArgsProfileProps) {
<Form
formData={profile === undefined ? [] : profile}
schema={schema}
uiSchema={uiSchema}
validator={validator}
onSubmit={onSubmit}
>
Expand Down
Loading