trigger screen

This commit is contained in:
IDONTSUDO 2023-11-01 18:24:43 +03:00
parent fbcfba3948
commit d10a829882
30 changed files with 19101 additions and 26 deletions

23
ui/.gitignore vendored Normal file
View file

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

18534
ui/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

50
ui/package.json Normal file
View file

@ -0,0 +1,50 @@
{
"name": "infinite-todo-list",
"version": "0.1.0",
"private": true,
"dependencies": {
"@monaco-editor/react": "^4.6.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.18.46",
"@types/react": "^18.2.21",
"@types/react-dom": "^18.2.7",
"@types/uuid": "^9.0.2",
"formik-antd": "^2.0.4",
"mobx": "^6.10.0",
"mobx-react-lite": "^4.0.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"sass": "^1.66.1",
"typescript": "^4.9.5",
"uuid": "^9.0.0",
"web-vitals": "^2.1.4"
},
"scripts": {
"dev": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

BIN
ui/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

20
ui/public/index.html Normal file
View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>Infinite Todo List</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

BIN
ui/public/logo192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
ui/public/logo512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

25
ui/public/manifest.json Normal file
View file

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
ui/public/robots.txt Normal file
View file

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View file

@ -0,0 +1,12 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="64px" height="64px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier"> <path d="M12 7.75732L12 16.2426" stroke="#f46036" stroke-width="2" stroke-linecap="round"/> <path d="M7.75735 12L16.2426 12" stroke="#f46036" stroke-width="2" stroke-linecap="round"/> <rect x="3" y="3" width="18" height="18" rx="3" stroke="#f46036" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </g>
</svg>

After

Width:  |  Height:  |  Size: 769 B

View file

@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="64px" height="64px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier"> <g id="Interface / Check"> <path id="Vector" d="M6 12L10.2426 16.2426L18.727 7.75732" stroke="#f8f9fa" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </g> </g>
</svg>

After

Width:  |  Height:  |  Size: 628 B

View file

@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="64px" height="64px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier"> <path d="M15.8351 11.6296L9.20467 5.1999C8.79094 4.79869 8 5.04189 8 5.5703L8 18.4297C8 18.9581 8.79094 19.2013 9.20467 18.8001L15.8351 12.3704C16.055 12.1573 16.0549 11.8427 15.8351 11.6296Z" fill="#013a63"/> </g>
</svg>

After

Width:  |  Height:  |  Size: 664 B

View file

@ -0,0 +1,13 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="64px" height="64px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier">
<rect width="24" height="24" fill="none"/> <path d="M7 17L16.8995 7.10051" stroke="#f55d3e" stroke-linecap="round" stroke-linejoin="round"/> <path d="M7 7.00001L16.8995 16.8995" stroke="#f46036" stroke-linecap="round" stroke-linejoin="round"/> </g>
</svg>

After

Width:  |  Height:  |  Size: 701 B

View file

@ -0,0 +1,12 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="64px" height="64px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier"> <path fill-rule="evenodd" clip-rule="evenodd" d="M2 5.75C2 5.33579 2.33579 5 2.75 5H20.75C21.1642 5 21.5 5.33579 21.5 5.75C21.5 6.16421 21.1642 6.5 20.75 6.5H2.75C2.33579 6.5 2 6.16421 2 5.75ZM2 9.75C2 9.33579 2.33579 9 2.75 9H20.75C21.1642 9 21.5 9.33579 21.5 9.75C21.5 10.1642 21.1642 10.5 20.75 10.5H2.75C2.33579 10.5 2 10.1642 2 9.75ZM20.2113 12.6586C20.5379 12.9134 20.5961 13.3847 20.3414 13.7113L16.4414 18.7113C16.3022 18.8897 16.0899 18.9958 15.8636 18.9999C15.6373 19.004 15.4213 18.9057 15.2757 18.7324L13.1757 16.2324C12.9093 15.9152 12.9504 15.4421 13.2676 15.1757C13.5848 14.9093 14.0579 14.9504 14.3243 15.2676L15.8284 17.0582L19.1586 12.7887C19.4134 12.4621 19.8847 12.4039 20.2113 12.6586ZM2 13.75C2 13.3358 2.33579 13 2.75 13H9.75C10.1642 13 10.5 13.3358 10.5 13.75C10.5 14.1642 10.1642 14.5 9.75 14.5H2.75C2.33579 14.5 2 14.1642 2 13.75ZM2 17.75C2 17.3358 2.33579 17 2.75 17H9.75C10.1642 17 10.5 17.3358 10.5 17.75C10.5 18.1642 10.1642 18.5 9.75 18.5H2.75C2.33579 18.5 2 18.1642 2 17.75Z" fill="#f46036"/> </g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,32 @@
export enum HttpMethod {
GET = 'GET',
POST = 'POST'
}
export class HttpRepository {
private server = 'http://localhost:3000'
public async jsonRequest<T>(method: HttpMethod, url: string, data?: any): Promise<T> {
const reqInit = {
'body': data,
'method': method,
'headers': { 'Content-Type': 'application/json' },
}
if (data !== undefined) {
reqInit['body'] = JSON.stringify(data)
}
return (await fetch(this.server + url, reqInit)).json()
}
public async request<T>(method: HttpMethod, url: string, data?: any): Promise<T> {
const reqInit = {
'body': data,
'method': method,
}
if (data !== undefined) {
reqInit['body'] = data
}
return (await fetch(this.server + url, reqInit)).json()
}
}

View file

@ -0,0 +1,11 @@
import {
HttpMethod,
HttpRepository,
} from "../../../core/repository/http_repository";
import { ITriggerModel } from "../model/trigger_model";
export class TriggerRepository extends HttpRepository {
public async save(model: ITriggerModel) {
return await this.jsonRequest(HttpMethod.POST, "/trigger", model);
}
}

View file

@ -0,0 +1,10 @@
import { TriggerType } from "./trigger_model";
export interface ITriggerViewValueModel {
value: string;
}
export interface TriggerViewModel extends ITriggerViewValueModel {
id: string;
type: TriggerType;
}

View file

@ -0,0 +1,10 @@
export interface ITriggerModel {
_id?: string;
type: string;
value: string[];
}
export enum TriggerType {
PROCESS = "PROCESS",
FILE = "FILE",
}

View file

@ -0,0 +1,39 @@
import * as React from "react";
import Editor from "@monaco-editor/react";
import { Button } from "antd";
import { observer } from "mobx-react-lite";
import { triggerStore } from "../logic/trigger_store";
export const CodeTriggerForm: React.FunctionComponent = observer(() => {
return (
<>
<div style={{ width: "100%", backgroundColor: "black", height: "1px" }} />
<Editor
height="40vh"
defaultLanguage="javascript"
value={triggerStore.codeTriggerValue}
onChange={(v) => {
triggerStore.writeNewTrigger(v);
}}
onValidate={(m) => {
console.log(m);
}}
/>
<div style={{ width: "100%", backgroundColor: "black", height: "1px" }} />
<div style={{ height: "10px" }}/>
<Button
onClick={() => triggerStore.saveCode()}
style={{ marginLeft: "10px", marginRight: "10px" }}
>
Save code
</Button>
<Button onClick={() => triggerStore.clearTriggerCode()}>
Reset code
</Button>
</>
);
});

View file

@ -0,0 +1,55 @@
import * as React from "react";
import { Formik } from "formik";
import { SubmitButton, Input, ResetButton, Form, FormItem } from "formik-antd";
import { Row, Col } from "antd";
import { observer } from "mobx-react-lite";
import { triggerStore } from "../logic/trigger_store";
import { TriggerType } from "../../model/trigger_model";
function validateRequired(value: string) {
return value ? undefined : "required";
}
export const FileTriggerForm: React.FunctionComponent = observer(() => {
return (
<>
<div style={{ marginTop: 80 }}>
<Formik
initialValues={{
value: "",
}}
onSubmit={(values, actions) => {
triggerStore.pushTrigger(values.value, TriggerType.FILE);
actions.setSubmitting(false);
actions.resetForm();
}}
validate={(values) => {
if (values.value.length === 0) {
return false;
}
return {};
}}
render={() => (
<Form>
<div style={{ background: "white", flex: 1, padding: 40 }}>
<FormItem
name="value"
required={true}
validate={validateRequired}
>
<Input name="value" placeholder="regExp file" />
</FormItem>
<Row style={{ marginTop: 60 }}>
<Col offset={8}>
<ResetButton>Reset</ResetButton>
<SubmitButton>Submit</SubmitButton>
</Col>
</Row>
</div>
</Form>
)}
/>
</div>
</>
);
});

View file

@ -0,0 +1,80 @@
import { makeAutoObservable } from "mobx";
import { v4 as uuidv4 } from "uuid";
import { TriggerType } from "../../model/trigger_model";
import { TriggerRepository } from "../../data/trigger_repository";
import { TriggerViewModel } from "../../model/trigger_form_view_model";
class TriggerStore {
constructor(repository: TriggerRepository) {
this.triggerType = TriggerType.FILE;
this.repository = repository;
makeAutoObservable(this);
}
triggerType: TriggerType;
codeTriggerValue = "";
triggers: TriggerViewModel[] = [];
repository: TriggerRepository;
deleteItem(id: string): void {
this.triggers = this.triggers.filter((el) => el.id !== id);
console.log(id);
}
getTriggerType = (): boolean => {
return this.triggerType === TriggerType.FILE;
};
setTriggerType = (): void => {
this.triggers = [];
if (this.triggerType === TriggerType.FILE) {
this.triggerType = TriggerType.PROCESS;
return;
}
this.triggerType = TriggerType.FILE;
};
getTriggerDescription = (): string => {
return this.triggerType === TriggerType.FILE
? TriggerType.FILE
: TriggerType.PROCESS;
};
pushTrigger = (value: string, type: TriggerType): void => {
console.log(value);
this.triggers.push({
value: value,
id: uuidv4(),
type: type,
});
};
writeNewTrigger(v: string | undefined): void {
if (v === undefined) {
throw new Error("Editor Value is undefined");
}
this.codeTriggerValue = v;
}
clearTriggerCode(): void {
this.codeTriggerValue = "";
}
saveCode(): void {
if (this.codeTriggerValue !== "") {
this.triggers.push({
id: uuidv4(),
value: this.codeTriggerValue,
type: TriggerType.PROCESS,
});
this.codeTriggerValue = "";
}
}
async saveResult(): Promise<void> {
await this.repository.save({
type: this.getTriggerDescription(),
value: this.triggers.map((el) => {
return el.value;
}),
});
}
}
export const triggerStore = new TriggerStore(new TriggerRepository());

View file

@ -0,0 +1,66 @@
import * as React from "react";
import { Button, Col, Row, Switch, Typography } from "antd";
import { CodeTriggerForm } from "./components/code_trigger_form";
import { observer } from "mobx-react-lite";
import { triggerStore } from "./logic/trigger_store";
import { FileTriggerForm } from "./components/file_trigger_form";
import { ReactComponent as DeleteIcon } from "../../../assets/icons/delete.svg";
const { Title } = Typography;
const Header = observer(() => {
return (
<Row style={{ justifyItems: "center", alignItems: "center" }}>
<div style={{ height: "37px" }}>
<Switch
checked={triggerStore.getTriggerType()}
onChange={() => triggerStore.setTriggerType()}
/>
</div>
<Title level={2}>
Trigger editor: {triggerStore.getTriggerDescription()}
</Title>
<div style={{ width: "10px" }}></div>
<Button onClick={() => triggerStore.saveResult()}>Save result</Button>
</Row>
);
});
const Bottom = observer(() => {
return (
<Col>
{triggerStore.triggers.map((el) => {
return (
<Row
style={{
justifyContent: "center",
}}
>
{el.value}
<DeleteIcon onClick={() => triggerStore.deleteItem(el.id)} />
</Row>
);
})}
</Col>
);
});
export const TriggerScreen: React.FunctionComponent = observer(() => {
return (
<>
<main className="test">
<Header />,
{triggerStore.getTriggerType() ? (
<>
<FileTriggerForm />
</>
) : (
<>
<CodeTriggerForm />
</>
)}
<Bottom />
</main>
</>
);
});

16
ui/src/index.tsx Normal file
View file

@ -0,0 +1,16 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { TriggerScreen } from './features/trigger/presentation/trigger_presentation';
import "antd/dist/antd.css";
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<TriggerScreen />
</React.StrictMode>
);

1
ui/src/react-app-env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="react-scripts" />

27
ui/tsconfig.json Normal file
View file

@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"useDefineForClassFields": true
},
"include": [
"src"
]
}