Merge pull request #54 from tiqi-group/fix/frontend-div-ids

Fix: frontend div ids adhere to html guidelines now
This commit is contained in:
Mose Müller 2023-10-30 14:21:55 +01:00 committed by GitHub
commit 61c6585ac6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 2520 additions and 4179 deletions

View File

@ -113,6 +113,7 @@ import React, { useEffect, useRef, useState } from 'react';
import { Card, Collapse, Image } from 'react-bootstrap';
import { DocStringComponent } from './DocStringComponent';
import { ChevronDown, ChevronRight } from 'react-bootstrap-icons';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
interface ImageComponentProps {
name: string;
@ -130,6 +131,8 @@ export const ImageComponent = React.memo((props: ImageComponentProps) => {
const renderCount = useRef(0);
const [open, setOpen] = useState(true); // add this if you want to expand/collapse your component
const fullAccessPath = parentPath.concat('.' + name);
const id = getIdFromFullAccessPath(fullAccessPath);
useEffect(() => {
renderCount.current++;
@ -143,7 +146,7 @@ export const ImageComponent = React.memo((props: ImageComponentProps) => {
// Your component logic here
return (
<div className={'imageComponent'} id={parentPath.concat('.' + name)}>
<div className={'imageComponent'} id={id}>
{/* Add the Card and Collapse components here if you want to be able to expand and
collapse your component. */}
<Card>

View File

@ -7,12 +7,10 @@
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"rules": {
"no-console": 1, // Means warning
"prettier/prettier": 2 // Means error }
"prettier/prettier": "error"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -46,9 +46,12 @@
"@types/node": "^20.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^5.0.0",
"prettier": "^3.0.0",
"@babel/plugin-proposal-private-property-in-object": "7.21.11"
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.9.0",
"eslint": "^8.52.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"prettier": "^3.0.3",
"typescript": "^4.9.0"
}
}

View File

@ -258,6 +258,7 @@ const App = () => {
<div className="App navbarOffset">
<DataServiceComponent
name={''}
props={state as DataServiceJSON}
isInstantUpdate={isInstantUpdate}
addNotification={addNotification}

View File

@ -2,6 +2,7 @@ import React, { useEffect, useRef } from 'react';
import { emit_update } from '../socket';
import { InputGroup, Form, Button } from 'react-bootstrap';
import { DocStringComponent } from './DocStringComponent';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
interface AsyncMethodProps {
name: string;
@ -17,6 +18,7 @@ export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => {
const { name, parentPath, docString, value: runningTask, addNotification } = props;
const renderCount = useRef(0);
const formRef = useRef(null);
const id = getIdFromFullAccessPath(parentPath.concat('.' + name));
useEffect(() => {
renderCount.current++;
@ -87,9 +89,7 @@ export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => {
});
return (
<div
className="align-items-center asyncMethodComponent"
id={parentPath.concat('.' + name)}>
<div className="align-items-center asyncMethodComponent" id={id}>
{process.env.NODE_ENV === 'development' && (
<p>Render count: {renderCount.current}</p>
)}
@ -99,11 +99,7 @@ export const AsyncMethodComponent = React.memo((props: AsyncMethodProps) => {
</h5>
<Form onSubmit={execute} ref={formRef}>
{args}
<Button
id={`button-${parentPath}.${name}`}
name={name}
value={parentPath}
type="submit">
<Button id={`button-${id}`} name={name} value={parentPath} type="submit">
{runningTask ? 'Stop' : 'Start'}
</Button>
</Form>

View File

@ -2,6 +2,7 @@ import React, { useEffect, useRef } from 'react';
import { ToggleButton } from 'react-bootstrap';
import { emit_update } from '../socket';
import { DocStringComponent } from './DocStringComponent';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
interface ButtonComponentProps {
name: string;
@ -17,6 +18,7 @@ export const ButtonComponent = React.memo((props: ButtonComponentProps) => {
const { name, parentPath, value, readOnly, docString, mapping, addNotification } =
props;
const buttonName = mapping ? (value ? mapping[0] : mapping[1]) : name;
const id = getIdFromFullAccessPath(parentPath.concat('.' + name));
const renderCount = useRef(0);
@ -33,14 +35,14 @@ export const ButtonComponent = React.memo((props: ButtonComponentProps) => {
};
return (
<div className={'buttonComponent'} id={parentPath.concat('.' + name)}>
<div className={'buttonComponent'} id={id}>
{process.env.NODE_ENV === 'development' && (
<p>Render count: {renderCount.current}</p>
)}
<DocStringComponent docString={docString} />
<ToggleButton
id={`toggle-check-${parentPath}.${name}`}
id={`toggle-check-${id}`}
type="checkbox"
variant={value ? 'success' : 'secondary'}
checked={value}

View File

@ -2,6 +2,7 @@ import React, { useEffect, useRef } from 'react';
import { InputGroup, Form, Row, Col } from 'react-bootstrap';
import { emit_update } from '../socket';
import { DocStringComponent } from './DocStringComponent';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
interface ColouredEnumComponentProps {
name: string;
@ -24,6 +25,7 @@ export const ColouredEnumComponent = React.memo((props: ColouredEnumComponentPro
addNotification
} = props;
const renderCount = useRef(0);
const id = getIdFromFullAccessPath(parentPath.concat('.' + name));
useEffect(() => {
renderCount.current++;
@ -33,13 +35,12 @@ export const ColouredEnumComponent = React.memo((props: ColouredEnumComponentPro
addNotification(`${parentPath}.${name} changed to ${value}.`);
}, [props.value]);
const handleValueChange = (newValue) => {
console.log(newValue);
const handleValueChange = (newValue: string) => {
emit_update(name, parentPath, newValue);
};
return (
<div className={'enumComponent'} id={parentPath.concat('.' + name)}>
<div className={'enumComponent'} id={id}>
{process.env.NODE_ENV === 'development' && (
<p>Render count: {renderCount.current}</p>
)}
@ -61,7 +62,7 @@ export const ColouredEnumComponent = React.memo((props: ColouredEnumComponentPro
value={value}
style={{ backgroundColor: enumDict[value] }}
onChange={(event) => handleValueChange(event.target.value)}>
{Object.entries(enumDict).map(([key, val]) => (
{Object.entries(enumDict).map(([key]) => (
<option key={key} value={key}>
{key}
</option>

View File

@ -3,8 +3,10 @@ import React from 'react';
import { Card, Collapse } from 'react-bootstrap';
import { ChevronDown, ChevronRight } from 'react-bootstrap-icons';
import { Attribute, GenericComponent } from './GenericComponent';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
type DataServiceProps = {
name: string;
props: DataServiceJSON;
parentPath?: string;
isInstantUpdate: boolean;
@ -15,21 +17,29 @@ export type DataServiceJSON = Record<string, Attribute>;
export const DataServiceComponent = React.memo(
({
name,
props,
parentPath = 'DataService',
isInstantUpdate,
addNotification
}: DataServiceProps) => {
const [open, setOpen] = useState(true);
let fullAccessPath = parentPath;
if (name) {
fullAccessPath = parentPath.concat('.' + name);
}
console.log(fullAccessPath);
const id = getIdFromFullAccessPath(fullAccessPath);
console.log(id);
return (
<div className="dataServiceComponent">
<div className="dataServiceComponent" id={id}>
<Card className="mb-3">
<Card.Header
onClick={() => setOpen(!open)}
style={{ cursor: 'pointer' }} // Change cursor style on hover
>
{parentPath} {open ? <ChevronDown /> : <ChevronRight />}
{fullAccessPath} {open ? <ChevronDown /> : <ChevronRight />}
</Card.Header>
<Collapse in={open}>
<Card.Body>
@ -39,7 +49,7 @@ export const DataServiceComponent = React.memo(
key={key}
attribute={value}
name={key}
parentPath={parentPath}
parentPath={fullAccessPath}
isInstantUpdate={isInstantUpdate}
addNotification={addNotification}
/>

View File

@ -153,8 +153,9 @@ export const GenericComponent = React.memo(
} else if (attribute.type === 'DataService') {
return (
<DataServiceComponent
name={name}
props={attribute.value as DataServiceJSON}
parentPath={parentPath.concat('.', name)}
parentPath={parentPath}
isInstantUpdate={isInstantUpdate}
addNotification={addNotification}
/>

View File

@ -2,6 +2,7 @@ import React, { useEffect, useRef, useState } from 'react';
import { Card, Collapse, Image } from 'react-bootstrap';
import { DocStringComponent } from './DocStringComponent';
import { ChevronDown, ChevronRight } from 'react-bootstrap-icons';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
interface ImageComponentProps {
name: string;
@ -18,6 +19,7 @@ export const ImageComponent = React.memo((props: ImageComponentProps) => {
const renderCount = useRef(0);
const [open, setOpen] = useState(true);
const id = getIdFromFullAccessPath(parentPath.concat('.' + name));
useEffect(() => {
renderCount.current++;
@ -28,7 +30,7 @@ export const ImageComponent = React.memo((props: ImageComponentProps) => {
}, [props.value]);
return (
<div className={'imageComponent'} id={parentPath.concat('.' + name)}>
<div className={'imageComponent'} id={id}>
<Card>
<Card.Header
onClick={() => setOpen(!open)}

View File

@ -1,6 +1,7 @@
import React, { useEffect, useRef } from 'react';
import { DocStringComponent } from './DocStringComponent';
import { Attribute, GenericComponent } from './GenericComponent';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
interface ListComponentProps {
name: string;
@ -16,13 +17,14 @@ export const ListComponent = React.memo((props: ListComponentProps) => {
props;
const renderCount = useRef(0);
const id = getIdFromFullAccessPath(parentPath.concat('.' + name));
useEffect(() => {
renderCount.current++;
}, [props]);
return (
<div className={'listComponent'} id={parentPath.concat('.' + name)}>
<div className={'listComponent'} id={id}>
{process.env.NODE_ENV === 'development' && (
<p>Render count: {renderCount.current}</p>
)}

View File

@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
import { emit_update } from '../socket';
import { Button, InputGroup, Form, Collapse } from 'react-bootstrap';
import { DocStringComponent } from './DocStringComponent';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
interface MethodProps {
name: string;
@ -19,6 +20,7 @@ export const MethodComponent = React.memo((props: MethodProps) => {
const [hideOutput, setHideOutput] = useState(false);
// Add a new state variable to hold the list of function calls
const [functionCalls, setFunctionCalls] = useState([]);
const id = getIdFromFullAccessPath(parentPath.concat('.' + name));
useEffect(() => {
renderCount.current++;
@ -69,9 +71,7 @@ export const MethodComponent = React.memo((props: MethodProps) => {
});
return (
<div
className="align-items-center methodComponent"
id={parentPath.concat('.' + name)}>
<div className="align-items-center methodComponent" id={id}>
{process.env.NODE_ENV === 'development' && (
<p>Render count: {renderCount.current}</p>
)}

View File

@ -3,6 +3,7 @@ import { Form, InputGroup } from 'react-bootstrap';
import { emit_update } from '../socket';
import { DocStringComponent } from './DocStringComponent';
import '../App.css';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
// TODO: add button functionality
@ -30,8 +31,8 @@ interface NumberComponentProps {
const handleArrowKey = (
key: string,
value: string,
selectionStart: number,
selectionEnd: number
selectionStart: number
// selectionEnd: number
) => {
// Split the input value into the integer part and decimal part
const parts = value.split('.');
@ -131,14 +132,14 @@ export const NumberComponent = React.memo((props: NumberComponentProps) => {
const [cursorPosition, setCursorPosition] = useState(null);
// Create a state for the input string
const [inputString, setInputString] = useState(props.value.toString());
const fullAccessPath = parentPath.concat('.' + name);
const id = getIdFromFullAccessPath(fullAccessPath);
useEffect(() => {
renderCount.current++;
// Set the cursor position after the component re-renders
const inputElement = document.getElementsByName(
parentPath.concat('.' + name)
)[0] as HTMLInputElement;
const inputElement = document.getElementsByName(id)[0] as HTMLInputElement;
if (inputElement && cursorPosition !== null) {
inputElement.setSelectionRange(cursorPosition, cursorPosition);
}
@ -233,8 +234,8 @@ export const NumberComponent = React.memo((props: NumberComponentProps) => {
({ value: newValue, selectionStart } = handleArrowKey(
key,
value,
selectionStart,
selectionEnd
selectionStart
// selectionEnd
));
} else if (key === 'Backspace') {
({ value: newValue, selectionStart } = handleBackspaceKey(
@ -275,7 +276,7 @@ export const NumberComponent = React.memo((props: NumberComponentProps) => {
};
return (
<div className="numberComponent" id={parentPath.concat('.' + name)}>
<div className="numberComponent" id={id}>
{process.env.NODE_ENV === 'development' && showName && (
<p>Render count: {renderCount.current}</p>
)}
@ -287,7 +288,7 @@ export const NumberComponent = React.memo((props: NumberComponentProps) => {
type="text"
value={inputString}
disabled={readOnly}
name={parentPath.concat('.' + name)}
name={fullAccessPath}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
className={isInstantUpdate && !readOnly ? 'instantUpdate' : ''}

View File

@ -4,6 +4,7 @@ import { emit_update } from '../socket';
import { DocStringComponent } from './DocStringComponent';
import { Slider } from '@mui/material';
import { NumberComponent } from './NumberComponent';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
interface SliderComponentProps {
name: string;
@ -21,11 +22,6 @@ interface SliderComponentProps {
export const SliderComponent = React.memo((props: SliderComponentProps) => {
const renderCount = useRef(0);
const [open, setOpen] = useState(false);
useEffect(() => {
renderCount.current++;
});
const {
name,
parentPath,
@ -38,6 +34,12 @@ export const SliderComponent = React.memo((props: SliderComponentProps) => {
isInstantUpdate,
addNotification
} = props;
const fullAccessPath = parentPath.concat('.' + name);
const id = getIdFromFullAccessPath(fullAccessPath);
useEffect(() => {
renderCount.current++;
});
useEffect(() => {
addNotification(`${parentPath}.${name} changed to ${value}.`);
@ -102,7 +104,7 @@ export const SliderComponent = React.memo((props: SliderComponentProps) => {
};
return (
<div className="sliderComponent" id={parentPath.concat('.' + name)}>
<div className="sliderComponent" id={id}>
{process.env.NODE_ENV === 'development' && (
<p>Render count: {renderCount.current}</p>
)}
@ -145,6 +147,7 @@ export const SliderComponent = React.memo((props: SliderComponentProps) => {
</Col>
<Col xs="auto">
<ToggleButton
id={`button-${id}`}
onClick={() => setOpen(!open)}
type="checkbox"
checked={open}

View File

@ -3,6 +3,7 @@ import { Form, InputGroup } from 'react-bootstrap';
import { emit_update } from '../socket';
import { DocStringComponent } from './DocStringComponent';
import '../App.css';
import { getIdFromFullAccessPath } from '../utils/stringUtils';
// TODO: add button functionality
@ -22,6 +23,8 @@ export const StringComponent = React.memo((props: StringComponentProps) => {
const renderCount = useRef(0);
const [inputString, setInputString] = useState(props.value);
const fullAccessPath = parentPath.concat('.' + name);
const id = getIdFromFullAccessPath(fullAccessPath);
useEffect(() => {
renderCount.current++;
@ -55,7 +58,7 @@ export const StringComponent = React.memo((props: StringComponentProps) => {
};
return (
<div className={'stringComponent'} id={parentPath.concat('.' + name)}>
<div className={'stringComponent'} id={id}>
{process.env.NODE_ENV === 'development' && (
<p>Render count: {renderCount.current}</p>
)}

View File

@ -0,0 +1,12 @@
export function getIdFromFullAccessPath(fullAccessPath: string) {
// Replace '].' with a single dash
let id = fullAccessPath.replace(/\]\./g, '-');
// Replace any character that is not a word character or underscore with a dash
id = id.replace(/[^\w_]+/g, '-');
// Remove any trailing dashes
id = id.replace(/-+$/, '');
return id;
}

View File

@ -1,13 +1,13 @@
{
"files": {
"main.css": "/static/css/main.398bc7f8.css",
"main.js": "/static/js/main.6d7a3319.js",
"main.css": "/static/css/main.c444b055.css",
"main.js": "/static/js/main.afebc391.js",
"index.html": "/index.html",
"main.398bc7f8.css.map": "/static/css/main.398bc7f8.css.map",
"main.6d7a3319.js.map": "/static/js/main.6d7a3319.js.map"
"main.c444b055.css.map": "/static/css/main.c444b055.css.map",
"main.afebc391.js.map": "/static/js/main.afebc391.js.map"
},
"entrypoints": [
"static/css/main.398bc7f8.css",
"static/js/main.6d7a3319.js"
"static/css/main.c444b055.css",
"static/js/main.afebc391.js"
]
}

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site displaying a pydase UI."/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>pydase App</title><script defer="defer" src="/static/js/main.6d7a3319.js"></script><link href="/static/css/main.398bc7f8.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site displaying a pydase UI."/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>pydase App</title><script defer="defer" src="/static/js/main.afebc391.js"></script><link href="/static/css/main.c444b055.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -45,11 +45,3 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @mui/styled-engine v5.13.2
*
* @license MIT
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

File diff suppressed because one or more lines are too long