@projectcaluma/ember-analytics 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/addon/components/ca-field-form.hbs +82 -0
- package/addon/components/ca-field-form.js +100 -0
- package/addon/components/ca-field-select.hbs +30 -0
- package/addon/components/ca-field-select.js +111 -0
- package/addon/components/ca-field-selector-list/ca-field-alias-input.hbs +21 -0
- package/addon/components/ca-field-selector-list/ca-field-alias-input.js +28 -0
- package/addon/components/ca-field-selector-list/ca-field-function-select.hbs +8 -0
- package/addon/components/ca-field-selector-list/ca-field-function-select.js +49 -0
- package/addon/components/ca-field-selector-list.hbs +82 -0
- package/addon/components/ca-field-selector-list.js +54 -0
- package/addon/components/ca-filter-modal.hbs +77 -0
- package/addon/components/ca-filter-modal.js +59 -0
- package/addon/components/ca-report-builder.hbs +26 -0
- package/addon/components/ca-report-builder.js +52 -0
- package/addon/components/ca-report-list.hbs +27 -0
- package/addon/components/ca-report-preview.hbs +42 -0
- package/addon/components/ca-report-preview.js +61 -0
- package/addon/components/ca-toggle-switch.hbs +19 -0
- package/addon/controllers/reports/edit/index.js +17 -0
- package/addon/controllers/reports/edit.js +44 -0
- package/addon/controllers/reports/index.js +11 -0
- package/addon/engine.js +17 -0
- package/addon/gql/fragments/analytics-available-field.graphql +8 -0
- package/addon/gql/fragments/analytics-field.graphql +9 -0
- package/addon/gql/fragments/analytics-table-fields-of-field.graphql +11 -0
- package/addon/gql/fragments/analytics-table-result.graphql +22 -0
- package/addon/gql/fragments/analytics-table.graphql +23 -0
- package/addon/gql/mutations/remove-analytics-field.graphql +5 -0
- package/addon/gql/mutations/remove-analytics-table.graphql +5 -0
- package/addon/gql/mutations/save-analytics-field.graphql +19 -0
- package/addon/gql/mutations/save-analytics-table.graphql +9 -0
- package/addon/gql/queries/get-all-analytics-fields.graphql +12 -0
- package/addon/gql/queries/get-all-analytics-tables.graphql +11 -0
- package/addon/gql/queries/get-analytics-results.graphql +20 -0
- package/addon/gql/queries/get-analytics-table.graphql +7 -0
- package/addon/gql/queries/get-available-fields-for-field.graphql +8 -0
- package/addon/routes/reports/edit/index.js +7 -0
- package/addon/routes/reports/edit/preview.js +7 -0
- package/addon/routes/reports/edit.js +14 -0
- package/addon/routes/reports/index.js +26 -0
- package/addon/routes/reports/new.js +32 -0
- package/addon/routes.js +11 -0
- package/addon/tasks/get-analytics-table.js +19 -0
- package/addon/tasks/save-analytics-field.js +19 -0
- package/addon/templates/reports/edit/index.hbs +8 -0
- package/addon/templates/reports/edit/preview.hbs +1 -0
- package/addon/templates/reports/edit.hbs +51 -0
- package/addon/templates/reports/index.hbs +4 -0
- package/addon/templates/reports/new.hbs +2 -0
- package/addon/validations/analytics-table.js +6 -0
- package/addon/validations/field.js +14 -0
- package/app/components/ca-field-form.js +1 -0
- package/app/components/ca-field-select.js +1 -0
- package/app/components/ca-field-selector-list/ca-field-alias-input.js +1 -0
- package/app/components/ca-field-selector-list/ca-field-function-select.js +1 -0
- package/app/components/ca-field-selector-list.js +1 -0
- package/app/components/ca-filter-modal.js +1 -0
- package/app/components/ca-report-builder.js +1 -0
- package/app/components/ca-report-list.js +1 -0
- package/app/components/ca-report-preview.js +1 -0
- package/app/components/ca-toggle-switch.js +1 -0
- package/app/controllers/reports/edit/index.js +1 -0
- package/app/controllers/reports/edit.js +1 -0
- package/app/controllers/reports/index.js +1 -0
- package/app/routes/reports/edit/index.js +1 -0
- package/app/routes/reports/edit/preview.js +1 -0
- package/app/routes/reports/edit.js +1 -0
- package/app/routes/reports/index.js +1 -0
- package/app/routes/reports/new.js +1 -0
- package/app/styles/@projectcaluma/ember-analytics.scss +1 -0
- package/app/styles/_ca-uikit-powerselect.scss +2 -0
- package/app/templates/reports/edit/index.js +1 -0
- package/app/templates/reports/edit/preview.js +1 -0
- package/app/templates/reports/edit.js +1 -0
- package/app/templates/reports/index.js +1 -0
- package/app/templates/reports/new.js +1 -0
- package/blueprints/@projectcaluma/ember-analytics/index.js +18 -0
- package/config/environment.js +16 -0
- package/index.js +13 -0
- package/package.json +90 -0
- package/translations/de.yaml +44 -0
- package/translations/en.yaml +44 -0
- package/translations/fr.yaml +44 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# @projectcaluma/ember-analytics-v1.0.0-beta.1 (2022-08-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### chore
|
|
5
|
+
|
|
6
|
+
* **deps:** update dependencies and drop support for node 10 ([51d6dee](https://github.com/projectcaluma/ember-caluma/commit/51d6deeda9811518622ba0cefd8d3876651dab4f))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **analytics:** adds analytics module for caluma ([#1655](https://github.com/projectcaluma/ember-caluma/issues/1655)) ([9573abe](https://github.com/projectcaluma/ember-caluma/commit/9573abe95cd39cb1467113026f2ab7773c3c9143))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### BREAKING CHANGES
|
|
15
|
+
|
|
16
|
+
* **deps:** Remove support for node v10
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{{#if this.showForm}}
|
|
2
|
+
<ValidatedForm @model={{this.field}} @on-submit={{this.submitField}} as |f|>
|
|
3
|
+
<div
|
|
4
|
+
data-test-add-field-form
|
|
5
|
+
class="uk-flex uk-flex-between uk-flex-middle"
|
|
6
|
+
>
|
|
7
|
+
<h3>{{t "caluma.analytics.edit.add-field"}}</h3>
|
|
8
|
+
<div class="uk-flex uk-flex-middle">
|
|
9
|
+
<div class="uk-margin-right uk-flex uk-flex-middle">
|
|
10
|
+
<f.input
|
|
11
|
+
@name="showOutput"
|
|
12
|
+
@label={{t "caluma.analytics.edit.show-in-output"}}
|
|
13
|
+
@required={{true}}
|
|
14
|
+
@renderComponent={{component
|
|
15
|
+
(ensure-safe-component "ca-toggle-switch")
|
|
16
|
+
value=f.model.showOutput
|
|
17
|
+
size="small"
|
|
18
|
+
onToggle=(mut f.model.showOutput)
|
|
19
|
+
}}
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<f.input
|
|
26
|
+
@type="select"
|
|
27
|
+
@name="dataSource"
|
|
28
|
+
@label={{t "caluma.analytics.edit.field"}}
|
|
29
|
+
>
|
|
30
|
+
<div class="uk-grid-small uk-child-width-1-5" uk-grid>
|
|
31
|
+
<CaFieldSelect
|
|
32
|
+
@onSelect={{this.setFieldPath}}
|
|
33
|
+
@selectedPath={{this.field.dataSource}}
|
|
34
|
+
@slug={{@analyticsTable.slug}}
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
</f.input>
|
|
38
|
+
{{#if this.showAggregationSelect}}
|
|
39
|
+
<f.input
|
|
40
|
+
@name="aggregateFunction"
|
|
41
|
+
@type="select"
|
|
42
|
+
@label={{t "caluma.analytics.edit.aggregation"}}
|
|
43
|
+
@options={{this.supportedFunctions}}
|
|
44
|
+
class="uk-width-small"
|
|
45
|
+
/>
|
|
46
|
+
{{/if}}
|
|
47
|
+
<f.input
|
|
48
|
+
@name="alias"
|
|
49
|
+
@type="text"
|
|
50
|
+
@label={{t "caluma.analytics.edit.display-title"}}
|
|
51
|
+
@placeholder={{t "caluma.analytics.edit.display-title-placeholder"}}
|
|
52
|
+
/>
|
|
53
|
+
<div class="uk-flex uk-flex-right">
|
|
54
|
+
<f.button
|
|
55
|
+
data-test-form-cancel
|
|
56
|
+
class="uk-margin-small-right"
|
|
57
|
+
@disabled={{this.saveField.isRunning}}
|
|
58
|
+
{{on "click" this.toggleForm}}
|
|
59
|
+
>
|
|
60
|
+
{{t "caluma.analytics.cancel"}}
|
|
61
|
+
</f.button>
|
|
62
|
+
|
|
63
|
+
<f.submit
|
|
64
|
+
data-test-form-submit
|
|
65
|
+
@loading={{this.saveField.isRunning}}
|
|
66
|
+
@disabled={{or this.saveField.isRunning (not this.isValueField)}}
|
|
67
|
+
>
|
|
68
|
+
{{t "caluma.analytics.edit.add-field"}}
|
|
69
|
+
</f.submit>
|
|
70
|
+
</div>
|
|
71
|
+
</ValidatedForm>
|
|
72
|
+
{{else}}
|
|
73
|
+
<div class="uk-flex uk-flex-right">
|
|
74
|
+
<UkButton
|
|
75
|
+
@color="primary"
|
|
76
|
+
data-test-add-field-button
|
|
77
|
+
{{on "click" this.toggleForm}}
|
|
78
|
+
>
|
|
79
|
+
{{t "caluma.analytics.edit.add-field"}}
|
|
80
|
+
</UkButton>
|
|
81
|
+
</div>
|
|
82
|
+
{{/if}}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { action } from "@ember/object";
|
|
2
|
+
import { inject as service } from "@ember/service";
|
|
3
|
+
import Component from "@glimmer/component";
|
|
4
|
+
import { tracked } from "@glimmer/tracking";
|
|
5
|
+
import { queryManager } from "ember-apollo-client";
|
|
6
|
+
import { Changeset } from "ember-changeset";
|
|
7
|
+
import lookupValidator from "ember-changeset-validations";
|
|
8
|
+
import { enqueueTask } from "ember-concurrency";
|
|
9
|
+
|
|
10
|
+
import saveAnalyticsField from "@projectcaluma/ember-analytics/tasks/save-analytics-field";
|
|
11
|
+
import FieldValidations from "@projectcaluma/ember-analytics/validations/field";
|
|
12
|
+
|
|
13
|
+
class Field {
|
|
14
|
+
@tracked alias;
|
|
15
|
+
@tracked dataSource;
|
|
16
|
+
@tracked aggregateFunction = "VALUE";
|
|
17
|
+
@tracked showOutput = true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default class CaFieldFormComponent extends Component {
|
|
21
|
+
@queryManager apollo;
|
|
22
|
+
@service notification;
|
|
23
|
+
@service intl;
|
|
24
|
+
|
|
25
|
+
@tracked supportedFunctions = [];
|
|
26
|
+
@tracked isValueField = false;
|
|
27
|
+
@tracked showForm = false;
|
|
28
|
+
|
|
29
|
+
@enqueueTask saveField = saveAnalyticsField;
|
|
30
|
+
|
|
31
|
+
constructor(...args) {
|
|
32
|
+
super(...args);
|
|
33
|
+
this.field = Changeset(
|
|
34
|
+
new Field(),
|
|
35
|
+
lookupValidator(FieldValidations),
|
|
36
|
+
FieldValidations
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get tableId() {
|
|
41
|
+
return this.args.analyticsTable?.id;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get analyticsFields() {
|
|
45
|
+
return this.args.analyticsTable?.fields.edges.map((edge) => edge.node);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get tableSlug() {
|
|
49
|
+
return this.args.analyticsTable?.slug;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get showAggregationSelect() {
|
|
53
|
+
return this.field.dataSource && this.supportedFunctions.length;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@action
|
|
57
|
+
toggleForm() {
|
|
58
|
+
this.showForm = !this.showForm;
|
|
59
|
+
this.field.rollback();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@action
|
|
63
|
+
setFieldPath(field) {
|
|
64
|
+
this.field.dataSource = field.sourcePath;
|
|
65
|
+
this.field.alias = field.label;
|
|
66
|
+
this.supportedFunctions = field.supportedFunctions;
|
|
67
|
+
this.isValueField = field.isValue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@action
|
|
71
|
+
async submitField() {
|
|
72
|
+
this.field.validate();
|
|
73
|
+
|
|
74
|
+
if (this.field.isInvalid) {
|
|
75
|
+
this.notification.danger(
|
|
76
|
+
this.intl.t(`caluma.analytics.notification.field-invalid`)
|
|
77
|
+
);
|
|
78
|
+
} else if (
|
|
79
|
+
this.analyticsFields.find(
|
|
80
|
+
(existing) => existing.alias === this.field.get("alias")
|
|
81
|
+
)
|
|
82
|
+
) {
|
|
83
|
+
this.notification.danger(
|
|
84
|
+
this.intl.t(`caluma.analytics.notification.alias-exists`)
|
|
85
|
+
);
|
|
86
|
+
} else {
|
|
87
|
+
const { id, alias, dataSource, aggregateFunction, showOutput } =
|
|
88
|
+
this.field.pendingData;
|
|
89
|
+
await this.saveField.perform({
|
|
90
|
+
table: this.tableId,
|
|
91
|
+
id,
|
|
92
|
+
alias,
|
|
93
|
+
dataSource,
|
|
94
|
+
showOutput,
|
|
95
|
+
function: aggregateFunction,
|
|
96
|
+
});
|
|
97
|
+
this.toggleForm();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{{#if @child}}
|
|
2
|
+
<span
|
|
3
|
+
data-test-field-select-seperator
|
|
4
|
+
uk-icon="icon: triangle-right; ratio: 1.5"
|
|
5
|
+
class="uk-width-auto uk-text-center uk-margin-auto-vertical"
|
|
6
|
+
></span>
|
|
7
|
+
{{/if}}
|
|
8
|
+
<div ...attributes data-test-field-select-primary-selector={{not @child}}>
|
|
9
|
+
<PowerSelect
|
|
10
|
+
class={{this.selectedOption.value}}
|
|
11
|
+
@options={{this.options}}
|
|
12
|
+
@selected={{this.selectedOption}}
|
|
13
|
+
@onChange={{this.update}}
|
|
14
|
+
@triggerId={{this.fieldPath}}
|
|
15
|
+
@onOpen={{this.fetchOptions.perform}}
|
|
16
|
+
as |option|
|
|
17
|
+
>
|
|
18
|
+
{{option.label}}
|
|
19
|
+
</PowerSelect>
|
|
20
|
+
</div>
|
|
21
|
+
{{#if this.isBranch}}
|
|
22
|
+
<CaFieldSelect
|
|
23
|
+
data-test-field-select-secondary-selector
|
|
24
|
+
@child={{true}}
|
|
25
|
+
@onSelect={{@onSelect}}
|
|
26
|
+
@parentPath={{this.fieldPath}}
|
|
27
|
+
@selectedPath={{@selectedPath}}
|
|
28
|
+
@slug={{@slug}}
|
|
29
|
+
/>
|
|
30
|
+
{{/if}}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { assert } from "@ember/debug";
|
|
2
|
+
import { action, set } from "@ember/object";
|
|
3
|
+
import { inject as service } from "@ember/service";
|
|
4
|
+
import Component from "@glimmer/component";
|
|
5
|
+
import { tracked } from "@glimmer/tracking";
|
|
6
|
+
import { queryManager } from "ember-apollo-client";
|
|
7
|
+
import { restartableTask } from "ember-concurrency";
|
|
8
|
+
|
|
9
|
+
import getAvailableFieldsForFieldQuery from "@projectcaluma/ember-analytics/gql/queries/get-available-fields-for-field.graphql";
|
|
10
|
+
|
|
11
|
+
export default class CaFieldSelectComponent extends Component {
|
|
12
|
+
@queryManager apollo;
|
|
13
|
+
@service notification;
|
|
14
|
+
@service intl;
|
|
15
|
+
|
|
16
|
+
@tracked _selectedOption;
|
|
17
|
+
@tracked options;
|
|
18
|
+
|
|
19
|
+
get selectedOption() {
|
|
20
|
+
if (!this.currentPathSegment) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
return { ...this._selectedOption, ...{ value: this.currentPathSegment } };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get currentPathSegment() {
|
|
27
|
+
if (!this.args.selectedPath) return "";
|
|
28
|
+
const remainingFromParentPath = this.args.parentPath
|
|
29
|
+
? this.args.selectedPath.substring(this.args.parentPath.length + 1)
|
|
30
|
+
: this.args.selectedPath;
|
|
31
|
+
return this.firstSegment(remainingFromParentPath);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get hasRemainingPath() {
|
|
35
|
+
if (!this.args.selectedPath) return false;
|
|
36
|
+
const remainingFromParentPath = this.args.parentPath
|
|
37
|
+
? this.args.selectedPath.substring(this.args.parentPath.length + 1)
|
|
38
|
+
: this.args.selectedPath;
|
|
39
|
+
return remainingFromParentPath.length > this.currentPathSegment.length + 1;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
get fieldPath() {
|
|
43
|
+
if (!this.currentPathSegment) return "";
|
|
44
|
+
return (
|
|
45
|
+
(this.args.parentPath ? `${this.args.parentPath}.` : "") +
|
|
46
|
+
this.currentPathSegment
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get isBranch() {
|
|
51
|
+
if (
|
|
52
|
+
(this.isRoot && this.fetchedFor === "_root_") ||
|
|
53
|
+
this.fetchedFor === this.args.parentPath
|
|
54
|
+
) {
|
|
55
|
+
return this._selectedOption ? !this._selectedOption.isLeaf : false;
|
|
56
|
+
}
|
|
57
|
+
return this.hasRemainingPath;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get isRoot() {
|
|
61
|
+
return !this.args.parentPath;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@action
|
|
65
|
+
update(value) {
|
|
66
|
+
assert(
|
|
67
|
+
"A listener for updates on CaFieldSelectComponent has to be set.",
|
|
68
|
+
this.args.onSelect
|
|
69
|
+
);
|
|
70
|
+
set(this, "_selectedOption", value);
|
|
71
|
+
this.args.onSelect(this._selectedOption);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@restartableTask
|
|
75
|
+
*fetchOptions() {
|
|
76
|
+
try {
|
|
77
|
+
if (
|
|
78
|
+
!this.fetchedFor ||
|
|
79
|
+
(!this.isRoot && this.fetchedFor !== this.args.parentPath)
|
|
80
|
+
) {
|
|
81
|
+
const options = yield this.apollo.query(
|
|
82
|
+
{
|
|
83
|
+
query: getAvailableFieldsForFieldQuery,
|
|
84
|
+
fetchPolicy: "no-cache",
|
|
85
|
+
variables: {
|
|
86
|
+
slug: this.args.slug,
|
|
87
|
+
prefix: this.args.parentPath ?? "",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
"analyticsTable.availableFields"
|
|
91
|
+
);
|
|
92
|
+
this.fetchedFor = this.isRoot ? "_root_" : this.args.parentPath;
|
|
93
|
+
this.options = options.edges.map((edge) => edge.node);
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(error);
|
|
97
|
+
this.notification.danger(
|
|
98
|
+
this.intl.t("caluma.analytics.notification.fetch-error")
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
firstSegment(path) {
|
|
104
|
+
if (!path) return "";
|
|
105
|
+
if (path.indexOf(".") === -1) {
|
|
106
|
+
return path;
|
|
107
|
+
}
|
|
108
|
+
const delimiterIndex = path.indexOf(".");
|
|
109
|
+
return path.substring(0, delimiterIndex);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<div class="uk-inline">
|
|
2
|
+
<button
|
|
3
|
+
data-test-delete-field
|
|
4
|
+
type="button"
|
|
5
|
+
class="uk-form-icon uk-form-icon-flip"
|
|
6
|
+
uk-icon="check"
|
|
7
|
+
hidden={{not this.hasChanged}}
|
|
8
|
+
name={{t "caluma.analytics.edit.delete-field"}}
|
|
9
|
+
{{on "click" this.trimAndSave}}
|
|
10
|
+
>
|
|
11
|
+
<span hidden>{{t "caluma.analytics.edit.delete-field"}}</span>
|
|
12
|
+
</button>
|
|
13
|
+
|
|
14
|
+
<input
|
|
15
|
+
data-test-field-alias-input
|
|
16
|
+
aria-label={{t "caluma.analytics.edit.display-title"}}
|
|
17
|
+
class="uk-input {{if this.hasChanged 'uk-form-success'}}"
|
|
18
|
+
value={{this.value}}
|
|
19
|
+
{{on "input" (perform this.debounceInput)}}
|
|
20
|
+
/>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { action } from "@ember/object";
|
|
2
|
+
import Component from "@glimmer/component";
|
|
3
|
+
import { tracked } from "@glimmer/tracking";
|
|
4
|
+
import { restartableTask, timeout } from "ember-concurrency";
|
|
5
|
+
|
|
6
|
+
export default class CaFieldSelectorListCaFieldAliasInputComponent extends Component {
|
|
7
|
+
@tracked _value = null;
|
|
8
|
+
|
|
9
|
+
get value() {
|
|
10
|
+
return this._value ?? this.args.value;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
get hasChanged() {
|
|
14
|
+
return this._value !== null && this._value !== this.args.value;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@action
|
|
18
|
+
async trimAndSave() {
|
|
19
|
+
await this.args.onSave(this._value);
|
|
20
|
+
this._value = null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@restartableTask
|
|
24
|
+
*debounceInput(event) {
|
|
25
|
+
yield timeout(200);
|
|
26
|
+
this._value = event.target.value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { inject as service } from "@ember/service";
|
|
2
|
+
import Component from "@glimmer/component";
|
|
3
|
+
import { tracked } from "@glimmer/tracking";
|
|
4
|
+
import { queryManager } from "ember-apollo-client";
|
|
5
|
+
import { task } from "ember-concurrency";
|
|
6
|
+
import { trackedTask } from "ember-resources/util/ember-concurrency";
|
|
7
|
+
|
|
8
|
+
import getAvailableFieldsForFieldQuery from "@projectcaluma/ember-analytics/gql/queries/get-available-fields-for-field.graphql";
|
|
9
|
+
|
|
10
|
+
export default class CaFieldSelectorListCaFieldFunctionSelectComponent extends Component {
|
|
11
|
+
@queryManager apollo;
|
|
12
|
+
@service notification;
|
|
13
|
+
@service intl;
|
|
14
|
+
|
|
15
|
+
@tracked aggregationFunctions = trackedTask(
|
|
16
|
+
this,
|
|
17
|
+
this.getAggregationFunctions,
|
|
18
|
+
() => [this.args.field, this.args.tableSlug]
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
@task
|
|
22
|
+
*getAggregationFunctions() {
|
|
23
|
+
try {
|
|
24
|
+
// Get the base path without the field so we can fetch the necessary fields later on.
|
|
25
|
+
const pathList = this.args.field.dataSource.split(".");
|
|
26
|
+
const prefix = pathList.slice(0, -1).join(".");
|
|
27
|
+
const options = yield this.apollo.query(
|
|
28
|
+
{
|
|
29
|
+
query: getAvailableFieldsForFieldQuery,
|
|
30
|
+
variables: {
|
|
31
|
+
slug: this.args.tableSlug,
|
|
32
|
+
prefix,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
"analyticsTable.availableFields"
|
|
36
|
+
);
|
|
37
|
+
const fields = options.edges.map((edge) => edge.node);
|
|
38
|
+
const field = fields.find(
|
|
39
|
+
(field) => field.sourcePath === this.args.field.dataSource
|
|
40
|
+
);
|
|
41
|
+
return field?.supportedFunctions ?? [];
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error(error);
|
|
44
|
+
this.notification.danger(
|
|
45
|
+
this.intl.t("caluma.analytics.notification.fetch-error")
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<table class="uk-table uk-table-divider uk-table-hover" uk-overflow-auto>
|
|
2
|
+
<thead>
|
|
3
|
+
<tr>
|
|
4
|
+
<th>{{t "caluma.analytics.edit.question"}}</th>
|
|
5
|
+
<th>{{t "caluma.analytics.edit.display-title"}}</th>
|
|
6
|
+
<th>{{t "caluma.analytics.edit.aggregation"}}</th>
|
|
7
|
+
<th class="uk-text-center">{{t
|
|
8
|
+
"caluma.analytics.edit.show-in-output"
|
|
9
|
+
}}</th>
|
|
10
|
+
<th>{{t "caluma.analytics.edit.filter"}}</th>
|
|
11
|
+
<th></th>
|
|
12
|
+
</tr>
|
|
13
|
+
</thead>
|
|
14
|
+
<tbody>
|
|
15
|
+
{{#each this.fields as |field|}}
|
|
16
|
+
{{#let (fn this.updateField field) as |update|}}
|
|
17
|
+
<tr>
|
|
18
|
+
<td>
|
|
19
|
+
{{field.dataSource}}
|
|
20
|
+
</td>
|
|
21
|
+
<td>
|
|
22
|
+
<CaFieldSelectorList::CaFieldAliasInput
|
|
23
|
+
@value={{field.alias}}
|
|
24
|
+
@onSave={{fn update "alias"}}
|
|
25
|
+
/>
|
|
26
|
+
</td>
|
|
27
|
+
<td>
|
|
28
|
+
<CaFieldSelectorList::CaFieldFunctionSelect
|
|
29
|
+
@field={{field}}
|
|
30
|
+
@tableSlug={{@analyticsTable.slug}}
|
|
31
|
+
@update={{update}}
|
|
32
|
+
/>
|
|
33
|
+
</td>
|
|
34
|
+
<td class="uk-flex uk-flex-center uk-flex-middle">
|
|
35
|
+
<UkToggleSwitch
|
|
36
|
+
@value={{field.showOutput}}
|
|
37
|
+
@size="small"
|
|
38
|
+
@onToggle={{fn update "showOutput"}}
|
|
39
|
+
/>
|
|
40
|
+
</td>
|
|
41
|
+
<td>
|
|
42
|
+
<CaFilterModal
|
|
43
|
+
@table={{@analyticsTable.id}}
|
|
44
|
+
@field={{field}}
|
|
45
|
+
as |TriggerButton|
|
|
46
|
+
>
|
|
47
|
+
<TriggerButton
|
|
48
|
+
@label={{if
|
|
49
|
+
field.filters.length
|
|
50
|
+
(t
|
|
51
|
+
"caluma.analytics.edit.edit-filters"
|
|
52
|
+
num=field.filters.length
|
|
53
|
+
)
|
|
54
|
+
(t "caluma.analytics.edit.add-filters")
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
</CaFilterModal>
|
|
58
|
+
</td>
|
|
59
|
+
<td>
|
|
60
|
+
<button
|
|
61
|
+
data-test-delete-field
|
|
62
|
+
type="button"
|
|
63
|
+
class="uk-icon-button"
|
|
64
|
+
uk-icon="trash"
|
|
65
|
+
name={{t "caluma.analytics.edit.delete-field"}}
|
|
66
|
+
{{on "click" (perform this.removeAnalyticsField field.id)}}
|
|
67
|
+
>
|
|
68
|
+
<span hidden>{{t "caluma.analytics.edit.delete-field"}}</span>
|
|
69
|
+
</button>
|
|
70
|
+
</td>
|
|
71
|
+
</tr>
|
|
72
|
+
{{/let}}
|
|
73
|
+
{{else}}
|
|
74
|
+
<td colspan="5">
|
|
75
|
+
<h3 class="uk-flex uk-flex-center uk-flex-middle">
|
|
76
|
+
<UkIcon @icon="search" @ratio="1.5" class="uk-margin-small-right" />
|
|
77
|
+
{{t "caluma.analytics.edit.empty"}}
|
|
78
|
+
</h3>
|
|
79
|
+
</td>
|
|
80
|
+
{{/each}}
|
|
81
|
+
</tbody>
|
|
82
|
+
</table>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { action } from "@ember/object";
|
|
2
|
+
import { inject as service } from "@ember/service";
|
|
3
|
+
import Component from "@glimmer/component";
|
|
4
|
+
import { queryManager, getObservable } from "ember-apollo-client";
|
|
5
|
+
import { enqueueTask } from "ember-concurrency";
|
|
6
|
+
|
|
7
|
+
import removeAnalyticsFieldMutation from "@projectcaluma/ember-analytics/gql/mutations/remove-analytics-field.graphql";
|
|
8
|
+
import saveAnalyticsField from "@projectcaluma/ember-analytics/tasks/save-analytics-field";
|
|
9
|
+
|
|
10
|
+
export default class CaFieldSelectorListComponent extends Component {
|
|
11
|
+
@queryManager apollo;
|
|
12
|
+
@service notification;
|
|
13
|
+
@service intl;
|
|
14
|
+
|
|
15
|
+
@enqueueTask saveField = saveAnalyticsField;
|
|
16
|
+
|
|
17
|
+
get fields() {
|
|
18
|
+
return (
|
|
19
|
+
this.args.analyticsTable?.fields?.edges?.map((edge) => edge.node) ?? []
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@action
|
|
24
|
+
async updateField(field, key, value) {
|
|
25
|
+
const requiredInput = {
|
|
26
|
+
id: field.id,
|
|
27
|
+
alias: field.alias,
|
|
28
|
+
dataSource: field.dataSource,
|
|
29
|
+
function: field.function,
|
|
30
|
+
table: this.args.analyticsTable.id,
|
|
31
|
+
};
|
|
32
|
+
await this.saveField.perform({
|
|
33
|
+
...requiredInput,
|
|
34
|
+
[key]: value,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@enqueueTask
|
|
39
|
+
*removeAnalyticsField(id) {
|
|
40
|
+
try {
|
|
41
|
+
yield this.apollo.mutate({
|
|
42
|
+
mutation: removeAnalyticsFieldMutation,
|
|
43
|
+
variables: { input: { id } },
|
|
44
|
+
});
|
|
45
|
+
const observableQuery = getObservable(this.args.analyticsTable);
|
|
46
|
+
yield observableQuery.refetch();
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error(error);
|
|
49
|
+
this.notification.danger(
|
|
50
|
+
this.intl.t("caluma.analytics.notification.delete-error")
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<UkModal
|
|
2
|
+
@visible={{this.visible}}
|
|
3
|
+
@onHide={{fn (mut this.visible) false}}
|
|
4
|
+
as |modal|
|
|
5
|
+
>
|
|
6
|
+
<modal.header>
|
|
7
|
+
<h2 class="uk-modal-title">{{t
|
|
8
|
+
"caluma.analytics.filter-modal.filters"
|
|
9
|
+
}}</h2>
|
|
10
|
+
</modal.header>
|
|
11
|
+
<modal.body>
|
|
12
|
+
|
|
13
|
+
<div class="uk-flex">
|
|
14
|
+
<input
|
|
15
|
+
class="uk-input"
|
|
16
|
+
type="text"
|
|
17
|
+
placeholder={{t "caluma.analytics.filter-modal.filter-placeholder"}}
|
|
18
|
+
value={{this.newFilter}}
|
|
19
|
+
aria-label={{t "caluma.analytics.filter-modal.filter-placeholder"}}
|
|
20
|
+
{{on "input" this.updateNewFilter}}
|
|
21
|
+
/>
|
|
22
|
+
|
|
23
|
+
<UkButton
|
|
24
|
+
@color="primary"
|
|
25
|
+
@disabled={{not this.newFilter}}
|
|
26
|
+
class="uk-flex uk-flex-middle"
|
|
27
|
+
{{on "click" this.addFilter}}
|
|
28
|
+
>
|
|
29
|
+
<UkIcon @icon="plus" @ratio="1.5" />
|
|
30
|
+
</UkButton>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<UkList
|
|
34
|
+
@divider="true"
|
|
35
|
+
class="uk-padding-small uk-padding-remove-left"
|
|
36
|
+
uk-overflow-auto
|
|
37
|
+
as |List|
|
|
38
|
+
>
|
|
39
|
+
{{#each this.filters as |filter|}}
|
|
40
|
+
<List.item class="uk-flex uk-flex-between uk-flex-middle">
|
|
41
|
+
<span>{{filter}}</span>
|
|
42
|
+
<button
|
|
43
|
+
type="button"
|
|
44
|
+
class="uk-icon-button"
|
|
45
|
+
uk-icon="trash"
|
|
46
|
+
name={{t "caluma.analytics.filter-modal.delete-filter"}}
|
|
47
|
+
{{on "click" (fn this.removeFilter filter)}}
|
|
48
|
+
>
|
|
49
|
+
<span hidden>{{t
|
|
50
|
+
"caluma.analytics.filter-modal.delete-filter"
|
|
51
|
+
}}</span>
|
|
52
|
+
</button>
|
|
53
|
+
</List.item>
|
|
54
|
+
{{else}}
|
|
55
|
+
<List.item>{{t "caluma.analytics.filter-modal.empty"}}</List.item>
|
|
56
|
+
{{/each}}
|
|
57
|
+
<List.item />
|
|
58
|
+
</UkList>
|
|
59
|
+
</modal.body>
|
|
60
|
+
<modal.footer class="uk-flex uk-flex-between">
|
|
61
|
+
<UkButton
|
|
62
|
+
@label={{t "caluma.analytics.cancel"}}
|
|
63
|
+
@onClick={{fn (mut this.visible) false}}
|
|
64
|
+
/>
|
|
65
|
+
<UkButton
|
|
66
|
+
@color="primary"
|
|
67
|
+
@onClick={{perform this.saveField this.graphqlInput}}
|
|
68
|
+
@loading={{this.saveField.isRunning}}
|
|
69
|
+
@label={{t "caluma.analytics.save"}}
|
|
70
|
+
/>
|
|
71
|
+
</modal.footer>
|
|
72
|
+
</UkModal>
|
|
73
|
+
{{yield
|
|
74
|
+
(component
|
|
75
|
+
(ensure-safe-component "uk-button") onClick=(fn (mut this.visible) true)
|
|
76
|
+
)
|
|
77
|
+
}}
|