@projectcaluma/ember-distribution 11.0.0-beta.29 → 11.0.0-beta.30

Sign up to get free protection for your applications and to get access to all the features.
@@ -30,6 +30,15 @@ export default class DistributionAbility extends Ability {
30
30
  );
31
31
  }
32
32
 
33
+ get canCheckInquiries() {
34
+ return (
35
+ !this.config.ui.readonly &&
36
+ (this.config.permissions.checkInquiries?.() ?? true) &&
37
+ this.distribution.controls.value?.check.edges.filter(hasStatus("READY"))
38
+ .length > 0
39
+ );
40
+ }
41
+
33
42
  get canComplete() {
34
43
  return (
35
44
  !this.config.ui.readonly &&
@@ -13,7 +13,7 @@ export default class InquiryAbility extends Ability {
13
13
  return (
14
14
  !this.config.ui.readonly &&
15
15
  this.model?.task.slug === this.config.inquiry.task &&
16
- this.model?.status === "SUSPENDED" &&
16
+ ["SUSPENDED", "READY"].includes(this.model?.status) &&
17
17
  this.model?.controllingGroups
18
18
  .map(String)
19
19
  .includes(String(this.calumaOptions.currentGroupId))
@@ -31,7 +31,7 @@
31
31
  )
32
32
  }}
33
33
  <div class="uk-alert uk-alert-warning uk-flex uk-flex-middle">
34
- <UkIcon @icon="warning" class="uk-margin-small-right" />
34
+ <UkIcon @icon="warning" class="uk-margin-small-right uk-flex-none" />
35
35
  {{t "caluma.distribution.answer.complete-not-allowed"}}
36
36
  {{t "caluma.distribution.not-allowed-hint"}}
37
37
  </div>
@@ -45,8 +45,21 @@
45
45
  <UkButton
46
46
  @type="submit"
47
47
  @color={{buttonConfig.color}}
48
- @disabled={{or (not isValid) this.completeWorkItem.isRunning}}
49
- @loading={{this.completeWorkItem.isRunning}}
48
+ @disabled={{or
49
+ (not isValid)
50
+ (and
51
+ this.completeWorkItem.isRunning
52
+ (includes
53
+ buttonConfig.workItemId this.completeWorkItem.lastRunning.args
54
+ )
55
+ )
56
+ }}
57
+ @loading={{and
58
+ this.completeWorkItem.isRunning
59
+ (includes
60
+ buttonConfig.workItemId this.completeWorkItem.lastRunning.args
61
+ )
62
+ }}
50
63
  @onClick={{fn
51
64
  (perform this.completeWorkItem)
52
65
  buttonConfig.workItemId
@@ -58,8 +71,18 @@
58
71
  <UkButton
59
72
  @type="button"
60
73
  @color={{buttonConfig.color}}
61
- @disabled={{this.completeWorkItem.isRunning}}
62
- @loading={{this.completeWorkItem.isRunning}}
74
+ @disabled={{and
75
+ this.completeWorkItem.isRunning
76
+ (includes
77
+ buttonConfig.workItemId this.completeWorkItem.lastRunning.args
78
+ )
79
+ }}
80
+ @loading={{and
81
+ this.completeWorkItem.isRunning
82
+ (includes
83
+ buttonConfig.workItemId this.completeWorkItem.lastRunning.args
84
+ )
85
+ }}
63
86
  @onClick={{fn
64
87
  (perform this.completeWorkItem)
65
88
  buttonConfig.workItemId
@@ -23,12 +23,23 @@
23
23
  )
24
24
  }}
25
25
  <div class="uk-alert uk-alert-warning uk-flex uk-flex-middle">
26
- <UkIcon @icon="warning" class="uk-margin-small-right" />
26
+ <UkIcon @icon="warning" class="uk-margin-small-right uk-flex-none" />
27
27
  {{t "caluma.distribution.edit.send-not-allowed"}}
28
28
  {{t "caluma.distribution.not-allowed-hint"}}
29
29
  </div>
30
30
  {{/if}}
31
31
 
32
+ {{#if
33
+ (and (can "edit inquiry" this.inquiry) (eq this.inquiry.status "READY"))
34
+ }}
35
+ <div class="uk-alert uk-alert-warning uk-flex uk-flex-middle">
36
+ <UkIcon @icon="warning" class="uk-margin-small-right uk-flex-none" />
37
+ <p class="uk-margin-remove">
38
+ {{t "caluma.distribution.edit.edit-sent" htmlSafe=true}}
39
+ </p>
40
+ </div>
41
+ {{/if}}
42
+
32
43
  <content.form />
33
44
 
34
45
  {{#if
@@ -0,0 +1,20 @@
1
+ {{#if this.document.isLoading}}
2
+ <div class="uk-text-center"><UkSpinner @ratio={{2}} /></div>
3
+ {{else if this.document.value}}
4
+ <CfFormWrapper
5
+ @document={{this.document.value}}
6
+ @fieldset={{this.fieldset}}
7
+ @onSave={{this.saveField}}
8
+ />
9
+ <DocumentValidity @document={{this.document.value}} as |isValid validate|>
10
+ <UkButton
11
+ @color="primary"
12
+ @label={{t "caluma.distribution.new.create-draft"}}
13
+ @type="submit"
14
+ @loading={{this.submit.isRunning}}
15
+ @disabled={{or (not isValid) this.submit.isRunning}}
16
+ @onClick={{perform this.submit validate}}
17
+ data-test-submit
18
+ />
19
+ </DocumentValidity>
20
+ {{/if}}
@@ -0,0 +1,113 @@
1
+ import { getOwner } from "@ember/application";
2
+ import { action } from "@ember/object";
3
+ import { guidFor } from "@ember/object/internals";
4
+ import { inject as service } from "@ember/service";
5
+ import Component from "@glimmer/component";
6
+ import { queryManager } from "ember-apollo-client";
7
+ import { dropTask } from "ember-concurrency";
8
+ import { trackedFunction } from "ember-resources/util/function";
9
+ import { DateTime } from "luxon";
10
+
11
+ import { decodeId } from "@projectcaluma/ember-core/helpers/decode-id";
12
+ import config from "@projectcaluma/ember-distribution/config";
13
+ import inquiryFormQuery from "@projectcaluma/ember-distribution/gql/queries/inquiry-form.graphql";
14
+ import { parseDocument } from "@projectcaluma/ember-form/lib/parsers";
15
+
16
+ export default class CdInquiryNewFormBulkEditComponent extends Component {
17
+ @service router;
18
+ @service distribution;
19
+
20
+ @queryManager apollo;
21
+
22
+ @config config;
23
+
24
+ answers = {};
25
+
26
+ document = trackedFunction(this, async () => {
27
+ // Fetch the full form (like in cf-content) of the inquiry task
28
+ const response = await this.apollo.query({
29
+ query: inquiryFormQuery,
30
+ variables: {
31
+ inquiryTask: this.config.inquiry.task,
32
+ },
33
+ });
34
+ const form = response.allTasks.edges[0].node.form;
35
+ const answers = { edges: [] };
36
+
37
+ // If we configured a default deadline lead time, we need to calculate the
38
+ // deadline that should be displayed in the form per default and add it to
39
+ // the fake document data
40
+ if (this.config.new.defaultDeadlineLeadTime) {
41
+ const deadline = DateTime.now()
42
+ .plus({ days: this.config.new.defaultDeadlineLeadTime })
43
+ .toISODate();
44
+
45
+ answers.edges.push({
46
+ node: {
47
+ dateValue: deadline,
48
+ question: {
49
+ slug: this.config.inquiry.deadlineQuestion,
50
+ },
51
+ __typename: "DateAnswer",
52
+ },
53
+ });
54
+
55
+ this.answers[this.config.inquiry.deadlineQuestion] = deadline;
56
+ }
57
+
58
+ // Generate a parsed raw data object which can be used for creating a caluma
59
+ // form lib layer document which we need for displaying a form. This is
60
+ // normally done in the cf-content component which fetches the form (like we
61
+ // do above) and the document from the backend and then merges it together
62
+ // with this function. However, since we need a document without existence
63
+ // in the backend, we need to create this object ourselves.
64
+ const raw = parseDocument({
65
+ id: btoa(`Document:inquiry-document-${guidFor(this)}`),
66
+ __typename: "Document",
67
+ answers,
68
+ form,
69
+ });
70
+
71
+ const owner = getOwner(this);
72
+ const Document = owner.factoryFor("caluma-model:document").class;
73
+
74
+ return new Document({ raw, owner });
75
+ });
76
+
77
+ get fieldset() {
78
+ return this.document.value?.fieldsets[0];
79
+ }
80
+
81
+ @action
82
+ async saveField(field, value) {
83
+ field.answer.value = value;
84
+
85
+ await field.validate.perform();
86
+
87
+ this.answers[field.question.slug] = value;
88
+ }
89
+
90
+ @dropTask
91
+ *submit(validate, e) {
92
+ e.preventDefault();
93
+
94
+ if (!this.args.selectedGroups.length || !(yield validate())) return;
95
+
96
+ yield this.distribution.createInquiry.perform(this.args.selectedGroups, {
97
+ answers: this.answers,
98
+ });
99
+
100
+ const lastControlling =
101
+ this.distribution.navigation.value.controlling.edges[0].node;
102
+
103
+ // transition to last added inquiry
104
+ this.router.transitionTo(
105
+ "inquiry.detail.index",
106
+ {
107
+ from: lastControlling.controllingGroups[0],
108
+ to: lastControlling.addressedGroups[0],
109
+ },
110
+ decodeId(lastControlling.id)
111
+ );
112
+ }
113
+ }
@@ -0,0 +1,71 @@
1
+ <div class="uk-margin-bottom uk-button-group">
2
+ {{#each-in this.config.new.types as |slug config|}}
3
+ {{#unless config.disabled}}
4
+ <UkButton
5
+ data-test-type={{slug}}
6
+ @label={{t config.label}}
7
+ @color={{if (includes slug @selectedTypes) "primary" "default"}}
8
+ @onClick={{fn this.updateSelectedTypes slug}}
9
+ />
10
+ {{/unless}}
11
+ {{/each-in}}
12
+ </div>
13
+
14
+ <div class="uk-search uk-search-default uk-width-1-1">
15
+ <span class="uk-search-icon-flip" uk-search-icon></span>
16
+ <input
17
+ placeholder={{t "caluma.distribution.new.search"}}
18
+ aria-label={{t "caluma.distribution.new.search"}}
19
+ class="uk-search-input"
20
+ type="search"
21
+ value={{@search}}
22
+ data-test-search
23
+ {{on "input" (perform this.updateSearch)}}
24
+ />
25
+ </div>
26
+
27
+ {{#if this.groups.isRunning}}
28
+ <div class="uk-text-center uk-margin">
29
+ <UkSpinner @ratio={{2}} />
30
+ </div>
31
+ {{else if this.groups.value.length}}
32
+ <table
33
+ class="uk-table uk-table-striped uk-table-hover uk-table-small uk-table-middle group-list"
34
+ >
35
+ <tbody>
36
+ {{#each this.groups.value as |group|}}
37
+ {{! template-lint-disable require-presentational-children }}
38
+ <tr
39
+ role="checkbox"
40
+ data-test-group={{group.identifier}}
41
+ {{on "click" (fn this.updateSelectedGroups group.identifier)}}
42
+ >
43
+ <td class="uk-padding-remove-right">
44
+ {{! template-lint-disable require-input-label no-nested-interactive }}
45
+ <input
46
+ type="checkbox"
47
+ class="uk-checkbox"
48
+ checked={{includes group.identifier @selectedGroups}}
49
+ />
50
+ </td>
51
+ <td class="uk-width-expand">{{group-name group.identifier}}</td>
52
+ <td class="uk-text-right">
53
+ {{#if group.config.icon}}
54
+ <UkIcon
55
+ @icon={{group.config.icon}}
56
+ class="uk-display-block uk-text-{{group.config.iconColor}}"
57
+ />
58
+ {{/if}}
59
+ </td>
60
+ </tr>
61
+ {{/each}}
62
+ </tbody>
63
+ </table>
64
+ {{else}}
65
+ <div class="uk-text-center">
66
+ <UkIcon @icon="search" @ratio={{10}} class="uk-margin-top" />
67
+ <p class="uk-text-muted">
68
+ {{t "caluma.distribution.new.empty"}}
69
+ </p>
70
+ </div>
71
+ {{/if}}
@@ -0,0 +1,76 @@
1
+ import { action } from "@ember/object";
2
+ import { inject as service } from "@ember/service";
3
+ import { macroCondition, isTesting } from "@embroider/macros";
4
+ import Component from "@glimmer/component";
5
+ import { timeout, restartableTask } from "ember-concurrency";
6
+ import { trackedTask } from "ember-resources/util/ember-concurrency";
7
+
8
+ import config from "@projectcaluma/ember-distribution/config";
9
+
10
+ const toggle = (value, array) => {
11
+ const set = new Set(array);
12
+
13
+ set.delete(value) || set.add(value);
14
+
15
+ return [...set];
16
+ };
17
+
18
+ export default class CdInquiryNewFormSelectComponent extends Component {
19
+ @service calumaOptions;
20
+
21
+ @config config;
22
+
23
+ groups = trackedTask(this, this.fetchGroups, () => [
24
+ this.args.selectedTypes,
25
+ this.args.search,
26
+ ]);
27
+
28
+ @action
29
+ updateSelectedTypes(type, e) {
30
+ e.preventDefault();
31
+
32
+ this.args.onChangeSelectedTypes(toggle(type, this.args.selectedTypes));
33
+ }
34
+
35
+ @action
36
+ updateSelectedGroups(identifier) {
37
+ this.args.onChangeSelectedGroups(
38
+ toggle(identifier, this.args.selectedGroups)
39
+ );
40
+ }
41
+
42
+ @restartableTask
43
+ *updateSearch(e) {
44
+ e.preventDefault();
45
+
46
+ /* istanbul ignore next */
47
+ if (macroCondition(isTesting())) {
48
+ // no timeout
49
+ } else {
50
+ yield timeout(500);
51
+ }
52
+
53
+ this.args.onChangeSearch(e.target.value);
54
+ }
55
+
56
+ @restartableTask
57
+ *fetchGroups(types, search) {
58
+ // https://github.com/ember-cli/eslint-plugin-ember/issues/1413
59
+ yield Promise.resolve();
60
+
61
+ const typedGroups = yield this.calumaOptions.fetchTypedGroups(
62
+ types,
63
+ search
64
+ );
65
+
66
+ return Object.entries(typedGroups)
67
+ .flatMap(([type, groups]) => {
68
+ return groups.map((group) => ({
69
+ identifier: group[this.calumaOptions.groupIdentifierProperty],
70
+ name: group[this.calumaOptions.groupNameProperty],
71
+ config: this.config.new.types[type],
72
+ }));
73
+ })
74
+ .sort((a, b) => a.name.localeCompare(b.name));
75
+ }
76
+ }
@@ -1,6 +1,4 @@
1
- {{#if this.controls.workItems.isRunning}}
2
- <div class="uk-text-center"><UkSpinner @ratio={{2}} /></div>
3
- {{else if (can "create inquiry of distribution")}}
1
+ {{#if (can "create inquiry of distribution")}}
4
2
  <p class="uk-text-large">{{t "caluma.distribution.new.title"}}</p>
5
3
 
6
4
  <hr />
@@ -30,95 +28,40 @@
30
28
  }}
31
29
  </div>
32
30
  <div>
33
- <UkButton
34
- @label={{t "caluma.distribution.new.reset"}}
35
- @onClick={{this.clearSelectedGroups}}
36
- data-test-reset
37
- />
38
- <UkButton
39
- @color="primary"
40
- @label={{t "caluma.distribution.new.create-draft"}}
41
- @type="submit"
42
- @loading={{this.submit.isRunning}}
43
- @disabled={{this.submit.isRunning}}
44
- @onClick={{perform this.submit}}
45
- data-test-submit
46
- />
31
+ {{#if this.edit}}
32
+ <UkButton
33
+ @label={{t "caluma.distribution.new.back"}}
34
+ @onClick={{fn (mut this.edit) false}}
35
+ />
36
+ {{else}}
37
+ <UkButton
38
+ @label={{t "caluma.distribution.new.reset"}}
39
+ @onClick={{this.clearSelectedGroups}}
40
+ data-test-reset
41
+ />
42
+ <UkButton
43
+ @color="primary"
44
+ @label={{t "caluma.distribution.new.continue"}}
45
+ @onClick={{fn (mut this.edit) true}}
46
+ data-test-continue
47
+ />
48
+ {{/if}}
47
49
  </div>
48
50
  </div>
49
51
  <hr />
50
52
  {{/if}}
51
53
 
52
- <div class="uk-margin-bottom uk-button-group">
53
- {{#each-in this.config.new.types as |slug config|}}
54
- {{#unless config.disabled}}
55
- <UkButton
56
- data-test-type={{slug}}
57
- @label={{t config.label}}
58
- @color={{if (includes slug @selectedTypes) "primary" "default"}}
59
- @onClick={{fn this.updateSelectedTypes slug}}
60
- />
61
- {{/unless}}
62
- {{/each-in}}
63
- </div>
64
-
65
- <div class="uk-search uk-search-default uk-width-1-1">
66
- <span class="uk-search-icon-flip" uk-search-icon></span>
67
- <input
68
- placeholder={{t "caluma.distribution.new.search"}}
69
- aria-label={{t "caluma.distribution.new.search"}}
70
- class="uk-search-input"
71
- type="search"
72
- value={{@search}}
73
- data-test-search
74
- {{on "input" (perform this.updateSearch)}}
75
- />
76
- </div>
77
-
78
- {{#if this.groups.isRunning}}
79
- <div class="uk-text-center uk-margin">
80
- <UkSpinner @ratio={{2}} />
81
- </div>
82
- {{else if this.groups.value.length}}
83
- <table
84
- class="uk-table uk-table-striped uk-table-hover uk-table-small uk-table-middle group-list"
85
- >
86
- <tbody>
87
- {{#each this.groups.value as |group|}}
88
- {{! template-lint-disable require-presentational-children }}
89
- <tr
90
- role="checkbox"
91
- data-test-group={{group.identifier}}
92
- {{on "click" (fn this.updateSelectedGroups group.identifier)}}
93
- >
94
- <td class="uk-padding-remove-right">
95
- {{! template-lint-disable require-input-label no-nested-interactive }}
96
- <input
97
- type="checkbox"
98
- class="uk-checkbox"
99
- checked={{includes group.identifier this.selectedGroups}}
100
- />
101
- </td>
102
- <td class="uk-width-expand">{{group-name group.identifier}}</td>
103
- <td class="uk-text-right">
104
- {{#if group.config.icon}}
105
- <UkIcon
106
- @icon={{group.config.icon}}
107
- class="uk-display-block uk-text-{{group.config.iconColor}}"
108
- />
109
- {{/if}}
110
- </td>
111
- </tr>
112
- {{/each}}
113
- </tbody>
114
- </table>
54
+ {{#if this.edit}}
55
+ <CdInquiryNewForm::BulkEdit @selectedGroups={{this.selectedGroups}} />
115
56
  {{else}}
116
- <div class="uk-text-center">
117
- <UkIcon @icon="search" @ratio={{10}} class="uk-margin-top" />
118
- <p class="uk-text-muted">
119
- {{t "caluma.distribution.new.empty"}}
120
- </p>
121
- </div>
57
+ <CdInquiryNewForm::Select
58
+ @search={{@search}}
59
+ @selectedGroups={{this.selectedGroups}}
60
+ @selectedTypes={{@selectedTypes}}
61
+ @onChangeSearch={{@onChangeSearch}}
62
+ @onChangeSelectedGroups={{fn (mut this.selectedGroups)}}
63
+ @onChangeSelectedTypes={{@onChangeSelectedTypes}}
64
+ />
122
65
  {{/if}}
123
66
  {{else}}
124
67
  <CdNotfound />
@@ -1,114 +1,15 @@
1
1
  import { action } from "@ember/object";
2
- import { inject as service } from "@ember/service";
3
- import { macroCondition, isTesting } from "@embroider/macros";
4
2
  import Component from "@glimmer/component";
5
3
  import { tracked } from "@glimmer/tracking";
6
- import { queryManager } from "ember-apollo-client";
7
- import { timeout, restartableTask, dropTask, task } from "ember-concurrency";
8
- import { trackedTask } from "ember-resources/util/ember-concurrency";
9
-
10
- import { decodeId } from "@projectcaluma/ember-core/helpers/decode-id";
11
- import config from "@projectcaluma/ember-distribution/config";
12
-
13
- const toggle = (value, array) => {
14
- const set = new Set(array);
15
-
16
- set.delete(value) || set.add(value);
17
-
18
- return [...set];
19
- };
20
4
 
21
5
  export default class CdInquiryNewFormComponent extends Component {
22
- @service calumaOptions;
23
- @service notification;
24
- @service intl;
25
- @service router;
26
- @service distribution;
27
-
28
- @queryManager apollo;
29
-
30
- @config config;
31
-
6
+ @tracked edit = false;
32
7
  @tracked selectedGroups = [];
33
8
 
34
- groups = trackedTask(this, this.fetchGroups, () => [
35
- this.args.selectedTypes,
36
- this.args.search,
37
- ]);
38
-
39
- @action
40
- updateSelectedTypes(type, e) {
41
- e.preventDefault();
42
-
43
- this.args.onChangeSelectedTypes(toggle(type, this.args.selectedTypes));
44
- }
45
-
46
- @action
47
- updateSelectedGroups(identifier) {
48
- this.selectedGroups = toggle(identifier, this.selectedGroups);
49
- }
50
-
51
9
  @action
52
10
  clearSelectedGroups(e) {
53
11
  e.preventDefault();
54
12
 
55
13
  this.selectedGroups = [];
56
14
  }
57
-
58
- @restartableTask
59
- *updateSearch(e) {
60
- e.preventDefault();
61
-
62
- /* istanbul ignore next */
63
- if (macroCondition(isTesting())) {
64
- // no timeout
65
- } else {
66
- yield timeout(500);
67
- }
68
-
69
- this.args.onChangeSearch(e.target.value);
70
- }
71
-
72
- @dropTask
73
- *submit(e) {
74
- e.preventDefault();
75
-
76
- if (!this.selectedGroups.length) return;
77
-
78
- yield this.distribution.createInquiry.perform(this.selectedGroups);
79
-
80
- const lastControlling =
81
- this.distribution.navigation.value.controlling.edges[0].node;
82
-
83
- // transition to last added inquiry
84
- this.router.transitionTo(
85
- "inquiry.detail.index",
86
- {
87
- from: lastControlling.controllingGroups[0],
88
- to: lastControlling.addressedGroups[0],
89
- },
90
- decodeId(lastControlling.id)
91
- );
92
- }
93
-
94
- @task
95
- *fetchGroups(types, search) {
96
- // https://github.com/ember-cli/eslint-plugin-ember/issues/1413
97
- yield Promise.resolve();
98
-
99
- const typedGroups = yield this.calumaOptions.fetchTypedGroups(
100
- types,
101
- search
102
- );
103
-
104
- return Object.entries(typedGroups)
105
- .flatMap(([type, groups]) => {
106
- return groups.map((group) => ({
107
- identifier: group[this.calumaOptions.groupIdentifierProperty],
108
- name: group[this.calumaOptions.groupNameProperty],
109
- config: this.config.new.types[type],
110
- }));
111
- })
112
- .sort((a, b) => a.name.localeCompare(b.name));
113
- }
114
15
  }