Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 5 additions & 1 deletion public/locales/de-DE/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,11 @@
"jobs": {
"overriding-job-priority": "Überschriebene Job-Priorität",
"suspend": "Anhalten",
"change-priority": "Job-Priorität ändern"
"change-priority": "Job-Priorität ändern",
"priority": "Priorität",
"include-jobs": "Auf bestehende Jobs anwenden",
"reset-priority": "Priorität zurücksetzen",
"priority-success": "Job-Definition-Priorität aktualisiert."
},
"sort": {
"name": "Name",
Expand Down
6 changes: 5 additions & 1 deletion public/locales/en-US/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,11 @@
"jobs": {
"overriding-job-priority": "Overriding Job Priority",
"suspend": "Suspend",
"change-priority": "Change Overriding Job Priority"
"change-priority": "Change Overriding Job Priority",
"priority": "Priority",
"include-jobs": "Apply to existing jobs",
"reset-priority": "Reset Priority",
"priority-success": "Job definition priority updated."
},
"sort": {
"name": "Name",
Expand Down
25 changes: 19 additions & 6 deletions src/api/resources/job_definition.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
import { GET } from '../helper.jsx'
import { GET, PUT } from "../helper.jsx";

const get_job_definitions = (state, definition_id) =>
GET(`/job-definition?processDefinitionId=${definition_id}`, state, state.api.job_definition.all.by_process_definition)
GET(
`/job-definition?processDefinitionId=${definition_id}`,
state,
state.api.job_definition.all.by_process_definition,
);

const set_priority = (state, id, priority, include_jobs = false) =>
PUT(
`/job-definition/${id}/jobPriority`,
{ priority, includeJobs: priority !== null && include_jobs },
state,
state.api.job_definition.priority,
);

const job_definition = {
all: {
by_process_definition: get_job_definitions
}
}
by_process_definition: get_job_definitions,
},
set_priority,
};

export default job_definition
export default job_definition;
23 changes: 22 additions & 1 deletion src/api/resources/job_definition.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { describe, it, vi, beforeEach } from "vitest";

vi.mock("../helper.jsx", () => ({
GET: vi.fn(),
PUT: vi.fn(),
}));

import { GET } from "../helper.jsx";
import { GET, PUT } from "../helper.jsx";
import { create_mock_state, expect_api_call } from "../../test/helpers.js";
import job_definition from "./job_definition.js";

Expand All @@ -22,4 +23,24 @@ describe("api/resources/job_definition", () => {
signal: state.api.job_definition.all.by_process_definition,
});
});

it("set_priority() PUTs overriding priority to the job definition", () => {
job_definition.set_priority(state, "job-def-1", 42, true);
expect_api_call(PUT, {
url: "/job-definition/job-def-1/jobPriority",
body: { priority: 42, includeJobs: true },
state,
signal: state.api.job_definition.priority,
});
});

