@solidxai/core 0.1.6-beta.2 → 0.1.6-beta.5
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/dist/entities/chatter-message-details.entity.d.ts +1 -0
- package/dist/entities/chatter-message-details.entity.d.ts.map +1 -1
- package/dist/entities/chatter-message-details.entity.js +5 -1
- package/dist/entities/chatter-message-details.entity.js.map +1 -1
- package/dist/entities/common.entity.js +1 -1
- package/dist/entities/common.entity.js.map +1 -1
- package/dist/entities/legacy-common.entity.d.ts.map +1 -1
- package/dist/entities/legacy-common.entity.js +1 -1
- package/dist/entities/legacy-common.entity.js.map +1 -1
- package/dist/interfaces.d.ts +4 -1
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +73 -3
- package/dist/services/authentication.service.d.ts.map +1 -1
- package/dist/services/authentication.service.js +16 -12
- package/dist/services/authentication.service.js.map +1 -1
- package/dist/services/chatter-message.service.d.ts +0 -1
- package/dist/services/chatter-message.service.d.ts.map +1 -1
- package/dist/services/chatter-message.service.js +22 -19
- package/dist/services/chatter-message.service.js.map +1 -1
- package/dist/services/dashboard-question.service.d.ts +4 -0
- package/dist/services/dashboard-question.service.d.ts.map +1 -1
- package/dist/services/dashboard-question.service.js +22 -8
- package/dist/services/dashboard-question.service.js.map +1 -1
- package/dist/services/model-metadata.service.d.ts.map +1 -1
- package/dist/services/model-metadata.service.js +101 -6
- package/dist/services/model-metadata.service.js.map +1 -1
- package/dist/services/question-data-providers/chartjs-sql-data-provider.service.d.ts +2 -4
- package/dist/services/question-data-providers/chartjs-sql-data-provider.service.d.ts.map +1 -1
- package/dist/services/question-data-providers/chartjs-sql-data-provider.service.js +2 -1
- package/dist/services/question-data-providers/chartjs-sql-data-provider.service.js.map +1 -1
- package/dist/services/question-data-providers/interfaces.d.ts +1 -0
- package/dist/services/question-data-providers/interfaces.d.ts.map +1 -0
- package/dist/services/question-data-providers/interfaces.js +1 -0
- package/dist/services/question-data-providers/interfaces.js.map +1 -0
- package/dist/services/question-data-providers/prime-react-datatable-sql-data-provider.service.d.ts +2 -5
- package/dist/services/question-data-providers/prime-react-datatable-sql-data-provider.service.d.ts.map +1 -1
- package/dist/services/question-data-providers/prime-react-datatable-sql-data-provider.service.js +2 -1
- package/dist/services/question-data-providers/prime-react-datatable-sql-data-provider.service.js.map +1 -1
- package/dist/services/question-data-providers/prime-react-meter-group-sql-data-provider.service.d.ts +2 -5
- package/dist/services/question-data-providers/prime-react-meter-group-sql-data-provider.service.d.ts.map +1 -1
- package/dist/services/question-data-providers/prime-react-meter-group-sql-data-provider.service.js +2 -1
- package/dist/services/question-data-providers/prime-react-meter-group-sql-data-provider.service.js.map +1 -1
- package/dist/services/queues/database-subscriber.service.d.ts +4 -2
- package/dist/services/queues/database-subscriber.service.d.ts.map +1 -1
- package/dist/services/queues/database-subscriber.service.js +9 -1
- package/dist/services/queues/database-subscriber.service.js.map +1 -1
- package/dist/services/queues/publisher-factory.service.d.ts.map +1 -1
- package/dist/services/queues/publisher-factory.service.js +4 -6
- package/dist/services/queues/publisher-factory.service.js.map +1 -1
- package/dist/services/queues/rabbitmq-subscriber.service.d.ts +4 -2
- package/dist/services/queues/rabbitmq-subscriber.service.d.ts.map +1 -1
- package/dist/services/queues/rabbitmq-subscriber.service.js +9 -1
- package/dist/services/queues/rabbitmq-subscriber.service.js.map +1 -1
- package/dist/services/selection-providers/list-of-dashboard-question-providers-selection-provider.service.d.ts.map +1 -1
- package/dist/services/selection-providers/list-of-dashboard-question-providers-selection-provider.service.js +4 -1
- package/dist/services/selection-providers/list-of-dashboard-question-providers-selection-provider.service.js.map +1 -1
- package/dist/transformers/typeorm/local-date-time-transformer.d.ts +4 -4
- package/dist/transformers/typeorm/local-date-time-transformer.d.ts.map +1 -1
- package/dist/transformers/typeorm/local-date-time-transformer.js +25 -28
- package/dist/transformers/typeorm/local-date-time-transformer.js.map +1 -1
- package/package.json +1 -1
- package/src/entities/chatter-message-details.entity.ts +3 -0
- package/src/entities/common.entity.ts +2 -2
- package/src/entities/legacy-common.entity.ts +3 -4
- package/src/interfaces.ts +7 -1
- package/src/seeders/seed-data/solid-core-metadata.json +73 -3
- package/src/services/authentication.service.ts +18 -14
- package/src/services/chatter-message.service.ts +21 -21
- package/src/services/dashboard-question.service.ts +23 -4
- package/src/services/model-metadata.service.ts +109 -7
- package/src/services/question-data-providers/chartjs-sql-data-provider.service.ts +3 -7
- package/src/services/question-data-providers/interfaces.ts +0 -0
- package/src/services/question-data-providers/prime-react-datatable-sql-data-provider.service.ts +4 -8
- package/src/services/question-data-providers/prime-react-meter-group-sql-data-provider.service.ts +4 -8
- package/src/services/queues/database-subscriber.service.ts +12 -1
- package/src/services/queues/publisher-factory.service.ts +8 -6
- package/src/services/queues/rabbitmq-subscriber.service.ts +12 -1
- package/src/services/selection-providers/list-of-dashboard-question-providers-selection-provider.service.ts +4 -1
- package/src/transformers/typeorm/local-date-time-transformer.ts +41 -33
|
@@ -225,6 +225,7 @@ export class ModelMetadataService {
|
|
|
225
225
|
let userKeyField = null;
|
|
226
226
|
const listViewLayout = [];
|
|
227
227
|
const formViewLayout = [];
|
|
228
|
+
const treeViewLayout = [];
|
|
228
229
|
|
|
229
230
|
for (let k = 0; k < fieldsMetadata.length; k++) {
|
|
230
231
|
const fieldMetadata = fieldsMetadata[k];
|
|
@@ -245,6 +246,7 @@ export class ModelMetadataService {
|
|
|
245
246
|
}
|
|
246
247
|
listViewLayout.push({ type: "field", attrs: { name: `${affectedField.name}` } })
|
|
247
248
|
formViewLayout.push({ type: "field", attrs: { name: `${affectedField.name}` } })
|
|
249
|
+
treeViewLayout.push({ type: "field", attrs: { name: `${affectedField.name}` } })
|
|
248
250
|
|
|
249
251
|
}
|
|
250
252
|
|
|
@@ -818,6 +820,7 @@ export class ModelMetadataService {
|
|
|
818
820
|
const metaData = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(filePath);
|
|
819
821
|
|
|
820
822
|
const listViewLayoutFields = [{ type: "field", attrs: { name: `id` } }];
|
|
823
|
+
const treeViewLayoutFields = [{ type: "field", attrs: { name: `id` } }];
|
|
821
824
|
const formViewLayoutFields = [];
|
|
822
825
|
|
|
823
826
|
for (let i = 0; i < model.fields.length; i++) {
|
|
@@ -825,8 +828,9 @@ export class ModelMetadataService {
|
|
|
825
828
|
if (field.isSystem) continue;
|
|
826
829
|
listViewLayoutFields.push({ type: "field", attrs: { name: `${field.name}` } })
|
|
827
830
|
formViewLayoutFields.push({ type: "field", attrs: { name: `${field.name}` } })
|
|
831
|
+
treeViewLayoutFields.push({ type: "field", attrs: { name: `${field.name}` } })
|
|
828
832
|
}
|
|
829
|
-
this.populateVAMConfigInFileInternal(formViewLayoutFields, model, listViewLayoutFields, metaData);
|
|
833
|
+
this.populateVAMConfigInFileInternal(formViewLayoutFields, model, listViewLayoutFields, treeViewLayoutFields, metaData);
|
|
830
834
|
// Write the updated object back to the file
|
|
831
835
|
const updatedContent = JSON.stringify(metaData, null, 2);
|
|
832
836
|
await fs.writeFile(filePath, updatedContent);
|
|
@@ -839,7 +843,7 @@ export class ModelMetadataService {
|
|
|
839
843
|
}
|
|
840
844
|
|
|
841
845
|
// Populate the View, Actions and Menus in the config file
|
|
842
|
-
private populateVAMConfigInFileInternal(formViewLayoutFields: any[], model: ModelMetadata, listViewLayoutFields: { type: string; attrs: { name: string; }; }[], metaData: any) {
|
|
846
|
+
private populateVAMConfigInFileInternal(formViewLayoutFields: any[], model: ModelMetadata, listViewLayoutFields: { type: string; attrs: { name: string; }; }[], treeViewLayoutFields: { type: string; attrs: { name: string; }; }[], metaData: any) {
|
|
843
847
|
const column1Fields = [];
|
|
844
848
|
const column2Fields = [];
|
|
845
849
|
|
|
@@ -852,7 +856,9 @@ export class ModelMetadataService {
|
|
|
852
856
|
}
|
|
853
857
|
}
|
|
854
858
|
const actionName = `${model.singularName}-list-action`;
|
|
855
|
-
const
|
|
859
|
+
const treeViewActionName = `${model.singularName}-tree-view-action`;
|
|
860
|
+
const listViewName = `${model.singularName}-list-view`;
|
|
861
|
+
const treeViewName = `${model.singularName}-tree-view`;
|
|
856
862
|
const formViewName = `${model.singularName}-form-view`;
|
|
857
863
|
const menuName = `${model.singularName}-menu-item`;
|
|
858
864
|
|
|
@@ -865,7 +871,21 @@ export class ModelMetadataService {
|
|
|
865
871
|
customComponent: ``,
|
|
866
872
|
customIsModal: true,
|
|
867
873
|
serverEndpoint: "",
|
|
868
|
-
viewUserKey:
|
|
874
|
+
viewUserKey: listViewName,
|
|
875
|
+
moduleUserKey: `${model.module.name}`,
|
|
876
|
+
modelUserKey: `${model.singularName}`
|
|
877
|
+
};
|
|
878
|
+
|
|
879
|
+
const treeViewAction = {
|
|
880
|
+
displayName: `${model.displayName} Tree View Action`,
|
|
881
|
+
name: treeViewActionName,
|
|
882
|
+
type: "solid",
|
|
883
|
+
domain: "",
|
|
884
|
+
context: "",
|
|
885
|
+
customComponent: ``,
|
|
886
|
+
customIsModal: true,
|
|
887
|
+
serverEndpoint: "",
|
|
888
|
+
viewUserKey: treeViewName,
|
|
869
889
|
moduleUserKey: `${model.module.name}`,
|
|
870
890
|
modelUserKey: `${model.singularName}`
|
|
871
891
|
};
|
|
@@ -877,11 +897,11 @@ export class ModelMetadataService {
|
|
|
877
897
|
actionUserKey: actionName,
|
|
878
898
|
moduleUserKey: `${model.module.name}`,
|
|
879
899
|
parentMenuItemUserKey: "",
|
|
880
|
-
iconName
|
|
900
|
+
iconName: ""
|
|
881
901
|
};
|
|
882
902
|
|
|
883
903
|
const modelListview = {
|
|
884
|
-
name:
|
|
904
|
+
name: listViewName,
|
|
885
905
|
displayName: `${model.displayName}`,
|
|
886
906
|
type: "list",
|
|
887
907
|
context: "{}",
|
|
@@ -905,6 +925,31 @@ export class ModelMetadataService {
|
|
|
905
925
|
}
|
|
906
926
|
};
|
|
907
927
|
|
|
928
|
+
const modelTreeview = {
|
|
929
|
+
name: treeViewName,
|
|
930
|
+
displayName: `${model.displayName}`,
|
|
931
|
+
type: "tree",
|
|
932
|
+
context: "{}",
|
|
933
|
+
moduleUserKey: `${model.module.name}`,
|
|
934
|
+
modelUserKey: `${model.singularName}`,
|
|
935
|
+
layout: {
|
|
936
|
+
type: "tree",
|
|
937
|
+
attrs: {
|
|
938
|
+
pagination: true,
|
|
939
|
+
pageSizeOptions: [
|
|
940
|
+
10,
|
|
941
|
+
25,
|
|
942
|
+
50
|
|
943
|
+
],
|
|
944
|
+
enableGlobalSearch: true,
|
|
945
|
+
create: true,
|
|
946
|
+
edit: true,
|
|
947
|
+
delete: true
|
|
948
|
+
},
|
|
949
|
+
children: treeViewLayoutFields
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
|
|
908
953
|
|
|
909
954
|
const modelFormView = {
|
|
910
955
|
name: formViewName,
|
|
@@ -954,10 +999,18 @@ export class ModelMetadataService {
|
|
|
954
999
|
metaData.actions.push(action);
|
|
955
1000
|
}
|
|
956
1001
|
|
|
957
|
-
if (notExists(metaData.
|
|
1002
|
+
if (notExists(metaData.actions, treeViewActionName)) {
|
|
1003
|
+
metaData.actions.push(treeViewAction);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
if (notExists(metaData.views, listViewName)) {
|
|
958
1007
|
metaData.views.push(modelListview);
|
|
959
1008
|
}
|
|
960
1009
|
|
|
1010
|
+
if (notExists(metaData.views, treeViewName)) {
|
|
1011
|
+
metaData.views.push(modelTreeview);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
961
1014
|
if (notExists(metaData.views, formViewName)) {
|
|
962
1015
|
metaData.views.push(modelFormView);
|
|
963
1016
|
}
|
|
@@ -979,6 +1032,14 @@ export class ModelMetadataService {
|
|
|
979
1032
|
}
|
|
980
1033
|
}));
|
|
981
1034
|
|
|
1035
|
+
const treeViewLayout = jsonFieldsList.map(field => ({
|
|
1036
|
+
type: "field",
|
|
1037
|
+
attrs: {
|
|
1038
|
+
name: `${field.name}`,
|
|
1039
|
+
isSearchable: true,
|
|
1040
|
+
}
|
|
1041
|
+
}));
|
|
1042
|
+
|
|
982
1043
|
const formViewLayout = jsonFieldsList.map(field => ({
|
|
983
1044
|
type: "field",
|
|
984
1045
|
attrs: {
|
|
@@ -1019,6 +1080,26 @@ export class ModelMetadataService {
|
|
|
1019
1080
|
children: listViewLayout
|
|
1020
1081
|
}, null, 3)
|
|
1021
1082
|
},
|
|
1083
|
+
{
|
|
1084
|
+
name: `${model.singularName}-tree-view`,
|
|
1085
|
+
displayName: `${model.displayName}`,
|
|
1086
|
+
type: 'tree',
|
|
1087
|
+
context: "{}",
|
|
1088
|
+
module: resolvedModule,
|
|
1089
|
+
model: model,
|
|
1090
|
+
layout: JSON.stringify({
|
|
1091
|
+
type: "tree",
|
|
1092
|
+
attrs: {
|
|
1093
|
+
pagination: true,
|
|
1094
|
+
pageSizeOptions: [10, 25, 50],
|
|
1095
|
+
enableGlobalSearch: true,
|
|
1096
|
+
create: true,
|
|
1097
|
+
edit: true,
|
|
1098
|
+
delete: true
|
|
1099
|
+
},
|
|
1100
|
+
children: treeViewLayout
|
|
1101
|
+
}, null, 3)
|
|
1102
|
+
},
|
|
1022
1103
|
{
|
|
1023
1104
|
name: `${model.singularName}-form-view`,
|
|
1024
1105
|
displayName: `${model.displayName}`,
|
|
@@ -1067,6 +1148,7 @@ export class ModelMetadataService {
|
|
|
1067
1148
|
}
|
|
1068
1149
|
|
|
1069
1150
|
let view = await viewRepo.findOne({ where: { name: `${model.singularName}-list-view` } });
|
|
1151
|
+
let treeView = await viewRepo.findOne({ where: { name: `${model.singularName}-tree-view` } });
|
|
1070
1152
|
|
|
1071
1153
|
const actionData = {
|
|
1072
1154
|
displayName: `${model.displayName} List Action`,
|
|
@@ -1082,13 +1164,33 @@ export class ModelMetadataService {
|
|
|
1082
1164
|
model: model
|
|
1083
1165
|
};
|
|
1084
1166
|
|
|
1167
|
+
const treeViewActionData = {
|
|
1168
|
+
displayName: `${model.displayName} Tree View Action`,
|
|
1169
|
+
name: `${model.singularName}-tree-view-action`,
|
|
1170
|
+
type: "solid",
|
|
1171
|
+
domain: "",
|
|
1172
|
+
context: "",
|
|
1173
|
+
customComponent: ``,
|
|
1174
|
+
customIsModal: true,
|
|
1175
|
+
serverEndpoint: "",
|
|
1176
|
+
view: treeView,
|
|
1177
|
+
module: resolvedModule,
|
|
1178
|
+
model: model
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1085
1181
|
let existingAction = await actionRepo.findOne({ where: { name: actionData.name } });
|
|
1182
|
+
let existingTreeViewAction = await actionRepo.findOne({ where: { name: treeViewActionData.name } });
|
|
1086
1183
|
|
|
1087
1184
|
if (!existingAction) {
|
|
1088
1185
|
const createdAction = actionRepo.create(actionData);
|
|
1089
1186
|
existingAction = await actionRepo.save(createdAction);
|
|
1090
1187
|
}
|
|
1091
1188
|
|
|
1189
|
+
if (!existingTreeViewAction) {
|
|
1190
|
+
const createdTreeViewAction = actionRepo.create(treeViewActionData);
|
|
1191
|
+
existingTreeViewAction = await actionRepo.save(createdTreeViewAction);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1092
1194
|
const adminRole = await this.roleService.findRoleByName('Admin');
|
|
1093
1195
|
|
|
1094
1196
|
const menuData = {
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import { Injectable, Logger } from "@nestjs/common";
|
|
2
2
|
import { DashboardQuestionDataProvider } from "src/decorators/dashboard-question-data-provider.decorator";
|
|
3
3
|
import { DashboardQuestion } from "src/entities/dashboard-question.entity";
|
|
4
|
-
import { IDashboardQuestionDataProvider } from "src/interfaces";
|
|
4
|
+
import { IDashboardQuestionDataProvider, QuestionSqlDataProviderContext } from "src/interfaces";
|
|
5
5
|
import { EntityManager } from "typeorm";
|
|
6
6
|
import { SqlExpressionResolverService } from "../sql-expression-resolver.service";
|
|
7
7
|
import { getKpi, getLabels } from "./helpers";
|
|
8
8
|
|
|
9
|
-
export interface QuestionSqlDataProviderContext {
|
|
10
|
-
// questionSqlDatasetConfig: QuestionSqlDatasetConfig;
|
|
11
|
-
// questionId: number;
|
|
12
|
-
// question: Question;
|
|
13
|
-
}
|
|
14
9
|
|
|
15
10
|
export enum SqlExpressionOperator {
|
|
16
11
|
EQUALS = '$equals',
|
|
@@ -49,7 +44,8 @@ export class ChartJsSqlDataProvider implements IDashboardQuestionDataProvider<Qu
|
|
|
49
44
|
return "ChartJsSqlDataProvider";
|
|
50
45
|
}
|
|
51
46
|
|
|
52
|
-
async getData(question: DashboardQuestion,
|
|
47
|
+
async getData(question: DashboardQuestion, context?: QuestionSqlDataProviderContext): Promise<any> {
|
|
48
|
+
const expressions: SqlExpression[] = context?.expressions || [];
|
|
53
49
|
// TODO: put some validation to check if the results of each SQL in each dataset returns the same number of rows
|
|
54
50
|
|
|
55
51
|
// This is what we have to return.
|
|
File without changes
|
package/src/services/question-data-providers/prime-react-datatable-sql-data-provider.service.ts
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import { Injectable } from "@nestjs/common";
|
|
2
2
|
import { DashboardQuestionDataProvider } from "src/decorators/dashboard-question-data-provider.decorator";
|
|
3
3
|
import { DashboardQuestion } from "src/entities/dashboard-question.entity";
|
|
4
|
-
import { IDashboardQuestionDataProvider } from "src/interfaces";
|
|
4
|
+
import { IDashboardQuestionDataProvider, QuestionSqlDataProviderContext } from "src/interfaces";
|
|
5
5
|
import { EntityManager } from "typeorm";
|
|
6
6
|
import { SqlExpressionResolverService } from "../sql-expression-resolver.service";
|
|
7
7
|
import { Logger } from '@nestjs/common';
|
|
8
8
|
import { SqlExpression } from "./chartjs-sql-data-provider.service";
|
|
9
9
|
import { getKpi } from "./helpers";
|
|
10
10
|
|
|
11
|
-
export interface QuestionSqlDataProviderContext {
|
|
12
|
-
// questionSqlDatasetConfig: QuestionSqlDatasetConfig;
|
|
13
|
-
// questionId: number;
|
|
14
|
-
// question: Question;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
11
|
@DashboardQuestionDataProvider()
|
|
18
12
|
@Injectable()
|
|
19
13
|
export class PrimeReactDatatableSqlDataProvider implements IDashboardQuestionDataProvider<QuestionSqlDataProviderContext, any> {
|
|
@@ -29,7 +23,9 @@ export class PrimeReactDatatableSqlDataProvider implements IDashboardQuestionDat
|
|
|
29
23
|
return "PrimeReactDatatableSqlDataProvider";
|
|
30
24
|
}
|
|
31
25
|
|
|
32
|
-
async getData(question: DashboardQuestion,
|
|
26
|
+
async getData(question: DashboardQuestion, context?: QuestionSqlDataProviderContext): Promise<any> {
|
|
27
|
+
const expressions: SqlExpression[] = context?.expressions || [];
|
|
28
|
+
|
|
33
29
|
// TODO: put some validation to check if the results of each SQL in each dataset returns the same number of rows
|
|
34
30
|
|
|
35
31
|
// Check the expected response for prime react data tables to understand what is going on here...
|
package/src/services/question-data-providers/prime-react-meter-group-sql-data-provider.service.ts
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
import { Injectable } from "@nestjs/common";
|
|
2
2
|
import { DashboardQuestionDataProvider } from "src/decorators/dashboard-question-data-provider.decorator";
|
|
3
3
|
import { DashboardQuestion } from "src/entities/dashboard-question.entity";
|
|
4
|
-
import { IDashboardQuestionDataProvider } from "src/interfaces";
|
|
4
|
+
import { IDashboardQuestionDataProvider, QuestionSqlDataProviderContext } from "src/interfaces";
|
|
5
5
|
import { EntityManager } from "typeorm";
|
|
6
6
|
import { SqlExpressionResolverService } from "../sql-expression-resolver.service";
|
|
7
7
|
import { Logger } from '@nestjs/common';
|
|
8
8
|
import { SqlExpression } from "./chartjs-sql-data-provider.service";
|
|
9
9
|
import { getKpi } from "./helpers";
|
|
10
10
|
|
|
11
|
-
export interface QuestionSqlDataProviderContext {
|
|
12
|
-
// questionSqlDatasetConfig: QuestionSqlDatasetConfig;
|
|
13
|
-
// questionId: number;
|
|
14
|
-
// question: Question;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
11
|
@DashboardQuestionDataProvider()
|
|
18
12
|
@Injectable()
|
|
19
13
|
export class PrimeReactMeterGroupSqlDataProvider implements IDashboardQuestionDataProvider<QuestionSqlDataProviderContext, any> {
|
|
@@ -58,7 +52,9 @@ export class PrimeReactMeterGroupSqlDataProvider implements IDashboardQuestionDa
|
|
|
58
52
|
return colors;
|
|
59
53
|
}
|
|
60
54
|
|
|
61
|
-
async getData(question: DashboardQuestion,
|
|
55
|
+
async getData(question: DashboardQuestion, context?: QuestionSqlDataProviderContext): Promise<any> {
|
|
56
|
+
const expressions: SqlExpression[] = context?.expressions || [];
|
|
57
|
+
|
|
62
58
|
// TODO: put some validation to check if the results of each SQL in each dataset returns the same number of rows
|
|
63
59
|
|
|
64
60
|
// This is what we have to return.
|
|
@@ -7,7 +7,7 @@ import { PollerService } from '../poller.service';
|
|
|
7
7
|
import { buildNamespacedQueueName } from './common';
|
|
8
8
|
|
|
9
9
|
export abstract class DatabaseSubscriber<T> implements OnModuleInit, QueueSubscriber<T> {
|
|
10
|
-
private
|
|
10
|
+
private _loggerInstance?: Logger;
|
|
11
11
|
private readonly url: string;
|
|
12
12
|
private readonly serviceRole: string;
|
|
13
13
|
|
|
@@ -23,6 +23,17 @@ export abstract class DatabaseSubscriber<T> implements OnModuleInit, QueueSubscr
|
|
|
23
23
|
// this.logger.debug(`DatabaseSubscriber instance created with options: ${JSON.stringify(this.options())}`);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
protected get loggerContext(): string {
|
|
27
|
+
return this.constructor.name;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
protected get logger(): Logger {
|
|
31
|
+
if (!this._loggerInstance) {
|
|
32
|
+
this._loggerInstance = new Logger(this.loggerContext);
|
|
33
|
+
}
|
|
34
|
+
return this._loggerInstance;
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
abstract subscribe(message: QueueMessage<T>);
|
|
27
38
|
|
|
28
39
|
abstract options(): QueuesModuleOptions;
|
|
@@ -23,14 +23,16 @@ export class PublisherFactory<T> {
|
|
|
23
23
|
// Register all ISolidDatabaseModules implementations
|
|
24
24
|
let actualPublisherToUse = this.solidIntrospectionService.getProvider(resolvedPublisherName);
|
|
25
25
|
if (!actualPublisherToUse) {
|
|
26
|
+
// Relaxed extra check in place to make sure we do not have to refactor old publishers or publishers named without the ____RabbitMq or ____Database convention
|
|
27
|
+
actualPublisherToUse = this.solidIntrospectionService.getProvider(publisherName);
|
|
26
28
|
|
|
27
29
|
// Extra check in place to make sure we do not have to refactor old publishers which have been created earlier.
|
|
28
|
-
if (defaultBrokerToUse === 'rabbitmq') {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
30
|
+
// if (defaultBrokerToUse === 'rabbitmq') {
|
|
31
|
+
// actualPublisherToUse = this.solidIntrospectionService.getProvider(publisherName);
|
|
32
|
+
// }
|
|
33
|
+
}
|
|
34
|
+
if (!actualPublisherToUse) {
|
|
35
|
+
throw new Error(`Unable to locate publisher with name ${resolvedPublisherName}`);
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
// type safe
|
|
@@ -8,7 +8,7 @@ import { buildNamespacedQueueName } from './common';
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscriber<T> { // TODO This can be made a generic type for better type visibility
|
|
11
|
-
private
|
|
11
|
+
private _loggerInstance?: Logger;
|
|
12
12
|
private readonly url: string;
|
|
13
13
|
private readonly serviceRole: string;
|
|
14
14
|
private connection: amqp.Connection | null = null;
|
|
@@ -30,6 +30,17 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
|
|
|
30
30
|
// this.logger.debug(`RabbitMqSubscriber instance created with options: ${JSON.stringify(this.options())} and url: ${this.url}`);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
protected get loggerContext(): string {
|
|
34
|
+
return this.constructor.name;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
protected get logger(): Logger {
|
|
38
|
+
if (!this._loggerInstance) {
|
|
39
|
+
this._loggerInstance = new Logger(this.loggerContext);
|
|
40
|
+
}
|
|
41
|
+
return this._loggerInstance;
|
|
42
|
+
}
|
|
43
|
+
|
|
33
44
|
abstract subscribe(message: QueueMessage<T>);
|
|
34
45
|
|
|
35
46
|
abstract options(): QueuesModuleOptions;
|
|
@@ -3,6 +3,7 @@ import { SelectionProvider } from "src/decorators/selection-provider.decorator";
|
|
|
3
3
|
import { SolidRegistry } from "src/helpers/solid-registry";
|
|
4
4
|
import { IDashboardQuestionDataProvider, IDashboardVariableSelectionProvider, ISelectionProvider, ISelectionProviderContext, ISelectionProviderValues } from "../../interfaces";
|
|
5
5
|
import { SQL_DYNAMIC_PROVIDER_NAME } from "../dashboard.service";
|
|
6
|
+
import { CHARTJS_SQL_DATA_PROVIDER_NAME, INBUILT_SQL_DATA_PROVIDERS, PRIME_REACT_DATATABLE_SQL_DATA_PROVIDER_NAME, PRIME_REACT_METER_GROUP_SQL_DATA_PROVIDER_NAME } from "../dashboard-question.service";
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
@SelectionProvider()
|
|
@@ -34,7 +35,9 @@ export class ListOfDashboardQuestionProvidersSelectionProvider implements ISelec
|
|
|
34
35
|
async values(query: string, ctxt: ISelectionProviderContext): Promise<readonly ISelectionProviderValues[]> {
|
|
35
36
|
const dashboardSelectionProviders = this.solidRegistry.getDashboardQuestionDataProviders()
|
|
36
37
|
//Exclude the SQL dynamic provider from the list, (since although it is a dashboard selection provider, it is not a valid option for the user to select)
|
|
37
|
-
return dashboardSelectionProviders
|
|
38
|
+
return dashboardSelectionProviders
|
|
39
|
+
.filter(provider => !INBUILT_SQL_DATA_PROVIDERS.includes(provider.name()))
|
|
40
|
+
.map(i => {
|
|
38
41
|
return { label: i.name, value: i.name };
|
|
39
42
|
});
|
|
40
43
|
}
|
|
@@ -20,59 +20,67 @@ function dateToUtcComponentString(d: Date): string {
|
|
|
20
20
|
const ss = pad(d.getUTCSeconds());
|
|
21
21
|
const ms = pad(d.getUTCMilliseconds(), 3);
|
|
22
22
|
|
|
23
|
-
// A
|
|
23
|
+
// A "naive" timestamp string representing the DB wall-clock components
|
|
24
24
|
return `${yyyy}-${mm}-${dd} ${hh}:${mi}:${ss}.${ms}`;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
function getWallClockConfig(): { tz: string; wallTimeMode: boolean } {
|
|
28
|
+
return {
|
|
29
|
+
tz: process.env.SOLIDX_WALL_TIME_TIMEZONE || process.env.SOLIDX_TIMEZONE || "UTC",
|
|
30
|
+
wallTimeMode: (process.env.SOLIDX_TIME_STORED_AS_WALL_TIME || "").toLowerCase() === "true",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns a dayjs instance positioned at the wall-clock time for the given Date.
|
|
36
|
+
* - Wall-clock mode ON: dayjs in the configured timezone (components = wall-clock components)
|
|
37
|
+
* - Wall-clock mode OFF: dayjs in UTC
|
|
38
|
+
* Counterpart to serializeDate — use this to format/display a date value correctly.
|
|
39
|
+
*/
|
|
40
|
+
export function parseDate(date: Date): dayjs.Dayjs {
|
|
41
|
+
const { tz, wallTimeMode } = getWallClockConfig();
|
|
42
|
+
if (!wallTimeMode) return dayjs.utc(date);
|
|
43
|
+
return dayjs(date).tz(tz);
|
|
44
|
+
}
|
|
30
45
|
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Converts a Date to a string for storage in plain text columns (e.g. audit values).
|
|
48
|
+
* - Wall-clock mode ON: "YYYY-MM-DD HH:mm:ss.SSS" in the configured timezone (no Z suffix)
|
|
49
|
+
* - Wall-clock mode OFF: ISO 8601 UTC string with Z suffix
|
|
50
|
+
* The presence/absence of the Z suffix lets consumers distinguish the two cases.
|
|
51
|
+
*/
|
|
52
|
+
export function serializeDate(date: Date): string {
|
|
53
|
+
const { wallTimeMode } = getWallClockConfig();
|
|
54
|
+
if (!wallTimeMode) return date.toISOString();
|
|
55
|
+
return parseDate(date).format("YYYY-MM-DD HH:mm:ss.SSS");
|
|
56
|
+
}
|
|
33
57
|
|
|
34
|
-
|
|
58
|
+
export const LocalDateTimeTransformer: ValueTransformer = {
|
|
59
|
+
// DB -> Entity
|
|
60
|
+
from(value: Date | string | null | undefined): Date | null | undefined {
|
|
61
|
+
// critical... super important to return undefined here
|
|
35
62
|
if (value === undefined) return undefined;
|
|
36
63
|
if (value === null) return null;
|
|
37
64
|
|
|
38
|
-
|
|
65
|
+
const { tz, wallTimeMode } = getWallClockConfig();
|
|
66
|
+
|
|
67
|
+
if (!wallTimeMode) {
|
|
39
68
|
return dayjs(value).toDate();
|
|
40
69
|
}
|
|
41
70
|
|
|
42
71
|
const naive = value instanceof Date ? dateToUtcComponentString(value) : String(value);
|
|
43
|
-
return dayjs.tz(naive,
|
|
72
|
+
return dayjs.tz(naive, tz).utc().toDate();
|
|
44
73
|
},
|
|
45
74
|
|
|
46
|
-
// Entity
|
|
75
|
+
// Entity -> DB
|
|
47
76
|
to(value: Date | null | undefined): Date | null | undefined {
|
|
48
|
-
|
|
49
|
-
const SOLIDX_WALL_TIME_TZ = process.env.SOLIDX_WALL_TIME_TIMEZONE || process.env.SOLIDX_TIMEZONE || "UTC";
|
|
50
|
-
const SOLIDX_TIME_STORED_AS_WALL_TIME = (process.env.SOLIDX_TIME_STORED_AS_WALL_TIME || "").toLowerCase() === "true";
|
|
51
|
-
|
|
52
|
-
// critical... super important to return undefined here
|
|
77
|
+
// critical... super important to return undefined here
|
|
53
78
|
if (value === undefined) return undefined;
|
|
54
79
|
if (value === null) return null;
|
|
55
80
|
|
|
56
|
-
|
|
57
|
-
return dayjs(value).toDate();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const wallTimeStr = dayjs(value).tz(SOLIDX_WALL_TIME_TZ).format("YYYY-MM-DD HH:mm:ss.SSS");
|
|
81
|
+
const wallTimeStr = serializeDate(value);
|
|
61
82
|
return dayjs.utc(wallTimeStr).toDate();
|
|
62
83
|
},
|
|
63
84
|
|
|
64
|
-
utc: {
|
|
65
|
-
from(value: Date | string | null | undefined): Date | null | undefined {
|
|
66
|
-
if (value === undefined) return undefined;
|
|
67
|
-
if (value === null) return null;
|
|
68
|
-
return dayjs(value).toDate();
|
|
69
|
-
},
|
|
70
|
-
to(value: Date | null | undefined): Date | null | undefined {
|
|
71
|
-
if (value === undefined) return undefined;
|
|
72
|
-
if (value === null) return null;
|
|
73
|
-
return dayjs(value).toDate();
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
85
|
};
|
|
77
86
|
|
|
78
|
-
export const UtcDateTimeTransformer = LocalDateTimeTransformer.utc;
|