From 24c842a8dc03577537fb0d43a1ab9aa9ad715d7f Mon Sep 17 00:00:00 2001 From: Arthur Deierlein Date: Wed, 19 Feb 2025 14:25:25 +0100 Subject: [PATCH] fix(frontend): refactor report ability to be async --- frontend/app/abilities/report.js | 62 ++++-- frontend/app/analysis/index/controller.js | 24 +-- frontend/app/analysis/index/template.hbs | 106 ++++----- frontend/app/components/can-edit.hbs | 9 + frontend/app/components/report-row.hbs | 240 +++++++++++---------- frontend/app/components/report-row.js | 9 +- frontend/app/helpers/conditional-action.js | 16 ++ 7 files changed, 261 insertions(+), 205 deletions(-) create mode 100644 frontend/app/components/can-edit.hbs create mode 100644 frontend/app/helpers/conditional-action.js diff --git a/frontend/app/abilities/report.js b/frontend/app/abilities/report.js index f0280c3b5..8312e069d 100644 --- a/frontend/app/abilities/report.js +++ b/frontend/app/abilities/report.js @@ -8,23 +8,49 @@ export default class ReportAbility extends Ability { return this.currentUser.user; } - get canEdit() { - const isEditable = - this.user?.isSuperuser || - (!this.model?.verifiedBy?.get("id") && - (this.model?.user?.get("id") === this.user?.get("id") || - (this.model?.user?.get("supervisors") ?? []) - .map((s) => s.id) - .includes(this.user?.get("id")))); - const isReviewer = - (this.model?.taskAssignees ?? []) - .concat( - this.model?.projectAssignees ?? [], - this.model?.customerAssignees ?? [], - ) - .filter((a) => a?.user) - .map((a) => a.user.get("id")) - .includes(this.user?.get("id")) && !this.model?.verifiedBy?.get("id"); - return isEditable || isReviewer; + get canEditSync() { + if (this.user?.isSuperuser) { + return true; + } + + if (this.model?.verifiedBy?.get("id")) { + return false; + } + + if (this.model?.user?.get("id") === this.user?.get("id")) { + return true; + } + + return false; + } + + async isReviewer() { + return ((await this.model?.taskAssignees) ?? []) + .concat( + (await this.model?.projectAssignees) ?? [], + (await this.model?.customerAssignees) ?? [], + ) + .filter((a) => a?.user) + .map((a) => a.user.get("id")) + .includes(this.user?.get("id")); + } + + async isSupervisee() { + return ((await this.model?.user?.get("supervisors")) ?? []) + .map((s) => s.id) + .includes(this.user?.get("id")); + } + + async canEditAsync() { + if (this.model?.verifiedBy?.get("id")) { + return false; + } + + const isSupervisee = await this.isSupervisee(); + if (isSupervisee) { + return true; + } + + return await this.isReviewer(); } } diff --git a/frontend/app/analysis/index/controller.js b/frontend/app/analysis/index/controller.js index a6a4b4435..da2b2cd1d 100644 --- a/frontend/app/analysis/index/controller.js +++ b/frontend/app/analysis/index/controller.js @@ -122,10 +122,8 @@ export default class AnalysisController extends QPController { return `The export limit is ${this.exportLimit}. Please use filters to reduce the amount of reports.`; } - get canBill() { - return ( - this.currentUser.user.isAccountant || this.currentUser.user.isSuperuser - ); + get isAccountant() { + return this.currentUser.user.isAccountant; } get appliedFilters() { @@ -362,16 +360,14 @@ export default class AnalysisController extends QPController { @action selectRow(report) { - if (this.abilities.can("edit report", report) || this.canBill) { - const selected = this.selectedReportIds; - - if (selected.includes(report.id)) { - this.selectedReportIds = A([ - ...selected.filter((id) => id !== report.id), - ]); - } else { - this.selectedReportIds = A([...selected, report.id]); - } + const selected = this.selectedReportIds; + + if (selected.includes(report.id)) { + this.selectedReportIds = A([ + ...selected.filter((id) => id !== report.id), + ]); + } else { + this.selectedReportIds = A([...selected, report.id]); } } } diff --git a/frontend/app/analysis/index/template.hbs b/frontend/app/analysis/index/template.hbs index 621c60401..56e883eba 100644 --- a/frontend/app/analysis/index/template.hbs +++ b/frontend/app/analysis/index/template.hbs @@ -330,56 +330,64 @@ {{#each reports as |report|}} {{! template-lint-disable}} - - {{report.user.username}} - {{moment-format - report.date - "DD.MM.YYYY" - }} - {{format-duration - report.duration - false - }} - {{report.task.project.customer.name}} - {{report.task.project.name}} - {{report.task.name}} - {{report.comment}} - {{if - report.verifiedBy - report.verifiedBy.username - }} - - - - - + > + {{report.user.username}} + {{moment-format + report.date + "DD.MM.YYYY" + }} + {{format-duration + report.duration + false + }} + {{report.task.project.customer.name}} + {{report.task.project.name}} + {{report.task.name}} + {{report.comment}} + {{if + report.verifiedBy + report.verifiedBy.username + }} + + + + + + {{/each}} {{#if this._canLoadMore}} - + {{#let (changeset @report this.ReportValidations) as |cs|}} + - - - - + + - - + + + + -
- - -
-
- -
-
- {{#if cs.task.project.remainingEffortTracking}} - + + - {{/if}} -
+ +
+ +
+
+ {{#if cs.task.project.remainingEffortTracking}} + + {{/if}} +
-
- - - - - - - + + + + + + + + + + + +
+
- - - - - -
-
- {{#if this.editable}} - - - {{/if}} -
- -{{/let}} \ No newline at end of file + {{#if editable}} + + + {{/if}} + + + {{/let}} + \ No newline at end of file diff --git a/frontend/app/components/report-row.js b/frontend/app/components/report-row.js index c630c4ec6..e90cf2a68 100644 --- a/frontend/app/components/report-row.js +++ b/frontend/app/components/report-row.js @@ -10,12 +10,9 @@ export default class ReportRowComponent extends Component { ReportValidations = ReportValidations; - get editable() { - return this.abilities.can("edit report", this.args.report); - } - - get title() { - return this.editable + @action + title(editable) { + return editable ? "" : `This entry was already verified by ${this.args.report.get( "verifiedBy.fullName", diff --git a/frontend/app/helpers/conditional-action.js b/frontend/app/helpers/conditional-action.js new file mode 100644 index 000000000..3deda63a0 --- /dev/null +++ b/frontend/app/helpers/conditional-action.js @@ -0,0 +1,16 @@ +import { helper } from "@ember/component/helper"; + +/** + * Returns an action if the condition is true; otherwise, returns a no-op function. + * + * @param {[boolean, Function]} args - An array where the first element is a condition (boolean) and the second element is an action (function). + * @returns {Function} The action if the condition is true; otherwise, a no-op function. + */ +export const conditionalAction = ([condition, action]) => { + if (condition) { + return action; + } + return () => {}; +}; + +export default helper(conditionalAction);