it("set_priority() resets priority without propagating to existing jobs", () => {
job_definition.set_priority(state, "job-def-1", null, true);
expect_api_call(PUT, {
url: "/job-definition/job-def-1/jobPriority",
body: { priority: null, includeJobs: false },
state,
signal: state.api.job_definition.priority,
});
});
});
116 changes: 87 additions & 29 deletions src/pages/Processes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ const DefinitionsEmpty = () => {
<a
href="https://docs.operaton.org/manual/latest/installation/full/tomcat/manual/"
target="_blank"
rel="noopener"
rel="noreferrer"
>
{t("processes.empty.how-to")}
</a>
Expand Down Expand Up @@ -928,8 +928,7 @@ const InstanceDetails = () => {
params: { selection_id, definition_id, panel },
query,
} = useRoute(),
history_mode = query.history === "true",
[t] = useTranslation();
history_mode = query.history === "true";

if (selection_id) {
if (
Expand Down Expand Up @@ -1044,19 +1043,17 @@ const InstanceVariables = () => {
? Object.entries(
state.api.process.instance.variables.value.data,
).map(
// eslint-disable-next-line react/jsx-key
([name, { type, value }]) => (
<tr>
<tr key={name}>
<td>{name}</td>
<td>{type}</td>
<td>{value}</td>
</tr>
),
)
: state.api.process.instance.variables.value.data.map(
// eslint-disable-next-line react/jsx-key
({ name, type, value }) => (
<tr>
<tr key={name}>
<td>{name}</td>
<td>{type}</td>
<td>{value}</td>
Expand Down Expand Up @@ -1426,6 +1423,14 @@ const JobDefinitions = () => {
{history_mode && (
<small class="history-na">{t("processes.history-mode-na")}</small>
)}
{state.api.job_definition.priority.value ? (
<RequestState
signal={state.api.job_definition.priority}
on_success={() => (
<p class="success">{t("processes.jobs.priority-success")}</p>
)}
/>
) : null}
<table>
<thead>
<tr>
Expand All @@ -1440,22 +1445,7 @@ const JobDefinitions = () => {
<tbody>
{state.api.job_definition.all.by_process_definition.value?.data?.map(
(definition) => (
<tr key={definition.id}>
<td>
{definition.suspended
? t("common.suspended")
: t("common.active")}
</td>
<td>?</td>
{/*<td>{definition.calledFromActivityIds.map(a => `${a}, `)}</td>*/}
<td>{definition.jobType}</td>
<td>{definition.jobConfiguration}</td>
<td>{definition.overridingJobPriority ?? "-"}</td>
<td>
<button>{t("processes.jobs.suspend")}</button>
<button>{t("processes.jobs.change-priority")}</button>
</td>
</tr>
<JobDefinitionRow key={definition.id} definition={definition} />
),
)}
</tbody>
Expand All @@ -1464,12 +1454,80 @@ const JobDefinitions = () => {
);
};

const BackToListBtn = ({ url, title, className }) => (
<a className={`tabs-back ${className || ""}`} href={url} title={title}>
<Icons.arrow_left />
<Icons.list />
</a>
);
const JobDefinitionRow = ({ definition }) => {
const state = useContext(AppState),
{ definition_id } = useRoute(),
[t] = useTranslation(),
priority = useSignal(definition.overridingJobPriority ?? ""),
include_jobs = useSignal(false),
input_id = `job-priority-${definition.id}`;

const refresh = () =>
engine_rest.job_definition.all.by_process_definition(
state,
definition_id,
),
on_submit = (e) => {
e.preventDefault();
const raw = String(priority.value).trim();
if (raw === "") return;
const parsed = Number(raw);
if (!Number.isFinite(parsed)) return;
void engine_rest.job_definition.set_priority(
state,
definition.id,
parsed,
include_jobs.value,
).then(refresh);
},
on_reset = () =>
engine_rest.job_definition.set_priority(
state,
definition.id,
null,
false,
).then(refresh);

return (
<tr>
<td>
{definition.suspended
? t("common.suspended")
: t("common.active")}
</td>
<td>{definition.activityId ?? "—"}</td>
<td>{definition.jobType}</td>
<td>{definition.jobConfiguration}</td>
<td>{definition.overridingJobPriority ?? "-"}</td>
<td>
<form onSubmit={on_submit}>
<label for={input_id}>{t("processes.jobs.priority")}</label>
<input
id={input_id}
type="number"
value={priority.value}
onInput={(e) => (priority.value = e.currentTarget.value)}
required
/>
<label>
<input
type="checkbox"
checked={include_jobs.value}
onChange={(e) => (include_jobs.value = e.currentTarget.checked)}
/>
{t("processes.jobs.include-jobs")}
</label>
<div class="button-group">
<button type="submit">{t("processes.jobs.change-priority")}</button>
<button type="button" class="secondary" onClick={on_reset}>
{t("processes.jobs.reset-priority")}
</button>
</div>
</form>
</td>
</tr>
);
};

const DefinitionsManage = () => {
const state = useContext(AppState),
Expand Down
64 changes: 64 additions & 0 deletions src/pages/Processes.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,70 @@ describe("ProcessesPage — definition tabs", () => {
expect(getByText("timer")).toBeTruthy();
expect(getByText("R/PT5M")).toBeTruthy();
});

it("sets an overriding job definition priority", async () => {
mockParams = { definition_id: "proc:1", panel: "jobs" };
engine_rest.job_definition.set_priority.mockResolvedValue(undefined);
signal_response(state.api.job_definition.all.by_process_definition, [
{
id: "jd1",
suspended: false,
activityId: "timer_start",
jobType: "timer",
jobConfiguration: "R/PT5M",
overridingJobPriority: null,
},
]);
const { container, getByLabelText, getByText } = renderPage(state);

fireEvent.input(getByLabelText("processes.jobs.priority"), {
target: { value: "42" },
});
fireEvent.click(getByLabelText("processes.jobs.include-jobs"));
fireEvent.submit(container.querySelector("form"));
await Promise.resolve();
await Promise.resolve();

expect(engine_rest.job_definition.set_priority).toHaveBeenCalled();
expect(engine_rest.job_definition.set_priority.mock.lastCall[0]).toBe(
state,
);
expect(engine_rest.job_definition.set_priority.mock.lastCall[1]).toBe(
"jd1",
);
expect(engine_rest.job_definition.set_priority.mock.lastCall[2]).toBe(42);
expect(engine_rest.job_definition.set_priority.mock.lastCall[3]).toBe(true);
expect(getByText("timer_start")).toBeTruthy();
});

it("resets an overriding job definition priority", async () => {
mockParams = { definition_id: "proc:1", panel: "jobs" };
engine_rest.job_definition.set_priority.mockResolvedValue(undefined);
signal_response(state.api.job_definition.all.by_process_definition, [
{
id: "jd1",
suspended: false,
activityId: "timer_start",
jobType: "timer",
jobConfiguration: "R/PT5M",
overridingJobPriority: 10,
},
]);
const { getByText } = renderPage(state);

fireEvent.click(getByText("processes.jobs.reset-priority"));
await Promise.resolve();
await Promise.resolve();

expect(engine_rest.job_definition.set_priority).toHaveBeenCalled();
expect(engine_rest.job_definition.set_priority.mock.lastCall[1]).toBe(
"jd1",
);
expect(engine_rest.job_definition.set_priority.mock.lastCall[2]).toBe(null);
expect(engine_rest.job_definition.set_priority.mock.lastCall[3]).toBe(
false,
);
});
});

describe("ProcessesPage — instance details", () => {
Expand Down
1 change: 1 addition & 0 deletions src/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ const createAppState = () => {
all: {
by_process_definition: signal(null),
},
priority: signal(null),
},
};

Expand Down