From 9b78b9dfc013a72ae5cfebe6909cde53f329e866 Mon Sep 17 00:00:00 2001 From: Karolina Przerwa Date: Mon, 26 Aug 2024 15:14:02 +0200 Subject: [PATCH] alembic: change jobs table names for consistency * tests: adapt tests to new implementation of jobs registry * chore: fix formatting --- invenio_jobs/administration/jobs.py | 2 + invenio_jobs/administration/runs.py | 9 - ...6f6990b8_update_jobs_module_table_names.py | 59 +++++++ invenio_jobs/api.py | 17 ++ .../invenio_jobs/administration/JobActions.js | 6 + .../administration/JobRunsHeader.js | 6 - .../JobSearchResultItemLayout.js | 1 - .../administration/RunActionForm.js | 8 +- .../invenio_jobs/administration/RunButton.js | 145 --------------- .../RunsSearchResultItemLayout.js | 1 - .../administration/ScheduleJobModal.js | 6 + .../administration/StatusFormatter.js | 6 + .../js/invenio_jobs/administration/index.js | 1 - invenio_jobs/ext.py | 1 - invenio_jobs/jobs.py | 10 +- invenio_jobs/models.py | 47 ++--- invenio_jobs/registry.py | 11 +- invenio_jobs/resources/config.py | 1 - invenio_jobs/resources/resources.py | 7 +- invenio_jobs/services/config.py | 4 +- invenio_jobs/services/results.py | 7 +- invenio_jobs/services/schema.py | 12 +- invenio_jobs/services/services.py | 70 ++++---- invenio_jobs/services/ui_schema.py | 1 - invenio_jobs/tasks.py | 2 +- invenio_jobs/webpack.py | 2 +- tests/conftest.py | 29 +-- tests/mock_module/__init__.py | 8 + tests/mock_module/jobs.py | 21 +++ tests/resources/test_resources.py | 166 +++++++++--------- tests/test_alembic.py | 6 +- 31 files changed, 323 insertions(+), 349 deletions(-) create mode 100644 invenio_jobs/alembic/1f896f6990b8_update_jobs_module_table_names.py create mode 100644 invenio_jobs/api.py delete mode 100644 invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunButton.js create mode 100644 tests/mock_module/__init__.py create mode 100644 tests/mock_module/jobs.py diff --git a/invenio_jobs/administration/jobs.py b/invenio_jobs/administration/jobs.py index 1ffa1e2..0e391e3 100644 --- a/invenio_jobs/administration/jobs.py +++ b/invenio_jobs/administration/jobs.py @@ -108,6 +108,7 @@ def get_api_endpoint(self, pid_value=None): return f"/api/jobs/{pid_value}/runs" def get_details_api_endpoint(self): + """Compute api endpoint link for job details view.""" api_url_prefix = current_app.config["SITE_API_URL"] slash_tpl = "/" if not self.api_endpoint.startswith("/") else "" @@ -117,6 +118,7 @@ def get_details_api_endpoint(self): return f"{slash_tpl}{self.api_endpoint}" def get_context(self, **kwargs): + """Compute admin view context.""" ctx = super().get_context(**kwargs) ctx["request_headers"] = self.request_headers ctx["ui_config"] = self.item_field_list diff --git a/invenio_jobs/administration/runs.py b/invenio_jobs/administration/runs.py index 10499fd..4379252 100644 --- a/invenio_jobs/administration/runs.py +++ b/invenio_jobs/administration/runs.py @@ -28,12 +28,3 @@ class RunsListView(AdminResourceListView): display_edit = False display_create = False actions = None - - # item_field_list = { - # "job": {"text": _("Jobs"), "order": 1, "width": 3}, - # "active": {"text": _("Status"), "order": 2, "width": 2}, - # "last_run_start_time": {"text": _("Last run"), "order": 3, "width": 3}, - # "user": {"text": _("Started by"), "order": 4, "width": 3}, - # "next_run": {"text": _("Next run"), "order": 5, "width": 3}, - # } - diff --git a/invenio_jobs/alembic/1f896f6990b8_update_jobs_module_table_names.py b/invenio_jobs/alembic/1f896f6990b8_update_jobs_module_table_names.py new file mode 100644 index 0000000..3f3d04e --- /dev/null +++ b/invenio_jobs/alembic/1f896f6990b8_update_jobs_module_table_names.py @@ -0,0 +1,59 @@ +# +# This file is part of Invenio. +# Copyright (C) 2016-2018 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. + +"""Update jobs module table names.""" + +import sqlalchemy as sa +import sqlalchemy_utils +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = "1f896f6990b8" +down_revision = "356496a01197" +branch_labels = () +depends_on = None + + +def upgrade(): + """Upgrade database.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint("fk_run_job_id_job", "run", type_="foreignkey") + op.rename_table("job", "jobs_job") + op.rename_table("run", "jobs_run") + + op.create_foreign_key( + "fk_jobs_run_job_id_jobs_job", "jobs_run", "jobs_job", ["job_id"], ["id"] + ) + op.drop_column("jobs_job", "default_args") + + # ### end Alembic commands ### + + +def downgrade(): + """Downgrade database.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint("fk_jobs_run_job_id_jobs_job", "jobs_run", type_="foreignkey") + + op.rename_table("jobs_job", "job") + op.rename_table("jobs_run", "run") + op.create_foreign_key("fk_run_job_id_job", "run", "job", ["job_id"], ["id"]) + op.add_column( + "job", + sa.Column( + "default_args", + sa.JSON() + .with_variant(sqlalchemy_utils.types.json.JSONType(), "mysql") + .with_variant( + postgresql.JSONB(none_as_null=True, astext_type=sa.Text()), "postgresql" + ) + .with_variant(sqlalchemy_utils.types.json.JSONType(), "sqlite"), + nullable=True, + ), + ) + + # ### end Alembic commands ### diff --git a/invenio_jobs/api.py b/invenio_jobs/api.py new file mode 100644 index 0000000..0df85f4 --- /dev/null +++ b/invenio_jobs/api.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2024 CERN. +# +# Invenio-Jobs is free software; you can redistribute it and/or modify it +# under the terms of the MIT License; see LICENSE file for more details. + +"""Record class mock.""" + + +class AttrDict(dict): + """Mock record class.""" + + def __init__(self, *args, **kwargs): + """Constructor.""" + super(AttrDict, self).__init__(*args, **kwargs) + self.__dict__ = self diff --git a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobActions.js b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobActions.js index 8810c7f..5516900 100644 --- a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobActions.js +++ b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobActions.js @@ -1,3 +1,9 @@ +// This file is part of InvenioRDM +// Copyright (C) 2024 CERN +// +// Invenio RDM Records 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 React, { Component } from "react"; import PropTypes from "prop-types"; import { Button, Modal, Icon } from "semantic-ui-react"; diff --git a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobRunsHeader.js b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobRunsHeader.js index df68802..3918836 100644 --- a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobRunsHeader.js +++ b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobRunsHeader.js @@ -14,10 +14,8 @@ import { i18next } from "@translations/invenio_app_rdm/i18next"; import _isEmpty from "lodash/isEmpty"; import PropTypes from "prop-types"; import React, { Component } from "react"; -import { http } from "react-invenio-forms"; import { Divider, Button, Grid, Header } from "semantic-ui-react"; import { AdminUIRoutes } from "@js/invenio_administration"; -import { withCancel } from "react-invenio-forms"; export class JobRunsHeader extends Component { constructor(props) { @@ -45,17 +43,13 @@ export class JobRunsHeader extends Component { render() { const { - pid, - columns, actions, apiEndpoint, idKeyPath, listUIEndpoint, - resourceSchema, resourceName, displayDelete, displayEdit, - uiSchema, data, error, loading, diff --git a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobSearchResultItemLayout.js b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobSearchResultItemLayout.js index c8c5dcf..f00a6f6 100644 --- a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobSearchResultItemLayout.js +++ b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/JobSearchResultItemLayout.js @@ -14,7 +14,6 @@ import { UserListItemCompact, toRelativeTime } from "react-invenio-forms"; import { withState } from "react-searchkit"; import { Popup, Table, Button } from "semantic-ui-react"; import { Actions } from "@js/invenio_administration"; -import { RunButton } from "./RunButton"; import { StatusFormatter } from "./StatusFormatter"; import { AdminUIRoutes } from "@js/invenio_administration/src/routes"; diff --git a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunActionForm.js b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunActionForm.js index a41f8e1..4c546f8 100644 --- a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunActionForm.js +++ b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunActionForm.js @@ -1,7 +1,13 @@ +// This file is part of InvenioRDM +// Copyright (C) 2024 CERN +// +// Invenio RDM Records 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 React, { Component } from "react"; import PropTypes from "prop-types"; import { ActionFormLayout } from "@js/invenio_administration"; -import ReactJson from "react-json-view"; +import ReactJson from "@microlink/react-json-view"; import { Accordion, Icon, Modal } from "semantic-ui-react"; export class RunActionForm extends Component { diff --git a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunButton.js b/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunButton.js deleted file mode 100644 index 3328848..0000000 --- a/invenio_jobs/assets/semantic-ui/js/invenio_jobs/administration/RunButton.js +++ /dev/null @@ -1,145 +0,0 @@ -// This file is part of InvenioRDM -// Copyright (C) 2024 CERN -// -// Invenio RDM Records 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 { i18next } from "@translations/invenio_app_rdm/i18next"; -import PropTypes from "prop-types"; -import React, { Component } from "react"; -import { http, withCancel } from "react-invenio-forms"; -import { - Button, - Dropdown, - DropdownMenu, - Form, - FormField, - FormInput, - TextArea, -} from "semantic-ui-react"; - -export class RunButton extends Component { - constructor(props) { - super(props); - - this.state = { - title: "Manual run", - config: JSON.stringify(props.config, null, "\t"), - queue: props.queue || "celery", - loading: false, - }; - } - - componentWillUnmount() { - this.cancellableAction && this.cancellableAction.cancel(); - } - - 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, setRun } = this.props; - const { title, config, queue } = this.state; - - try { - var userConfigJSON = config === "" ? null : JSON.parse(config); - } catch (e) { - onError(e); - } - - const runData = { - title: title, - queue: queue, - }; - - if (userConfigJSON !== null) { - runData.args = userConfigJSON; - } - - try { - this.cancellableAction = await withCancel( - http.post("/api/jobs/" + jobId + "/runs", runData) - ); - } catch (error) { - if (error.response) { - onError(error.response.data); - } else { - onError(error); - } - } - const response = await this.cancellableAction.promise; - setRun(response.data?.status, response.data?.created); - this.setState({ loading: false }); - }; - - render() { - const { title, config, queue, loading } = this.state; - const lines = config.split(/\r?\n/).length; - - return ( - - -
- e.stopPropagation()} - onChange={this.handleTitleChange} - /> - e.stopPropagation()} - onChange={this.handleConfigChange} - /> - -