Skip to content

Commit b48f7d3

Browse files
committed
[SER-254] Annotation (Add Note) feature for time series graphs
1 parent e52cb55 commit b48f7d3

File tree

40 files changed

+1161
-580
lines changed

40 files changed

+1161
-580
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ frontend/express/public/sdk/
2020
bin/scripts/nghttp2
2121
frontend/express/public/images/*/
2222
!frontend/express/public/images/leaflet/
23+
!frontend/express/public/images/annotation/
2324
!frontend/express/public/images/dashboard/
2425
!frontend/express/public/images/flags/
2526
!frontend/express/public/images/management/

Gruntfile.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ module.exports = function(grunt) {
145145
'frontend/express/public/javascripts/countly/vue/components/datatable.js',
146146
'frontend/express/public/javascripts/countly/vue/components/dialog.js',
147147
'frontend/express/public/javascripts/countly/vue/components/drawer.js',
148+
'frontend/express/public/core/notes/javascripts/countly.models.js',
149+
'frontend/express/public/core/notes/javascripts/countly.common.notes.js',
148150
'frontend/express/public/javascripts/countly/vue/components/vis.js',
149151
'frontend/express/public/javascripts/countly/vue/components/helpers.js',
150152
'frontend/express/public/javascripts/countly/vue/components/sidebar.js',
@@ -189,7 +191,8 @@ module.exports = function(grunt) {
189191
'frontend/express/public/core/geo-countries/javascripts/countly.views.js',
190192
'frontend/express/public/core/geo-countries/javascripts/countly.widgets.geo.js',
191193
'frontend/express/public/core/home/javascripts/countly.models.js',
192-
'frontend/express/public/core/home/javascripts/countly.views.js'
194+
'frontend/express/public/core/home/javascripts/countly.views.js',
195+
'frontend/express/public/core/notes/javascripts/countly.views.js'
193196
],
194197
dest: 'frontend/express/public/javascripts/min/countly.lib.concat.js'
195198
}

api/parts/mgmt/users.js

+11-5
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ usersApi.checkNoteEditPermission = async function(params) {
740740
return reject(false);
741741
}
742742
const globalAdmin = params.member.global_admin;
743-
const isAppAdmin = hasAdminAccess(params.member, params.qstring.args.app_id);
743+
const isAppAdmin = hasAdminAccess(params.member, params.qstring.app_id);
744744
const noteOwner = (note.owner + '' === params.member._id + '');
745745
return resolve(noteOwner || (isAppAdmin && note.noteType === 'public') || (globalAdmin && note.noteType === 'public'));
746746
}
@@ -780,6 +780,10 @@ usersApi.saveNote = async function(params) {
780780
'category': {
781781
'required': false,
782782
'type': 'Boolean'
783+
},
784+
"indicator": {
785+
'required': false,
786+
'type': 'String'
783787
}
784788
};
785789
const args = params.qstring.args;
@@ -796,6 +800,7 @@ usersApi.saveNote = async function(params) {
796800
owner: params.member._id + "",
797801
created_at: new Date().getTime(),
798802
updated_at: new Date().getTime(),
803+
indicator: args.indicator,
799804
};
800805

801806
if (args._id) {
@@ -910,8 +915,8 @@ usersApi.fetchUserAppIds = async function(params) {
910915
**/
911916
usersApi.fetchNotes = async function(params) {
912917
countlyCommon.getPeriodObj(params);
918+
// const timestampRange = countlyCommon.getTimestampRangeQuery(params, false);
913919

914-
const timestampRange = countlyCommon.getTimestampRangeQuery(params, false);
915920
let appIds = [];
916921
let filtedAppIds = [];
917922
try {
@@ -931,21 +936,21 @@ usersApi.fetchNotes = async function(params) {
931936
}
932937
const query = {
933938
'app_id': {$in: filtedAppIds},
934-
'ts': timestampRange,
939+
'ts': {$gte: params.qstring.period[0], $lte: params.qstring.period[1]},
935940
$or: [
936941
{'owner': params.member._id + ""},
937942
{'noteType': 'public'},
938943
{'emails': {'$in': [params.member.email] }},
939944
],
940945
};
941-
942946
if (params.qstring.category) {
943-
query.category = params.qstring.category;
947+
query.category = {$in: JSON.parse(params.qstring.category)};
944948
}
945949

946950
if (params.qstring.note_type) {
947951
query.noteType = params.qstring.note_type;
948952
}
953+
949954
let skip = params.qstring.iDisplayStart || 0;
950955
let limit = params.qstring.iDisplayLength || 5000;
951956
const sEcho = params.qstring.sEcho || 1;
@@ -968,6 +973,7 @@ usersApi.fetchNotes = async function(params) {
968973
log.e(' got error while paring query notes request', e);
969974
}
970975
let count = 0;
976+
971977
common.db.collection('notes').count(query, function(error, noteCount) {
972978
if (!error && noteCount) {
973979
count = noteCount;

frontend/express/public/core/events/javascripts/countly.details.views.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@
157157
return this.$store.getters["countlyAllEvents/availableSegments"];
158158
},
159159
selectedEventName: function() {
160+
var eventName = this.$store.getters["countlyAllEvents/selectedEventName"];
161+
if (eventName) {
162+
this.graphNotesCategory = 'events ' + eventName;
163+
}
160164
return this.$store.getters["countlyAllEvents/allEventsProcessed"].eventName;
161165
},
162166
groupData: function() {
@@ -205,7 +209,10 @@
205209

206210
},
207211
data: function() {
208-
return {description: CV.i18n('events.all.title.new') };
212+
return {
213+
description: CV.i18n('events.all.title.new'),
214+
graphNotesCategory: ''
215+
};
209216
},
210217
beforeCreate: function() {
211218
var self = this;

frontend/express/public/core/events/templates/allEvents.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ <h2> {{i18n('events.all.title.new')}}
5656
<cly-section class="bu-mt-5 bu-mr-5">
5757
<cly-chart-bar v-if="currentActiveSegmentation !== 'segment'" :option="barData" :legend="lineLegend" :force-loading="isChartLoading" v-loading="isChartLoading">
5858
</cly-chart-bar>
59-
<cly-chart-time v-else :option="chartData" :legend="lineLegend" :force-loading="isChartLoading" v-loading="isChartLoading"></cly-chart-time>
59+
<cly-chart-time v-else :option="chartData" :legend="lineLegend" :force-loading="isChartLoading" v-loading="isChartLoading" :category="graphNotesCategory"></cly-chart-time>
6060
</cly-section>
6161
<cly-section class="bu-mt-5 bu-mr-5">
6262
<detail-tables></detail-tables>
6363
</cly-section>
6464
</div>
6565
</div>
6666
</cly-main>
67-
</div>
67+
</div>

frontend/express/public/core/home/templates/sessionsWidget.html

+2-4
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@ <h2>{{item.number}}</h2>
2222
</div>
2323
</div>
2424
<div style="border-radius: 0 0px 4px 4px; background-color: #ffffff; border: 1px solid #ececec ">
25-
<cly-chart-time :option="chartData(item.value)"></cly-chart-time>
25+
<cly-chart-time category="session" :option="chartData(item.value)"></cly-chart-time>
2626
</div>
2727
</el-tab-pane>
2828
</el-tabs>
2929
</div>
30-
</div>
31-
32-
30+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*global CV,countlyVue, CountlyHelpers, countlyGraphNotes, countlyCommon*/
2+
(function(countlyGraphNotesCommon) {
3+
countlyGraphNotesCommon.COLOR_TAGS = [{
4+
value: 1,
5+
label: "#39C0C8"
6+
},
7+
{
8+
value: 2,
9+
label: "#F5C900"
10+
},
11+
{
12+
value: 3,
13+
label: "#F96300"
14+
},
15+
{
16+
value: 4,
17+
label: "#F34971"
18+
},
19+
{
20+
value: 5,
21+
label: "#6C47FF"
22+
}];
23+
24+
countlyGraphNotesCommon.drawer = countlyVue.views.create({
25+
template: CV.T('/core/notes/templates/annotationDrawer.html'),
26+
data: function() {
27+
return {
28+
noteTypes: [{label: "Private", value: "private"}, {label: "Shared", value: "shared"}, {label: "Public", value: "public"}],
29+
colorTag: countlyGraphNotesCommon.COLOR_TAGS,
30+
defaultTag: {
31+
value: 1,
32+
label: "#39C0C8"
33+
}
34+
};
35+
},
36+
props: {
37+
settings: Object,
38+
controls: Object
39+
},
40+
methods: {
41+
onSubmit: function(doc) {
42+
var self = this;
43+
countlyGraphNotes.save(doc, function(res) {
44+
if (res.result === "success") {
45+
CountlyHelpers.notify({
46+
type: 'success',
47+
message: CV.i18n('common.success')
48+
});
49+
}
50+
else {
51+
CountlyHelpers.notify({
52+
message: CV.i18n('common.error')
53+
});
54+
}
55+
self.$emit("cly-refresh", true);
56+
});
57+
},
58+
onOpen: function() {
59+
countlyCommon.getGraphNotes([countlyCommon.ACTIVE_APP_ID]);
60+
}
61+
},
62+
});
63+
64+
})(window.countlyGraphNotesCommon = window.countlyGraphNotesCommon || {});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/* globals countlyCommon, $, CountlyHelpers*/
2+
(function(countlyGraphNotes) {
3+
countlyGraphNotes.save = function(data, callback) {
4+
var args = {
5+
note: data.note,
6+
ts: data.ts,
7+
noteType: data.noteType,
8+
color: data.color.value,
9+
category: data.category,
10+
};
11+
12+
if (data.noteType === 'shared') {
13+
args.emails = data.emails;
14+
}
15+
16+
if (data._id) {
17+
args._id = data._id;
18+
}
19+
else {
20+
var notes = null; //window.countlyGlobal.apps[countlyCommon.ACTIVE_APP_ID].notes;
21+
countlyCommon.getGraphNotes([countlyCommon.ACTIVE_APP_ID], {}).then(function(res) {
22+
notes = res.aaData;
23+
24+
if (notes.length > 0) {
25+
var sortedNotes = notes.sort(function(a, b) {
26+
return new Date(b.created_at) - new Date(a.created_at);
27+
});
28+
if (typeof sortedNotes[0].indicator !== "undefined") {
29+
args.indicator = CountlyHelpers.stringIncrement(sortedNotes[0].indicator);
30+
}
31+
else {
32+
args.indicator = "A";
33+
}
34+
}
35+
else {
36+
args.indicator = "A";
37+
}
38+
39+
return $.ajax({
40+
type: "POST",
41+
url: countlyCommon.API_PARTS.data.w + '/notes/save',
42+
data: {
43+
args: JSON.stringify(args),
44+
app_id: countlyCommon.ACTIVE_APP_ID,
45+
},
46+
dataType: "json",
47+
success: function() {
48+
if (callback) {
49+
callback({result: "success"});
50+
}
51+
},
52+
error: function() {
53+
if (callback) {
54+
callback({result: "error"});
55+
}
56+
}
57+
});
58+
});
59+
}
60+
};
61+
countlyGraphNotes.delete = function(noteId, callback) {
62+
return $.ajax({
63+
type: "GET",
64+
url: countlyCommon.API_PARTS.data.w + '/notes/delete',
65+
data: {
66+
app_id: countlyCommon.ACTIVE_APP_ID,
67+
note_id: noteId,
68+
},
69+
dataType: "json",
70+
success: function() {
71+
if (callback) {
72+
callback({result: "success"});
73+
}
74+
},
75+
error: function() {
76+
if (callback) {
77+
callback({result: "error"});
78+
}
79+
}
80+
});
81+
};
82+
}(window.countlyGraphNotes = window.countlyGraphNotes || {}));

0 commit comments

Comments
 (0)