Skip to content

Commit

Permalink
Created a new visual element - progress bar (#1303)
Browse files Browse the repository at this point in the history
* created progress bar element
* updated ProgressBar.tsx and factory.py
* removed unnecessary functions
* updated the value property in progress bar
* bug: fixed type error in val
* removed WithValue functions
* removed unwanted params
* renamed ProgressBar to Progress
* init: progress element tests
* updated progress element tests
* all progress tests passed
* improved quality and style
* added python tests and fixed typo in factory.py
* removed type Helpers
* added progress in viselements.json
* moved progress to sorted part
* added default_value label to progress
* improved pytests
* copied viselements.json from the develop branch
* added property to show or hide the progress component
* changed default value of render to true
* added progress to viselements.json and fixed errors in test_progress.py
* added render property to viselements.json
* changed bool to dynamic(bool) in render
* minor changes in pytests
* changed default value of linear to False in viselements.json
* Added default_value entry in element doc + reorder elements
---------

Co-authored-by: Fabien Lelaquais <[email protected]>
  • Loading branch information
yaten2302 and FabienLelaquais authored Jun 17, 2024
1 parent 449a6a1 commit 8a8fb36
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 0 deletions.
46 changes: 46 additions & 0 deletions frontend/taipy-gui/src/components/Taipy/Progress.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 Progress from "./Progress";

describe("Progress component", () => {
it("renders circular progress without value (indeterminate)", () => {
const { getByRole } = render(<Progress />);
const elt = getByRole("progressbar");
expect(elt).toHaveClass("MuiCircularProgress-root");
});
it("renders circular progress with value (determinate)", () => {
const { getByRole, getByText } = render(<Progress showValue value={50} />);
const elt = getByRole("progressbar");
const valueText = getByText("50%");
expect(elt).toHaveClass("MuiCircularProgress-root");
expect(valueText).toBeInTheDocument();
});
it("renders linear progress without value (inderminate)", () => {
const { getByRole } = render(<Progress linear />);
const elt = getByRole("progressbar");
expect(elt).toHaveClass("MuiLinearProgress-root");
});
it("renders linear progress with value (determinate)", () => {
const { getByRole, getByText } = render(<Progress linear showValue value={50} />);
const elt = getByRole("progressbar");
const valueText = getByText("50%");
expect(elt).toHaveClass("MuiLinearProgress-root");
expect(valueText).toBeInTheDocument();
});
});
80 changes: 80 additions & 0 deletions frontend/taipy-gui/src/components/Taipy/Progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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 Box from "@mui/material/Box";
import CircularProgress from "@mui/material/CircularProgress";
import LinearProgress from "@mui/material/LinearProgress";
import Typography from "@mui/material/Typography";

import { useDynamicProperty } from "../../utils/hooks";

interface ProgressBarProps {
linear?: boolean; //by default - false
showValue?: boolean; //by default - false
value?: number; //progress value
defaultValue?: number; //default progress value
render?: boolean;
defaultRender?: boolean;
}

const Progress = (props: ProgressBarProps) => {
const { linear, showValue } = props;

const value = useDynamicProperty(props.value, props.defaultValue, undefined);
const render = useDynamicProperty(props.render, props.defaultRender, true);

if (!render) {
return null;
}

return showValue && value !== undefined ? (
linear ? (
<Box sx={{ display: "flex", alignItems: "center" }}>
<Box sx={{ width: "100%", mr: 1 }}>
<LinearProgress variant="determinate" value={value} />
</Box>
<Box sx={{ minWidth: 35 }}>
<Typography variant="body2" color="text.secondary">{`${Math.round(value)}%`}</Typography>
</Box>
</Box>
) : (
<Box sx={{ position: "relative", display: "inline-flex" }}>
<CircularProgress variant="determinate" value={value} />
<Box
sx={{
top: 0,
left: 0,
bottom: 0,
right: 0,
position: "absolute",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<Typography variant="caption" component="div" color="text.secondary">
{`${Math.round(value)}%`}
</Typography>
</Box>
</Box>
)
) : linear ? (
<LinearProgress variant={value === undefined ? "indeterminate" : "determinate"} value={value} />
) : (
<CircularProgress variant={value === undefined ? "indeterminate" : "determinate"} value={value} />
);
};

export default Progress;
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 @@ -34,6 +34,7 @@ import NavBar from "./NavBar";
import PageContent from "../pages/PageContent";
import Pane from "./Pane";
import Part from "./Part";
import Progress from "./Progress";
import Selector from "./Selector";
import Slider from "./Slider";
import StatusList from "./StatusList";
Expand Down Expand Up @@ -74,6 +75,7 @@ export const getRegisteredComponents = () => {
Table: Table,
Toggle: Toggle,
TreeView: TreeView,
Progress: Progress,
}).forEach(([name, comp]) => (registeredComponents[name] = comp as ComponentType));
if (window.taipyConfig?.extensions) {
Object.entries(window.taipyConfig.extensions).forEach(([libName, elts]) => {
Expand Down
16 changes: 16 additions & 0 deletions taipy/gui/_renderers/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class _Factory:
"number": "value",
"pane": "open",
"part": "class_name",
"progress": "value",
"selector": "value",
"slider": "value",
"status": "value",
Expand Down Expand Up @@ -600,6 +601,21 @@ class _Factory:
]
)
._set_propagate(),
"progress": lambda gui, control_type, attrs: _Builder(
gui=gui,
control_type=control_type,
element_name="Progress",
attributes=attrs,
)
.set_value_and_default(var_type=PropertyType.dynamic_number)
.set_attributes(
[
("linear", PropertyType.boolean, False),
("show_value", PropertyType.boolean, False),
("render", PropertyType.dynamic_boolean, True)
]
)
._set_propagate(),
}

# TODO: process \" in property value
Expand Down
31 changes: 31 additions & 0 deletions taipy/gui/viselements.json
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,37 @@
]
}
],
[
"progress",
{
"properties": [
{
"name": "value",
"type": "dynamic(int)",
"doc": "If set, then the value represents the progress percentage that is shown.TODO - if unset?",
"default_property": "true"
},
{
"name": "linear",
"type": "bool",
"default_value": "False",
"doc": "If set to True, the control displays a linear progress indicator instead of a circular one."
},
{
"name": "show_value",
"type": "bool",
"default_value": "False",
"doc": "If set to True, the progress value is shown."
},
{
"name": "render",
"type": "dynamic(bool)",
"doc": "If False, this progress indicator is hidden from the page.",
"default_property": "true"
}
]
}
],
[
"indicator",
{
Expand Down
20 changes: 20 additions & 0 deletions tests/gui/builder/control/test_progress.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 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 taipy.gui.builder as tgb
from taipy.gui import Gui


def test_progress_builder(gui: Gui, helpers):
with tgb.Page(frame=None) as page:
tgb.progress(linear="true", show_value="true", value={50}) # type: ignore[attr-defined]
expected_list = ["<Progress", 'linear={true}', 'showValue={true}', 'value="{50}"']
helpers.test_control_builder(gui, page, expected_list)
60 changes: 60 additions & 0 deletions tests/gui/control/test_progress.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# 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.

from taipy.gui import Gui


def test_circular_progress_indeterminate_md(gui: Gui, helpers):
md_string = "<|progress|>"
expected_list = ["<Progress"]
helpers.test_control_md(gui, md_string, expected_list)


def test_circular_progress_determinate_md(gui: Gui, helpers):
md_string = "<|progress|value=50|show_value|>"
expected_list = ["<Progress", 'value="50"']
helpers.test_control_md(gui, md_string, expected_list)


def test_linear_progress_indeterminate_md(gui: Gui, helpers):
md_string = "<|progress|linear|>"
expected_list = ["<Progress", "linear={true}"]
helpers.test_control_md(gui, md_string, expected_list)


def test_linear_progress_determinate_md(gui: Gui, helpers):
md_string = "<|progress|value=50|show_value|linear|>"
expected_list = ["<Progress", 'value="50"', "linear={true}"]
helpers.test_control_md(gui, md_string, expected_list)


def test_circular_progress_indeterminate_html(gui: Gui, helpers):
html_string = "<taipy:progress/>"
expected_list = ["<Progress"]
helpers.test_control_html(gui, html_string, expected_list)


def test_circular_progress_determinate_html(gui: Gui, helpers):
html_string = '<taipy:progress show_value value="50"/>'
expected_list = ["<Progress", 'value="50"']
helpers.test_control_html(gui, html_string, expected_list)


def test_linear_progress_indeterminate_html(gui: Gui, helpers):
html_string = "<taipy:progress linear/>"
expected_list = ["<Progress", 'linear={true}']
helpers.test_control_html(gui, html_string, expected_list)


def test_linear_progress_determinate_html(gui: Gui, helpers):
html_string = '<taipy:progress linear show_value value="50"/>'
expected_list = ["<Progress", "linear={true}", 'value="50"']
helpers.test_control_html(gui, html_string, expected_list)

0 comments on commit 8a8fb36

Please sign in to comment.