Skip to content

Commit

Permalink
UI: Refactor RunButton into component
Browse files Browse the repository at this point in the history
Plus changes requested by manuel
  • Loading branch information
carlinmack committed Jun 3, 2024
1 parent 007d3ed commit 2b8a33b
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,43 @@
// Invenio RDM is free software; you can redistribute it and/or modify it
// under the terms of the MIT License; see LICENSE file for more details.

import { RunButton } from "./RunButton";
import React, { Component } from "react";
import { NotificationContext } from "@js/invenio_administration";
import { i18next } from "@translations/invenio_app_rdm/i18next";
import PropTypes from "prop-types";
import React, { Component } from "react";
import { http } from "react-invenio-forms";
import { RunButton } from "./RunButton";

export class JobRunsHeaderComponent extends Component {
constructor(props) {
super();
super(props);

this.state = {
jobId: props.jobId,
title: "Job Details",
title: i18next.t("Job Details"),
description: "",
config: {},
loading: true,
};
}

componentDidMount() {
const { jobId } = this.state;
const { jobId } = this.props;
http
.get("/api/jobs/" + jobId)
.then((response) => response.data)
.then((data) => {
this.setState({
loading: false,
...(data.title && { title: data.title }),
...(data.description && { description: data.description }),
...(data.default_args && { config: data.default_args }),
});
})
.catch((error) => {
this.onError(error);
this.setState({
loading: false,
});
});
}

Expand All @@ -42,28 +49,26 @@ export class JobRunsHeaderComponent extends Component {
onError = (e) => {
const { addNotification } = this.context;
addNotification({
title: i18next.t("Error"),
content: e.message,
title: i18next.t("Status ") + e.status,
content: `${e.message}`,
type: "error",
});
console.error(e);
};

render() {
const { title, description, config, loading } = this.state;
const { jobId } = this.props;
const { title, description, config } = this.state;
return (
<>
<div className="column six wide">
<h1 className="ui header m-0">{title}</h1>
<p className="ui grey header">{description}</p>
</div>
<div className="column ten wide right aligned">
<RunButton
jobId={jobId}
config={config ?? {}}
onError={this.onError}
/>
{loading ? null : (
<RunButton jobId={jobId} config={config} onError={this.onError} />
)}
</div>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@
* under the terms of the MIT License; see LICENSE file for more details.
*/

import { NotificationContext } from "@js/invenio_administration";
import { BoolFormatter } from "@js/invenio_administration";
import { BoolFormatter, NotificationContext } from "@js/invenio_administration";
import { i18next } from "@translations/invenio_app_rdm/i18next";
import PropTypes from "prop-types";
import React, { Component } from "react";
import { UserListItemCompact, toRelativeTime } from "react-invenio-forms";
import { withState } from "react-searchkit";
import { Button, Icon, Popup, Table } from "semantic-ui-react";
// import { RunButton } from "./RunButton";
import { http } from "react-invenio-forms";
import { Popup, Table } from "semantic-ui-react";
import { RunButton } from "./RunButton";
import { StatusFormatter } from "./StatusFormatter";

class SearchResultItemComponent extends Component {
Expand All @@ -24,8 +22,8 @@ class SearchResultItemComponent extends Component {
onError = (e) => {
const { addNotification } = this.context;
addNotification({
title: i18next.t("Error"),
content: e.message,
title: i18next.t("Status ") + e.status,
content: `${e.message}`,
type: "error",
});
console.error(e);
Expand Down Expand Up @@ -57,23 +55,23 @@ class SearchResultItemComponent extends Component {
collapsing
className=""
>
{result.last_run && (
<StatusFormatter status={result.last_run.status} />
)}
{result.last_run ? (
<Popup
content={result.last_run.created}
trigger={
<span>
{toRelativeTime(result.last_run.created, i18next.language)}
</span>
}
/>
<>
<StatusFormatter status={result.last_run.status} />
<Popup
content={result.last_run.created}
trigger={
<span>
{toRelativeTime(result.last_run.created, i18next.language)}
</span>
}
/>
</>
) : (
"−"
)}
</Table.Cell>
{result.last_run && result.last_run.started_by ? (
{result?.last_run?.started_by ? (
<Table.Cell
key={`job-user-${result.last_run.started_by.id}`}
data-label={i18next.t("Started by")}
Expand Down Expand Up @@ -106,19 +104,11 @@ class SearchResultItemComponent extends Component {
: toRelativeTime(result.next_run, i18next.language) ?? "−"}
</Table.Cell>
<Table.Cell collapsing>
<Button
icon
fluid
basic
labelPosition="left"
onClick={() => {
http.post("/api/jobs/" + result.id + "/runs");
}}
>
<Icon name="play" />
Run now
</Button>
{/* <RunButton jobId={result.id} config={result.default_args ?? {}} onError={this.onError} /> */}
<RunButton
jobId={result.id}
config={result.default_args ?? {}}
onError={this.onError}
/>
</Table.Cell>
</Table.Row>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,70 +6,120 @@

import { i18next } from "@translations/invenio_app_rdm/i18next";
import PropTypes from "prop-types";
import React, { useState } from "react";
import React, { Component } from "react";
import { http } from "react-invenio-forms";
import {
Button,
Dropdown,
DropdownMenu,
Form,
FormField,
FormInput,
TextArea,
} from "semantic-ui-react";

export const RunButton = ({ jobId, config, onError }) => {
const [loading, setLoading] = useState(false);
export class RunButton extends Component {
constructor(props) {
super(props);

this.state = {
title: "Manual run",
config: JSON.stringify(props.config, null, "\t"),
queue: "low",
loading: false,
};
}

handleTitleChange = (e, { name, value }) => this.setState({ title: value });
handleConfigChange = (e, { name, value }) => this.setState({ config: value });
handleQueueChange = (e, { name, value }) => this.setState({ queue: value });

handleSubmit = async () => {
this.setState({ loading: true });

const { jobId, onError } = this.props;
const { title, config, queue } = this.state;

try {
var userConfigJSON = JSON.parse(config);
} catch (e) {
onError(e);
}

const runData = {
title: title,
args: userConfigJSON,
queue: queue,
};

const handleClick = async () => {
setLoading(true);
try {
await http.post("/api/jobs/" + jobId + "/runs");
setLoading(false);
await http.post("/api/jobs/" + jobId + "/runs", runData);
} catch (error) {
setLoading(false);
onError(error);
if (error.response) {
onError(error.response.data);
} else {
onError(error);
}
}
this.setState({ loading: false });
};

return (
<Dropdown
text={i18next.t("Run now")}
icon="play"
floating
labeled
button
className="icon"
basic
closeOnBlur={false}
direction="left"
>
<DropdownMenu>
<Form className="p-10">
{Object.keys(config).map((key) => (
render() {
const { title, config, queue, loading } = this.state;
const lines = config.split(/\r?\n/).length;

return (
<Dropdown
text={i18next.t("Run now")}
icon="play"
floating
labeled
button
className="icon"
basic
direction="left"
>
<DropdownMenu>
<Form className="p-10" onSubmit={this.handleSubmit}>
<FormInput
key={key}
label={key}
defaultValue={config[key]}
name="title"
label="Title"
value={title}
onClick={(e) => e.stopPropagation()}
onChange={this.handleTitleChange}
/>
))}
<Button
type="submit"
content="Run"
onClick={handleClick}
loading={loading}
/>
</Form>
</DropdownMenu>
</Dropdown>
);
};
<FormField
control={TextArea}
label="Arguments"
name="config"
rows={lines}
className="block min-width-max"
value={config}
onClick={(e) => e.stopPropagation()}
onChange={this.handleConfigChange}
/>
<FormField
control={Dropdown}
name="queue"
label="Queue"
selection
value={queue}
options={[
{ key: "celery", text: "celery", value: "celery" },
{ key: "low", text: "low", value: "low" },
]}
onChange={this.handleQueueChange}
/>
<Button type="submit" content="Run" loading={loading} />
</Form>
</DropdownMenu>
</Dropdown>
);
}
}

RunButton.propTypes = {
jobId: PropTypes.string.isRequired,
config: PropTypes.object,
config: PropTypes.object.isRequired,
onError: PropTypes.func.isRequired,
};

RunButton.defaultProps = {
config: {},
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { StopButton } from "./StopButton";

class SearchResultItemComponent extends Component {
constructor(props) {
super();
super(props);

this.state = {
status: props.result.status,
Expand Down Expand Up @@ -59,7 +59,7 @@ class SearchResultItemComponent extends Component {
className=""
>
{result.started_at === null
? "Waiting..."
? `${i18next.t("Waiting")}...`
: toRelativeTime(result.started_at, i18next.language)}
</Table.Cell>
<Table.Cell
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const StatusFormatter = ({ status }) => {
value={status === "CANCELLING"}
/>
<BoolFormatter
tooltip={i18next.t("Cancelling")}
tooltip={i18next.t("Cancelled")}
icon="ban"
color="red"
value={status === "CANCELLED"}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export const StopButton = ({ stopURL, setStatus, onError }) => {
const response = await http.post(stopURL).catch((error) => {
if (error.response) {
onError(error.response.data);
setLoading(false);
} else {
onError(error);
}
Expand Down
Loading

0 comments on commit 2b8a33b

Please sign in to comment.