-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor: move search index * UI: add MVP for job details view * UI: Set title to name of job and move status * fix: adapt to actual API * UX: Add run button dropdown * UI: remove settings button * bug: fix getting user from API and pid_value encoding * UI: Fix details page and user display * UI: add pop up showing timestamp * UI: add description * refactor: move classes into template * UI: move active status and remove schedule button * UX: add interactive run button to details page * refactor: move status formatter to own component * api: change RunStatusEnum states * JS: add run button * JS: Add stop button * UX: add error message for actions * refactor: turn JobRunsHeader into a component * refactor: move JS files * UX: have stop button alter status state * UI: Refactor RunButton into component Plus changes requested by manuel * UI: have run button update jobs list status * JS: use cancellable promises
- Loading branch information
1 parent
6264e5c
commit 34f9c02
Showing
19 changed files
with
728 additions
and
231 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobRuns.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// This file is part of Invenio | ||
// Copyright (C) 2024 CERN. | ||
// | ||
// 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 { | ||
NotificationController, | ||
initDefaultSearchComponents, | ||
} from "@js/invenio_administration"; | ||
import { createSearchAppInit } from "@js/invenio_search_ui"; | ||
import React from "react"; | ||
import ReactDOM from "react-dom"; | ||
import { JobRunsHeaderComponent } from "./JobRunsHeader"; | ||
import { JobSearchLayout } from "./JobSearchLayout"; | ||
import { SearchResultItemLayout } from "./RunsSearchResultItemLayout"; | ||
|
||
const domContainer = document.getElementById("invenio-search-config"); | ||
|
||
const defaultComponents = initDefaultSearchComponents(domContainer); | ||
|
||
const overridenComponents = { | ||
...defaultComponents, | ||
"InvenioAdministration.SearchResultItem.layout": SearchResultItemLayout, | ||
"SearchApp.layout": JobSearchLayout, | ||
}; | ||
|
||
createSearchAppInit( | ||
overridenComponents, | ||
true, | ||
"invenio-search-config", | ||
false, | ||
NotificationController | ||
); | ||
|
||
const pidValue = domContainer.dataset.pidValue; | ||
const header = document.getElementById("header"); | ||
|
||
header && ReactDOM.render(<JobRunsHeaderComponent jobId={pidValue} />, header); |
83 changes: 83 additions & 0 deletions
83
invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobRunsHeader.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
// This file is part of Invenio | ||
// Copyright (C) 2024 CERN. | ||
// | ||
// 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 { 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"; | ||
import { withCancel } from "react-invenio-forms"; | ||
|
||
export class JobRunsHeaderComponent extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
title: i18next.t("Job Details"), | ||
description: "", | ||
config: {}, | ||
loading: true, | ||
}; | ||
} | ||
|
||
componentDidMount() { | ||
const { jobId } = this.props; | ||
withCancel( | ||
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, | ||
}); | ||
}) | ||
); | ||
} | ||
|
||
static contextType = NotificationContext; | ||
|
||
onError = (e) => { | ||
const { addNotification } = this.context; | ||
addNotification({ | ||
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; | ||
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"> | ||
{loading ? null : ( | ||
<RunButton jobId={jobId} config={config} onError={this.onError} /> | ||
)} | ||
</div> | ||
</> | ||
); | ||
} | ||
} | ||
|
||
JobRunsHeaderComponent.propTypes = { | ||
jobId: PropTypes.string.isRequired, | ||
}; |
File renamed without changes.
139 changes: 139 additions & 0 deletions
139
invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobSearchResultItemLayout.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
* This file is part of Invenio. | ||
* Copyright (C) 2024 CERN. | ||
* | ||
* Invenio 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 { 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 { Popup, Table } from "semantic-ui-react"; | ||
import { RunButton } from "./RunButton"; | ||
import { StatusFormatter } from "./StatusFormatter"; | ||
|
||
class SearchResultItemComponent extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
lastRunStatus: props.result?.last_run?.status, | ||
lastRunCreatedTime: props.result?.last_run?.created, | ||
}; | ||
} | ||
static contextType = NotificationContext; | ||
|
||
onError = (e) => { | ||
const { addNotification } = this.context; | ||
addNotification({ | ||
title: i18next.t("Status ") + e.status, | ||
content: `${e.message}`, | ||
type: "error", | ||
}); | ||
console.error(e); | ||
}; | ||
|
||
render() { | ||
const { result } = this.props; | ||
const { lastRunStatus, lastRunCreatedTime } = this.state; | ||
|
||
return ( | ||
<Table.Row> | ||
<Table.Cell | ||
key={`job-name-${result.title}`} | ||
data-label={i18next.t("Name")} | ||
collapsing | ||
className="word-break-all" | ||
> | ||
<a href={`/administration/jobs/${result.id}`}>{result.title}</a> | ||
| ||
<BoolFormatter | ||
tooltip={i18next.t("Inactive")} | ||
icon="ban" | ||
color="grey" | ||
value={result.active === false} | ||
/> | ||
</Table.Cell> | ||
<Table.Cell | ||
key={`job-last-run-${result.created}`} | ||
data-label={i18next.t("Last run")} | ||
collapsing | ||
className="" | ||
> | ||
{lastRunStatus ? ( | ||
<> | ||
<StatusFormatter status={lastRunStatus} /> | ||
<Popup | ||
content={lastRunCreatedTime} | ||
trigger={ | ||
<span> | ||
{toRelativeTime(lastRunCreatedTime, i18next.language)} | ||
</span> | ||
} | ||
/> | ||
</> | ||
) : ( | ||
"−" | ||
)} | ||
</Table.Cell> | ||
{result?.last_run?.started_by ? ( | ||
<Table.Cell | ||
key={`job-user-${result.last_run.started_by.id}`} | ||
data-label={i18next.t("Started by")} | ||
collapsing | ||
className="word-break-all" | ||
> | ||
<UserListItemCompact | ||
user={result.last_run.started_by} | ||
id={result.last_run.started_by.id} | ||
/> | ||
</Table.Cell> | ||
) : ( | ||
<Table.Cell | ||
key="job-user" | ||
data-label={i18next.t("Started by")} | ||
collapsing | ||
className="word-break-all" | ||
> | ||
System | ||
</Table.Cell> | ||
)} | ||
<Table.Cell | ||
collapsing | ||
key={`job-next-run${result.next_run}`} | ||
data-label={i18next.t("Next run")} | ||
className="word-break-all" | ||
> | ||
{result.active === false | ||
? "Inactive" | ||
: toRelativeTime(result.next_run, i18next.language) ?? "−"} | ||
</Table.Cell> | ||
<Table.Cell collapsing> | ||
<RunButton | ||
jobId={result.id} | ||
config={result.default_args ?? {}} | ||
onError={this.onError} | ||
setRun={(status, created) => { | ||
this.setState({ | ||
lastRunStatus: status, | ||
lastRunCreatedTime: created, | ||
}); | ||
}} | ||
/> | ||
</Table.Cell> | ||
</Table.Row> | ||
); | ||
} | ||
} | ||
|
||
SearchResultItemComponent.propTypes = { | ||
result: PropTypes.object.isRequired, | ||
}; | ||
|
||
SearchResultItemComponent.defaultProps = {}; | ||
|
||
export const SearchResultItemLayout = withState(SearchResultItemComponent); |
Oops, something went wrong.