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

Feature/#551 Expose a metric control #1272

Merged
merged 30 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
06892d0
Adding <Metric /> components to Taipy-gui.
namnguyen20999 May 7, 2024
b099da2
resolve conflict
namnguyen20999 May 7, 2024
b7c0ad5
fix incorrect pytest mark
namnguyen20999 May 7, 2024
29ca496
Using useMemo instead of useState + useEffect
namnguyen20999 May 9, 2024
6784551
move style outside component and refactor threshold as dynamic_value
namnguyen20999 May 10, 2024
162b966
using useMemo for Plot layout & style
namnguyen20999 May 13, 2024
1e24f1a
Merge branch 'develop' into feature/#551-Exposing-metric-control
namnguyen20999 May 13, 2024
04a0cb6
Merge branch 'develop' into feature/#551-Exposing-metric-control
namnguyen20999 May 13, 2024
ede60cf
update min & max default type from int to string. update using height…
namnguyen20999 May 13, 2024
1e0a2c1
change the property of min & max back to the number
namnguyen20999 May 13, 2024
2417590
trigger workflow
namnguyen20999 May 14, 2024
5d0b519
adding custom sprintf-js format for metric
namnguyen20999 May 16, 2024
d789639
correcting the suffix for delta
namnguyen20999 May 16, 2024
ba99a52
remove format & format_delta
namnguyen20999 May 17, 2024
d2c72ea
merge develop into US551
namnguyen20999 May 17, 2024
83c0692
merge develop intoUS551
namnguyen20999 May 17, 2024
f68778a
Merge branch 'develop' into feature/#551-Exposing-metric-control
namnguyen20999 May 18, 2024
9122b12
remove main.py
namnguyen20999 May 18, 2024
5864234
fix linter
namnguyen20999 May 18, 2024
2dc5d46
Trigger Build
namnguyen20999 May 18, 2024
1d4fabd
Merge branch 'develop' into feature/#551-Exposing-metric-control
namnguyen20999 May 20, 2024
b4491d6
adding logic to hide number + resolve review comments
namnguyen20999 May 21, 2024
ccc9443
adding default value for showValue
namnguyen20999 May 21, 2024
ed21313
Merge branch 'develop' into feature/#551-Exposing-metric-control
namnguyen20999 May 21, 2024
47c5061
change sprintf-js back to 1.1.2
namnguyen20999 May 21, 2024
dc06dca
Merge branch 'feature/#551-Exposing-metric-control' of github.com:Ava…
namnguyen20999 May 21, 2024
2a512fc
adding deps in data
namnguyen20999 May 21, 2024
689566f
Merge branch 'develop' into feature/#551-Exposing-metric-control
namnguyen20999 May 21, 2024
1bcf034
change style & layout back to string
namnguyen20999 May 22, 2024
af4dd42
Merge branch 'feature/#551-Exposing-metric-control' of github.com:Ava…
namnguyen20999 May 22, 2024
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
2 changes: 1 addition & 1 deletion frontend/taipy-gui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion frontend/taipy-gui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"react-window": "^1.8.6",
"react-window-infinite-loader": "^1.0.7",
"socket.io-client": "^4.3.2",
"sprintf-js": "^1.1.2",
"sprintf-js": "^1.1.3",
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
"uuid": "^9.0.0"
},
"overrides": {
Expand Down
31 changes: 31 additions & 0 deletions frontend/taipy-gui/src/components/Taipy/Metric.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2021-2024 Avaiga Private Limited
*
* 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 React from "react";
import {render} from "@testing-library/react";
import "@testing-library/jest-dom";

import Metric from "./Metric";

describe("Metric Component", () => {
it("renders", async () => {
const { getByTestId } = render(<Metric testId={'test-id'}/>);
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
const elt = getByTestId("test-id");
expect(elt.tagName).toBe("DIV");
})
it("displays the right info for class", async () => {
const { getByTestId } = render(<Metric testId={'test-id'} className={'taipy-gauge'}/>);
const elt = getByTestId('test-id');
expect(elt).toHaveClass('taipy-gauge');
})
});
113 changes: 113 additions & 0 deletions frontend/taipy-gui/src/components/Taipy/Metric.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright 2021-2024 Avaiga Private Limited
*
* 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 React, {CSSProperties, lazy, Suspense, useMemo} from 'react';
import {Data} from "plotly.js";
import {useClassNames, useDynamicJsonProperty, useDynamicProperty} from "../../utils/hooks";
import {TaipyBaseProps, TaipyHoverProps} from "./utils";
import Box from "@mui/material/Box";
import Skeleton from "@mui/material/Skeleton";

const Plot = lazy(() => import("react-plotly.js"));

interface MetricProps extends TaipyBaseProps, TaipyHoverProps {
type?: string
min?: number
max?: number
value?: number
defaultValue?: number
delta?: number
defaultDelta?: number
threshold?: number
defaultThreshold?: number
testId?: string
defaultLayout?: string;
layout?: string;
defaultStyle?: string;
style?: string;
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
width?: string | number;
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
height?: string | number;
}

const emptyLayout = {} as Record<string, Record<string, unknown>>;
const defaultStyle = {position: "relative", display: "inline-block"};

const Metric = (props: MetricProps) => {
const {
width = "100%",
height
} = props;
const value = useDynamicProperty(props.value, props.defaultValue, 0)
const threshold = useDynamicProperty(props.threshold, props.defaultThreshold, undefined)
const delta = useDynamicProperty(props.delta, props.defaultDelta, undefined)
const className = useClassNames(props.libClassName, props.dynamicClassName, props.className);
const baseLayout = useDynamicJsonProperty(props.layout, props.defaultLayout || "", emptyLayout);
const baseStyle = useDynamicJsonProperty(props.style, props.defaultStyle || "", defaultStyle);

const data = useMemo(() => ([
{
domain: {x: [0, 1], y: [0, 1]},
FredLL-Avaiga marked this conversation as resolved.
Show resolved Hide resolved
value: value,
type: "indicator",
mode: (() => {
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
let mode = "gauge+number";
if (delta !== undefined) mode += "+delta";
return mode;
})(),
delta: {
reference: typeof value === 'number' && typeof delta === 'number' ? value - delta : undefined,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For better readability, I would change that to
(value === undefined || delta === undefined) ? undefined : (value - delta)
that is more efficient and more readable (value and delta ARE numbers - except when they're not).

},
gauge: {
axis: {range: [
typeof props.min === 'number' ? props.min : 0,
typeof props.max === 'number' ? props.max : 100
]},
shape: props.type === "linear" ? "bullet" : "angular",
threshold: {
line: {color: "red", width: 4},
thickness: 0.75,
value: threshold
}
},
}
]), [
value,
delta,
threshold,
props.min,
props.max,
props.type,
]);

const style = useMemo(
() =>
height === undefined
? ({...baseStyle, width: width} as CSSProperties)
: ({...baseStyle, width: width, height: height} as CSSProperties),
[baseStyle, height, width]
);

return (
<Box data-testid={props.testId} className={className}>
<Suspense fallback={<Skeleton key="skeleton"/>}>
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
<Plot
data={data as Data[]}
layout={baseLayout}
style={style}
/>
</Suspense>
</Box>
);
}

export default Metric;
2 changes: 2 additions & 0 deletions frontend/taipy-gui/src/components/Taipy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import StatusList from "./StatusList";
import Table from "./Table";
import Toggle from "./Toggle";
import TreeView from "./TreeView";
import Metric from "./Metric";
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved

const registeredComponents: Record<string, ComponentType> = {};

Expand All @@ -62,6 +63,7 @@ export const getRegisteredComponents = () => {
Login: Login,
Layout: Layout,
MenuCtl: MenuCtl,
Metric: Metric,
NavBar: NavBar,
PageContent: PageContent,
Pane: Pane,
Expand Down
2 changes: 2 additions & 0 deletions frontend/taipy-gui/src/extensions/exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import Login from "../components/Taipy/Login";
import Router from "../components/Router";
import Table from "../components/Taipy/Table";
import TableFilter, { FilterDesc } from "../components/Taipy/TableFilter";
import Metric from "../components/Taipy/Metric";
import { useLovListMemo, LoV, LoVElt } from "../components/Taipy/lovUtils";
import { LovItem } from "../utils/lov";
import { getUpdateVar } from "../components/Taipy/utils";
Expand Down Expand Up @@ -45,6 +46,7 @@ export {
Router,
Table,
TableFilter,
Metric,
TaipyContext as Context,
createRequestDataUpdateAction,
createRequestUpdateAction,
Expand Down
24 changes: 24 additions & 0 deletions taipy/gui/_renderers/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class _Factory:
"text": "value",
"toggle": "value",
"tree": "value",
"metric": "value"
}

_TEXT_ATTRIBUTES = ["format", "id", "hover_text", "raw"]
Expand Down Expand Up @@ -349,6 +350,29 @@ class _Factory:
]
)
._set_propagate(),
"metric": lambda gui, control_type, attrs: _Builder(
gui=gui,
control_type=control_type,
element_name="Metric",
attributes=attrs,
)
.set_value_and_default(with_default=False, var_type=PropertyType.dynamic_number, native_type=True)
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
.set_attributes(
[
("id",),
("active", PropertyType.dynamic_boolean, True),
("layout", PropertyType.dynamic_dict),
("style", PropertyType.dynamic_dict),
("hover_text", PropertyType.dynamic_string),
("type", PropertyType.string, "circular"),
("min", PropertyType.number, 0),
("max", PropertyType.number, 100),
("delta", PropertyType.dynamic_number),
("threshold", PropertyType.dynamic_number),
("width", PropertyType.string_or_number),
("height", PropertyType.string_or_number),
]
),
"navbar": lambda gui, control_type, attrs: _Builder(
gui=gui, control_type=control_type, element_name="NavBar", attributes=attrs, default_value=None
).set_attributes(
Expand Down
Loading
Loading