ng-kinintel 0.0.358 → 0.0.388

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.
Files changed (23) hide show
  1. package/package.json +1 -1
  2. package/src/lib/components/alert-groups/alert-groups.component.html +3 -3
  3. package/src/lib/components/alert-groups/alert-groups.component.ts +3 -1
  4. package/src/lib/components/alert-groups/edit-alert-group/edit-alert-group.component.html +1 -1
  5. package/src/lib/components/alert-groups/edit-alert-group/edit-alert-group.component.ts +4 -2
  6. package/src/lib/components/dashboards/dashboards.component.html +2 -2
  7. package/src/lib/components/dashboards/dashboards.component.ts +5 -3
  8. package/src/lib/components/dataset/dataset-editor/dataset-add-join/dataset-add-join.component.ts +1 -1
  9. package/src/lib/components/dataset/dataset-editor/dataset-editor.component.html +1 -1
  10. package/src/lib/components/datasource/create-datasource/advanced-settings/advanced-settings.component.ts +4 -0
  11. package/src/lib/components/datasource/create-datasource/api-access/api-access.component.html +86 -18
  12. package/src/lib/components/datasource/create-datasource/api-access/api-access.component.ts +2 -2
  13. package/src/lib/components/datasource/create-datasource/create-datasource.component.html +1 -1
  14. package/src/lib/components/datasource/create-datasource/create-datasource.component.ts +13 -7
  15. package/src/lib/components/datasource/create-datasource/import-data/import-data.component.ts +0 -1
  16. package/src/lib/components/datasource/create-datasource/import-data/import-wizard/import-wizard.component.ts +4 -0
  17. package/src/lib/components/datasource/document-datasource/document-datasource.component.ts +4 -0
  18. package/src/lib/components/feeds/feed/feed.component.html +47 -4
  19. package/src/lib/components/feeds/feeds.component.html +3 -3
  20. package/src/lib/components/shared-with-me/feed-api-modal/feed-api-modal.component.html +60 -0
  21. package/src/lib/components/shared-with-me/shared-with-me.component.html +5 -5
  22. package/src/lib/components/shared-with-me/shared-with-me.component.ts +18 -10
  23. package/src/lib/services/datasource.service.ts +2 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-kinintel",
3
- "version": "0.0.358",
3
+ "version": "0.0.388",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^15.2.9",
6
6
  "@angular/core": "^15.2.9"
@@ -9,7 +9,7 @@
9
9
  </div>
10
10
  </div>
11
11
  <div class="mt-6 flex flex-col-reverse justify-stretch">
12
- <button type="button" [routerLink]="['/alert-groups', 0]"
12
+ <button type="button" [routerLink]="[routePath, 0]"
13
13
  class="inline-flex items-center justify-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-primary focus:outline-none">
14
14
  Create Alert Group
15
15
  </button>
@@ -18,7 +18,7 @@
18
18
  </div>
19
19
 
20
20
  <div class="p-4" *ngIf="!alertGroups.length && !loading">
21
- <button type="button" [routerLink]="['/alert-groups', 0]"
21
+ <button type="button" [routerLink]="[routePath, 0]"
22
22
  class="relative block w-full border-2 border-gray-300 border-dashed rounded-lg p-12 text-center hover:border-gray-400 focus:outline-none">
23
23
 
24
24
  <div class="relative inline-block">
@@ -95,7 +95,7 @@
95
95
  <td class="relative whitespace-nowrap border-gray-200 py-2 px-4 text-right text-sm"
96
96
  [ngClass]="{'border-b-0': i === alertGroups.length - 1, 'border-b': i !== alertGroups.length - 1}">
97
97
  <div class="align-center justify-end">
98
- <button mat-button color="primary" [routerLink]="['/alert-groups', element.id]"> Edit
98
+ <button mat-button color="primary" [routerLink]="[routePath, element.id]"> Edit
99
99
  </button>
100
100
  <div class="divider"></div>
101
101
  <div class="divider"></div>
@@ -1,4 +1,4 @@
1
- import {Component, OnInit} from '@angular/core';
1
+ import {Component, Input, OnInit} from '@angular/core';
2
2
  import {BehaviorSubject, merge, Subject} from 'rxjs';
3
3
  import {debounceTime, map, switchMap} from 'rxjs/operators';
4
4
  import {ProjectService} from '../../../lib/services/project.service';
@@ -12,6 +12,8 @@ import moment from 'moment';
12
12
  })
13
13
  export class AlertGroupsComponent implements OnInit {
14
14
 
15
+ @Input() routePath = '/alert-groups';
16
+
15
17
  public alertGroups: any = [];
16
18
  public searchText = new BehaviorSubject('');
17
19
  public limit = new BehaviorSubject(10);
@@ -81,7 +81,7 @@
81
81
 
82
82
  <div class="pt-5">
83
83
  <div class="flex justify-end">
84
- <button type="button" [routerLink]="['/alert-groups']"
84
+ <button type="button" [routerLink]="[routePath]"
85
85
  class="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none">Cancel</button>
86
86
  <button type="button" (click)="save()" [disabled]="!alertGroup.title || (!alertGroup.taskTimePeriods || !alertGroup.taskTimePeriods.length) || (!alertGroup.notificationGroups || !alertGroup.notificationGroups.length)"
87
87
  class="disabled:opacity-50 ml-3 inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-primary focus:outline-none">
@@ -1,4 +1,4 @@
1
- import {Component, OnInit} from '@angular/core';
1
+ import {Component, Input, OnInit} from '@angular/core';
2
2
  import {NotificationService} from '../../../../lib/services/notification.service';
3
3
  import {AlertService} from '../../../../lib/services/alert.service';
4
4
  import {MatLegacyDialog as MatDialog} from '@angular/material/legacy-dialog';
@@ -14,6 +14,8 @@ import {ActivatedRoute, Router} from '@angular/router';
14
14
  })
15
15
  export class EditAlertGroupComponent implements OnInit {
16
16
 
17
+ @Input() routePath = '/alert-groups';
18
+
17
19
  public alertGroup: any = {};
18
20
  public notificationGroups: any = [];
19
21
  public showNewTaskTimePeriod = false;
@@ -66,7 +68,7 @@ export class EditAlertGroupComponent implements OnInit {
66
68
 
67
69
  public save() {
68
70
  this.alertService.saveAlertGroup(this.alertGroup).then(() => {
69
- this.router.navigate(['/alert-groups']);
71
+ this.router.navigate([this.routePath]);
70
72
  });
71
73
  }
72
74
 
@@ -91,7 +91,7 @@
91
91
  [ngClass]="{'border-b-0': i === dashboards.length - 1, 'border-b': i !== dashboards.length - 1}">
92
92
  <div class="flex flex-col">
93
93
  <div class="item-title-select flex items-center font-medium cursor-pointer hover:underline"
94
- [routerLink]="['/dashboards/view/' + element.id]">
94
+ [routerLink]="[viewURL + element.id]">
95
95
  {{element.title}}
96
96
  </div>
97
97
  <div (click)="element.viewDescription = !element.viewDescription"
@@ -110,7 +110,7 @@
110
110
  <td class="relative whitespace-nowrap border-gray-200 py-2 px-4 text-right text-sm font-medium"
111
111
  [ngClass]="{'border-b-0': i === dashboards.length - 1, 'border-b': i !== dashboards.length - 1}">
112
112
  <div class="flex items-center justify-end">
113
- <button mat-button color="primary" [routerLink]="['/dashboards/view/' + element.id]"> View</button>
113
+ <button mat-button color="primary" [routerLink]="[viewURL + element.id]"> View</button>
114
114
  <div class="divider"></div>
115
115
  <button color="primary" mat-icon-button [matMenuTriggerFor]="itemMenu">
116
116
  <mat-icon>more_vert</mat-icon>
@@ -23,6 +23,8 @@ export class DashboardsComponent implements OnInit {
23
23
  @Input() allowNew: boolean;
24
24
  @Input() admin: boolean;
25
25
  @Input() accountId: any;
26
+ @Input() viewURL = '/dashboards/view/';
27
+ @Input() editURL: string;
26
28
 
27
29
  public dashboards: any = [];
28
30
  public searchText = new BehaviorSubject('');
@@ -81,17 +83,17 @@ export class DashboardsComponent implements OnInit {
81
83
 
82
84
  public edit(id) {
83
85
  const route = _.filter(this.router.url.split('/'))[0];
84
- this.router.navigateByUrl(`${route}/${id}${this.admin ? '?a=true' : ''}`);
86
+ this.router.navigateByUrl(`${this.editURL || route}/${id}${this.admin ? '?a=true' : ''}`);
85
87
  }
86
88
 
87
89
  public copy(id) {
88
90
  const route = _.filter(this.router.url.split('/'))[0];
89
- this.router.navigateByUrl(`${route}/copy/${id}${this.admin ? '?a=true' : ''}`);
91
+ this.router.navigateByUrl(`${this.editURL || route}/copy/${id}${this.admin ? '?a=true' : ''}`);
90
92
  }
91
93
 
92
94
  public extend(id) {
93
95
  const route = _.filter(this.router.url.split('/'))[0];
94
- this.router.navigateByUrl(`${route}/extend/${id}${this.admin ? '?a=true' : ''}`);
96
+ this.router.navigateByUrl(`${this.editURL || route}/extend/${id}${this.admin ? '?a=true' : ''}`);
95
97
  }
96
98
 
97
99
  public delete(id) {
@@ -342,7 +342,7 @@ export class DatasetAddJoinComponent implements OnInit {
342
342
  filters: [{
343
343
  lhsExpression: '',
344
344
  rhsExpression: '',
345
- filterType: ''
345
+ filterType: 'eq'
346
346
  }],
347
347
  filterJunctions: []
348
348
  };
@@ -320,7 +320,7 @@
320
320
  <div class="example-list flex flex-wrap" cdkDropListGroup>
321
321
  <ng-template ngFor let-transformation [ngForOf]="terminatingTransformations" let-i="index">
322
322
  <div cdkDropList (cdkDropListDropped)="drop($event)" cdkDropListOrientation="horizontal"
323
- [cdkDropListData]="{item:transformation,index:i}">
323
+ [cdkDropListData]="{item:transformation,index:i}" *ngIf="!transformation.hidden">
324
324
  <div class="flex items-center">
325
325
  <div class="new-transformation flex items-center justify-center w-6 h-6">
326
326
  <a [matMenuTriggerFor]="addTransformation"
@@ -92,6 +92,10 @@ export class AdvancedSettingsComponent implements OnInit {
92
92
 
93
93
  public async saveChanges() {
94
94
  this.errorMessage = '';
95
+
96
+ // Map the importKey so it doesn't get wiped.
97
+ this.datasourceUpdate.importKey = this.datasourceUpdate.instanceImportKey;
98
+
95
99
  this.datasourceUpdate.indexes = _.filter(this.advancedSettings.indexes, index => {
96
100
  return index.fieldNames.length;
97
101
  });
@@ -31,63 +31,108 @@
31
31
  <div class="text-sm mb-2">
32
32
  Return the data for this datasource.
33
33
  <br><br>
34
- Filtering of the returned data can be effected by supplying parameters of the format <b>filter_COLUMNNAME</b>. The parameter value can either be
35
- simply a value for exact match filtering or a value followed by a | and a match type which should be one of the following values:
34
+ Filtering of the returned data can be effected by supplying parameters of the format <b>FIELD_MATCHTYPE</b>
35
+ where FIELD matches one of
36
+ the field names defined in the data source and MATCHTYPE should be one of the following values.
36
37
  <br><br>
37
38
  <table>
39
+ <tr>
40
+ <th>Match Type</th>
41
+ <th>Description</th>
42
+ <th>Example</th>
43
+ </tr>
38
44
  <tr>
39
45
  <td>eq</td>
40
46
  <td>for an equals match</td>
47
+ <td>id_eq=3</td>
41
48
  </tr>
42
49
  <tr>
43
50
  <td>neq</td>
44
51
  <td>for a not equals match</td>
52
+ <td>id_neq=7</td>
45
53
  </tr>
46
54
  <tr>
47
- <td>null</td>
55
+ <td>isnull</td>
48
56
  <td>for a null match</td>
57
+ <td>id_isnull=1</td>
49
58
  </tr>
50
59
  <tr>
51
- <td>notnull</td>
60
+ <td>isnotnull</td>
52
61
  <td>for a not null match</td>
62
+ <td>id_isnotnull=1</td>
53
63
  </tr>
54
64
  <tr>
55
65
  <td>gt</td>
56
66
  <td>for a greater than match</td>
67
+ <td>id_gt=1</td>
57
68
  </tr>
58
69
  <tr>
59
70
  <td>lt</td>
60
71
  <td>for a less than match</td>
72
+ <td>id_lt=1</td>
61
73
  </tr>
62
74
  <tr>
63
75
  <td>gte</td>
64
76
  <td>for a greater than or equals match</td>
77
+ <td>id_gte=1</td>
65
78
  </tr>
66
79
  <tr>
67
80
  <td>lte</td>
68
81
  <td>for a less than or equals match</td>
82
+ <td>id_lte=10</td>
69
83
  </tr>
70
84
  <tr>
71
85
  <td>startswith</td>
72
86
  <td>for a string starts with match</td>
87
+ <td>name_startswith=app</td>
73
88
  </tr>
74
89
  <tr>
75
90
  <td>endswith</td>
76
91
  <td>for a string ends with match</td>
92
+ <td>name_endswith=app</td>
77
93
  </tr>
78
94
  <tr>
79
95
  <td>contains</td>
80
- <td>or a string contains match</td>
96
+ <td>for a string contains match</td>
97
+ <td>name_contains=app</td>
98
+ </tr>
99
+ <tr>
100
+ <td>like</td>
101
+ <td>for a wildcard or regular expression match. Simple wildcards can be supplied using * for
102
+ one or more characters. Regular expressions
103
+ can be supplied by surrounding the value with / delimiters.
104
+ </td>
105
+ <td>name_like=ap*, name_like=/^ap.*le$/</td>
106
+ </tr>
107
+ <tr>
108
+ <td>in</td>
109
+ <td>for where the value is one of a list supplied in comma separated format</td>
110
+ <td>name_in="apple,pear,banana"</td>
111
+ </tr>
112
+ <tr>
113
+ <td>notin</td>
114
+ <td>for where the value is not one of a list supplied in comma separated format</td>
115
+ <td>name_notin="apple,pear,banana"</td>
81
116
  </tr>
82
117
  </table>
83
118
  <br><br>
84
- Results can be sorted by supplying a <b>sort</b> parameter which identifies columns to sort and directions (either asc or desc) using pipe separation
119
+ Alternatively, advanced queries can be supplied using the built in Data Query Language passed as a <b>query</b> parameter which should be suitable URL encoded.
120
+ <br><br>
121
+ e.g. <code>query=((id >= 5 && name like 'app*') || id < 3)</code>
122
+ <br><br>
123
+ Results can be sorted by supplying a <b>sort</b> parameter which identifies columns to sort and
124
+ directions (either asc or desc) using pipe separation
85
125
  <br><br>
86
- By default the first 100 rows will be returned. Paging can be achieved by supplying
126
+ By default the first 100 rows will be returned. Paging can be achieved by supplying
87
127
  <b>limit</b> and <b>offset</b> parameters.
88
128
  </div>
89
129
  <div #list class=" bg-gray-800 border-2 border-gray-900 text-white rounded-md p-4">
90
- <pre class="whitespace-normal">curl -H <span class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre><pre class="whitespace-normal"> -X <b>GET</b> <span class="text-cta">{{backendURL}}/api/tabularData/{{datasourceUpdate.instanceImportKey}}?{{listQueryString}}&limit=50&offset=10</span></pre>
130
+ <pre class="whitespace-normal">curl -H <span
131
+ class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span
132
+ class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre>
133
+ <pre class="whitespace-normal"> -X <b>GET</b> <span class="text-cta">{{backendURL}}
134
+ /api/tabularData/{{datasourceUpdate.instanceImportKey}}?{{listQueryString}}
135
+ &limit=50&offset=10</span></pre>
91
136
  </div>
92
137
  <button mat-icon-button [cdkCopyToClipboard]="list.textContent" (cdkCopyToClipboardCopied)="copied()"
93
138
  class="text-white absolute bottom-0 right-0">
@@ -102,7 +147,11 @@
102
147
  Insert a set of new rows to the data source identified by the passed import key
103
148
  </div>
104
149
  <div #create class=" bg-gray-800 border-2 border-gray-900 text-white rounded-md p-4">
105
- <pre class="whitespace-normal">curl -H <span class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre><pre class="whitespace-normal"> -X <b>POST</b> <span class="text-cta">{{backendURL}}/api/tabularData/{{datasourceUpdate.instanceImportKey}}</span></pre>
150
+ <pre class="whitespace-normal">curl -H <span
151
+ class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span
152
+ class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre>
153
+ <pre class="whitespace-normal"> -X <b>POST</b> <span class="text-cta">{{backendURL}}
154
+ /api/tabularData/{{datasourceUpdate.instanceImportKey}}</span></pre>
106
155
  </div>
107
156
  <button mat-icon-button [cdkCopyToClipboard]="create.textContent" (cdkCopyToClipboardCopied)="copied()"
108
157
  class="text-white absolute bottom-0 right-0">
@@ -118,11 +167,15 @@
118
167
  <div class="relative w-full">
119
168
  <div class="text-base font-semibold">Replace</div>
120
169
  <div class="text-sm mb-2">
121
- Replace a set of rows to the data source identified by the passed import key. This will perform
170
+ Replace a set of rows to the data source identified by the passed import key. This will perform
122
171
  an insert or update depending on whether the row already exists according to the unique key.
123
172
  </div>
124
173
  <div #replace class="relative bg-gray-800 border-2 border-gray-900 text-white rounded-md p-4">
125
- <pre class="whitespace-normal">curl -H <span class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre><pre class="whitespace-normal"> -X <b>PATCH</b> <span class="text-cta">{{backendURL}}/api/tabularData/{{datasourceUpdate.instanceImportKey}}</span></pre>
174
+ <pre class="whitespace-normal">curl -H <span
175
+ class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span
176
+ class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre>
177
+ <pre class="whitespace-normal"> -X <b>PATCH</b> <span class="text-cta">{{backendURL}}
178
+ /api/tabularData/{{datasourceUpdate.instanceImportKey}}</span></pre>
126
179
  </div>
127
180
  <button mat-icon-button [cdkCopyToClipboard]="replace.textContent"
128
181
  class="text-white absolute bottom-0 right-0">
@@ -137,11 +190,15 @@
137
190
  <div class="relative w-full">
138
191
  <div class="text-base font-semibold">Update</div>
139
192
  <div class="text-sm mb-2">
140
- Update a set of rows to the data source identified by the passed import key. This will perform
193
+ Update a set of rows to the data source identified by the passed import key. This will perform
141
194
  an update based upon the unique key and will not add any new rows if they don't already exist.
142
195
  </div>
143
196
  <div #update class="relative bg-gray-800 border-2 border-gray-900 text-white rounded-md p-4">
144
- <pre class="whitespace-normal">curl -H <span class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre><pre class="whitespace-normal"> -X <b>PUT</b> <span class="text-cta">{{backendURL}}/api/tabularData/{{datasourceUpdate.instanceImportKey}}</span></pre>
197
+ <pre class="whitespace-normal">curl -H <span
198
+ class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span
199
+ class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre>
200
+ <pre class="whitespace-normal"> -X <b>PUT</b> <span class="text-cta">{{backendURL}}
201
+ /api/tabularData/{{datasourceUpdate.instanceImportKey}}</span></pre>
145
202
  </div>
146
203
  <button mat-icon-button [cdkCopyToClipboard]="update.textContent"
147
204
  class="text-white absolute bottom-0 right-0">
@@ -156,10 +213,15 @@
156
213
  <div class="relative w-full">
157
214
  <div class="text-base font-semibold">Delete</div>
158
215
  <div class="text-sm mb-2">
159
- Delete a set of rows explicitly by unique key for the data source identified by the passed import key.
216
+ Delete a set of rows explicitly by unique key for the data source identified by the passed import
217
+ key.
160
218
  </div>
161
219
  <div #delete class="relative bg-gray-800 border-2 border-gray-900 text-white rounded-md p-4">
162
- <pre class="whitespace-normal">curl -H <span class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre><pre class="whitespace-normal"> -X <b>DELETE</b> <span class="text-cta">{{backendURL}}/api/tabularData/{{datasourceUpdate.instanceImportKey}}</span></pre>
220
+ <pre class="whitespace-normal">curl -H <span
221
+ class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span
222
+ class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre>
223
+ <pre class="whitespace-normal"> -X <b>DELETE</b> <span class="text-cta">{{backendURL}}
224
+ /api/tabularData/{{datasourceUpdate.instanceImportKey}}</span></pre>
163
225
  </div>
164
226
  <button mat-icon-button [cdkCopyToClipboard]="delete.textContent"
165
227
  class="text-white absolute bottom-0 right-0">
@@ -175,9 +237,11 @@
175
237
  <div class="relative w-full">
176
238
  <div class="text-base font-semibold">Filtered Delete</div>
177
239
  <div class="text-sm mb-2">
178
- Delete a set of rows using one or more filter expressions additively to identify the rows for deletion for the data source identified by the passed import key.
240
+ Delete a set of rows using one or more filter expressions additively to identify the rows for
241
+ deletion for the data source identified by the passed import key.
179
242
  <br><br>
180
- Filters are supplied as objects containing a column name supplied as the <b>column</b> property, a match value supplied as the <b>value</b> property and a match type supplied as
243
+ Filters are supplied as objects containing a column name supplied as the <b>column</b> property, a
244
+ match value supplied as the <b>value</b> property and a match type supplied as
181
245
  the <b>matchType</b> property.
182
246
  <br><br>
183
247
  Possible values for the <b>matchType</b> are:<br><br>
@@ -231,7 +295,11 @@
231
295
 
232
296
  </div>
233
297
  <div #deleteFiltered class="relative bg-gray-800 border-2 border-gray-900 text-white rounded-md p-4">
234
- <pre class="whitespace-normal">curl -H <span class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre><pre class="whitespace-normal"> -X <b>DELETE</b> <span class="text-cta">{{backendURL}}/api/tabularData/filtered/{{datasourceUpdate.instanceImportKey}}</span></pre>
298
+ <pre class="whitespace-normal">curl -H <span
299
+ class="text-cta">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey : '[[apiKey]]'}}</b>"</span> -H <span
300
+ class="text-cta">"API-SECRET:<b>{{apiKeys ? apiKeys.apiSecret : '[[apiSecret]]'}}</b>"</span></pre>
301
+ <pre class="whitespace-normal"> -X <b>DELETE</b> <span class="text-cta">{{backendURL}}
302
+ /api/tabularData/filtered/{{datasourceUpdate.instanceImportKey}}</span></pre>
235
303
  </div>
236
304
  <button mat-icon-button [cdkCopyToClipboard]="deleteFiltered.textContent"
237
305
  class="text-white absolute bottom-0 right-0">
@@ -52,9 +52,9 @@ export class ApiAccessComponent implements OnInit {
52
52
  example.push(', ');
53
53
  }
54
54
  }
55
- this.listQueryString += 'filter_' + column.name + '=VALUE&';
55
+ this.listQueryString += column.name + '_eq=VALUE&';
56
56
  if (index == this.columns.length - 1)
57
- this.listQueryString += 'sort=' + column.name + '|desc';
57
+ this.listQueryString += 'query=' + column.name + '+isnotnull&sort=' + column.name + '|desc';
58
58
  });
59
59
  example.push('}]');
60
60
  this.createExample = example.join('');
@@ -30,7 +30,7 @@
30
30
  <mat-icon class="text-xl">tune</mat-icon>
31
31
  advanced
32
32
  </button>
33
- <button *ngIf="!editMode" (click)="apiAccess()" [disabled]="!datasourceInstanceKey"
33
+ <button *ngIf="!editMode && !hideAPIAccess" (click)="apiAccess()" [disabled]="!datasourceInstanceKey"
34
34
  class="disabled:opacity-50 w-20 flex flex-col items-center justify-center py-1 px-2 text-xs text-gray-600 cursor-pointer hover:bg-gray-100">
35
35
  <mat-icon class="text-xl">api</mat-icon>
36
36
  api access
@@ -20,6 +20,7 @@ import {
20
20
  } from '../create-datasource/import-data/import-wizard/import-wizard.component';
21
21
  import {BehaviorSubject} from 'rxjs';
22
22
  import {CreateDatasetComponent} from '../../dataset/create-dataset/create-dataset.component';
23
+ import shortHash from 'short-hash';
23
24
 
24
25
 
25
26
  declare var window: any;
@@ -37,6 +38,8 @@ export class CreateDatasourceComponent implements OnInit, AfterViewInit, OnDestr
37
38
  @Input() backendURL: string;
38
39
  @Input() namePrefix = '';
39
40
  @Input() readonly = false;
41
+ @Input() automaticImportKey: boolean = false;
42
+ @Input() hideAPIAccess: boolean = false;
40
43
  @Input() editColumns = true;
41
44
  @Input() filterJunction = {
42
45
  logic: 'AND',
@@ -144,7 +147,8 @@ export class CreateDatasourceComponent implements OnInit, AfterViewInit, OnDestr
144
147
  rows: this.rows,
145
148
  datasourceInstanceKey: this.datasourceInstanceKey,
146
149
  reloadURL: this.reloadURL,
147
- namePrefix: this.namePrefix
150
+ namePrefix: this.namePrefix,
151
+ automaticImportKey: this.automaticImportKey
148
152
  }
149
153
  });
150
154
  dialogRef.afterClosed().subscribe(res => {
@@ -506,7 +510,13 @@ export class CreateDatasourceComponent implements OnInit, AfterViewInit, OnDestr
506
510
  // Reset invalid items
507
511
  this.invalidItems = [];
508
512
 
513
+
509
514
  if (!this.datasourceInstanceKey) {
515
+
516
+ if (this.automaticImportKey){
517
+ this.datasourceUpdate.importKey = shortHash(Date.now().toString());
518
+ }
519
+
510
520
  await this.datasourceService.createCustomDatasource(this.datasourceUpdate).then(key => {
511
521
  if (!exit) {
512
522
  window.location.href = this.reloadURL + '/' + key;
@@ -530,9 +540,7 @@ export class CreateDatasourceComponent implements OnInit, AfterViewInit, OnDestr
530
540
 
531
541
  const invalidAddRows = _.map(result.validationErrors.add || [], 'itemNumber');
532
542
  for (let i = this.adds.length - 1; i >= 0; i--) {
533
- if (!invalidAddRows.includes(i)) {
534
- this.adds.splice(i, 1);
535
- } else {
543
+ if (invalidAddRows.includes(i)) {
536
544
  this.invalidItems[this.adds[i]] = _.find(result.validationErrors.add, {itemNumber: i}).validationErrors;
537
545
  }
538
546
  }
@@ -540,9 +548,7 @@ export class CreateDatasourceComponent implements OnInit, AfterViewInit, OnDestr
540
548
 
541
549
  const invalidUpdateRows = _.map(result.validationErrors.update || [], 'itemNumber');
542
550
  for (let i = this.updates.length - 1; i >= 0; i--) {
543
- if (!invalidUpdateRows.includes(i)) {
544
- this.updates.splice(i, 1);
545
- } else {
551
+ if (invalidUpdateRows.includes(i)) {
546
552
  this.invalidItems[this.updates[i]] = _.find(result.validationErrors.update, {itemNumber: i}).validationErrors;
547
553
  }
548
554
  }
@@ -152,7 +152,6 @@ export class ImportDataComponent implements OnInit {
152
152
 
153
153
  if (result && result.rejected > 0) {
154
154
  this.importErrors = Object.values(result.validationErrors)[0];
155
- console.log(this.importErrors);
156
155
  } else {
157
156
  window.location.href = this.reloadURL + '/' + this.datasourceInstanceKey;
158
157
  }
@@ -12,6 +12,7 @@ import {DatasourceService} from '../../../../../services/datasource.service';
12
12
  import {HttpClient} from '@angular/common/http';
13
13
  import {MatLegacySnackBar as MatSnackBar} from '@angular/material/legacy-snack-bar';
14
14
  import {KinintelModuleConfig} from '../../../../../../lib/ng-kinintel.module';
15
+ import shortHash from 'short-hash';
15
16
 
16
17
  const _ = lodash.default;
17
18
 
@@ -161,6 +162,9 @@ export class ImportWizardComponent implements OnInit {
161
162
  this.datasourceUpdate.fields.push(column);
162
163
  });
163
164
 
165
+ if (this.data.automaticImportKey)
166
+ this.datasourceUpdate.importKey = shortHash(Date.now().toString());
167
+
164
168
  const key = await this.datasourceService.createCustomDatasource(this.datasourceUpdate);
165
169
 
166
170
  if (this.importKey) {
@@ -292,6 +292,10 @@ export class DocumentDatasourceComponent implements OnInit {
292
292
  {
293
293
  title: 'WTSA',
294
294
  value: 'wtsa'
295
+ },
296
+ {
297
+ title: 'WTDC',
298
+ value: 'wtdc'
295
299
  }
296
300
  ];
297
301
  })
@@ -36,7 +36,8 @@
36
36
  [ngClass]="{'border-red-600': !!error}"
37
37
  placeholder="my-new-data-feed" [(ngModel)]="feed.path">
38
38
  </div>
39
- <small *ngIf="!error" class="font-normal">The path used to identify this API Connection</small>
39
+ <small *ngIf="!error" class="font-normal">The path used to identify this API
40
+ Connection</small>
40
41
  <small *ngIf="error" class="font-normal text-red-600">{{error}}</small>
41
42
 
42
43
  </div>
@@ -68,15 +69,17 @@
68
69
  </label>
69
70
  <div class="flex flex-col mt-1 sm:col-span-2 sm:mt-0">
70
71
  <mat-checkbox class="example-margin" [(ngModel)]="cacheEnabled"
71
- (ngModelChange)="updateCacheEnabled($event)">
72
- Enable API Caching</mat-checkbox>
72
+ (ngModelChange)="updateCacheEnabled($event)">
73
+ Enable API Caching
74
+ </mat-checkbox>
73
75
 
74
76
  <div class="flex mt-4" *ngIf="cacheEnabled">
75
77
  <span
76
78
  class="inline-flex items-center px-3 rounded-l border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm">
77
79
  Cache time in seconds
78
80
  </span>
79
- <input type="number" class="w-full rounded-l-none flex-1" placeholder="time in seconds"
81
+ <input type="number" class="w-full rounded-l-none flex-1"
82
+ placeholder="time in seconds"
80
83
  [(ngModel)]="feed.cacheTimeSeconds">
81
84
  </div>
82
85
  <small class="font-normal">Enable caching to reduce requests to the server. Setting
@@ -122,8 +125,48 @@
122
125
  {{param.title}}
123
126
  </mat-list-option>
124
127
  </mat-selection-list>
128
+ <small class="font-normal">If selected, these parameters will be available to be
129
+ supplied as request parameters with names matching the parameter names.</small>
125
130
  </div>
126
131
  </div>
132
+
133
+ <div *ngIf="feedDataset"
134
+ class="sm:grid sm:grid-cols-3 sm:items-start sm:gap-4 sm:border-t sm:border-gray-200 sm:pt-5">
135
+ <label class="block text-sm font-medium text-gray-700 sm:mt-px sm:pt-2">
136
+ Advanced Querying
137
+ </label>
138
+ <div class="flex flex-col mt-1 sm:col-span-2 sm:mt-0">
139
+ <mat-checkbox class="example-margin" [(ngModel)]="feed.adhocFiltering">
140
+ Enable Adhoc Filtering
141
+ </mat-checkbox>
142
+ <small class="font-normal">Adhoc filtering allows adhoc field filters to be supplied as
143
+ request parameters
144
+ in the format field_operator=value</small>
145
+
146
+
147
+ <mat-checkbox class="example-margin mt-3" [(ngModel)]="feed.advancedQuerying">
148
+ Enable Advanced Querying
149
+ </mat-checkbox>
150
+
151
+ <div class="flex mt-4" *ngIf="feed.advancedQuerying">
152
+ <span
153
+ class="inline-flex items-center px-3 rounded-l border border-r-0 border-gray-300 bg-gray-50 text-gray-500 text-sm">
154
+ Request Parameter Name
155
+ </span>
156
+ <input type="text" class="w-full rounded-l-none flex-1"
157
+ placeholder="Parameter name"
158
+ [(ngModel)]="feed.advancedQueryParameterName">
159
+ </div>
160
+
161
+ <small class="font-normal">Advanced querying allows for advanced queries to be supplied as a query string with nested
162
+ boolean logic.</small>
163
+ </div>
164
+
165
+
166
+
167
+ </div>
168
+
169
+
127
170
  </div>
128
171
  </div>
129
172
  </div>
@@ -83,7 +83,7 @@
83
83
  <tbody *ngFor="let feed of feeds" class="hover:bg-gray-50">
84
84
  <tr class="hover:bg-gray-50">
85
85
  <td [ngClass]="{'border-b': !feed._showExample, 'border-b-0': feed._showExample}"
86
- class="whitespace-nowrap border-gray-200 px-4 py-2 text-sm font-medium text-gray-900">
86
+ class="border-gray-200 px-4 py-2 text-sm font-medium text-gray-900">
87
87
  <div class="flex items-center">
88
88
  {{feedUrl}}{{feed.path}}
89
89
  <mat-icon color="primary" class="ml-2 text-sm cursor-pointer"
@@ -92,13 +92,13 @@
92
92
  </div>
93
93
  </td>
94
94
  <td [ngClass]="{'border-b': !feed._showExample, 'border-b-0': feed._showExample}"
95
- class="whitespace-nowrap border-gray-200 px-4 py-2 text-sm text-gray-500">
95
+ class="border-gray-200 px-4 py-2 text-sm text-gray-500">
96
96
  <a class="primary hover:underline font-medium"
97
97
  (click)="view(feed.datasetInstanceId)">
98
98
  {{feed.datasetLabel ? feed.datasetLabel.title : ''}}</a>
99
99
  </td>
100
100
  <td [ngClass]="{'border-b': !feed._showExample, 'border-b-0': feed._showExample}"
101
- class="whitespace-nowrap border-gray-200 px-4 py-2 text-sm text-gray-500">
101
+ class="border-gray-200 px-4 py-2 text-sm text-gray-500">
102
102
  {{feed.exposedParameterNames.join(', ')}}
103
103
  </td>
104
104
  <td [ngClass]="{'border-b': !feed._showExample, 'border-b-0': feed._showExample}"
@@ -43,7 +43,67 @@ curl -H <span class="text-emerald-400">"API-KEY:<b>{{apiKeys ? apiKeys.apiKey :
43
43
  </button>
44
44
  </div>
45
45
 
46
+ <div class="text-sm my-4">
47
+ <div class="mb-4 font-medium text-base">
48
+ Example request parameters
49
+ </div>
46
50
 
51
+ <div class="mb-4">
52
+ Filtering of the returned data can be effected by supplying parameters of the format <b>filter_COLUMNNAME</b>. The parameter value can either be
53
+ simply a value for exact match filtering or a value followed by a | and a match type which should be one of the following values:
54
+ </div>
55
+ <table>
56
+ <tr>
57
+ <td>eq</td>
58
+ <td>for an equals match</td>
59
+ </tr>
60
+ <tr>
61
+ <td>neq</td>
62
+ <td>for a not equals match</td>
63
+ </tr>
64
+ <tr>
65
+ <td>null</td>
66
+ <td>for a null match</td>
67
+ </tr>
68
+ <tr>
69
+ <td>notnull</td>
70
+ <td>for a not null match</td>
71
+ </tr>
72
+ <tr>
73
+ <td>gt</td>
74
+ <td>for a greater than match</td>
75
+ </tr>
76
+ <tr>
77
+ <td>lt</td>
78
+ <td>for a less than match</td>
79
+ </tr>
80
+ <tr>
81
+ <td>gte</td>
82
+ <td>for a greater than or equals match</td>
83
+ </tr>
84
+ <tr>
85
+ <td>lte</td>
86
+ <td>for a less than or equals match</td>
87
+ </tr>
88
+ <tr>
89
+ <td>startswith</td>
90
+ <td>for a string starts with match</td>
91
+ </tr>
92
+ <tr>
93
+ <td>endswith</td>
94
+ <td>for a string ends with match</td>
95
+ </tr>
96
+ <tr>
97
+ <td>contains</td>
98
+ <td>or a string contains match</td>
99
+ </tr>
100
+ </table>
101
+ <br><br>
102
+ Results can be sorted by supplying a <b>sort</b> parameter which identifies columns to sort and directions (either asc or desc) using pipe separation
103
+ <br><br>
104
+ By default the first 100 rows will be returned. Paging can be achieved by supplying
105
+ <b>limit</b> and <b>offset</b> parameters.
106
+ </div>
47
107
 
48
108
  </div>
49
109
 
@@ -59,17 +59,17 @@
59
59
  </tr>
60
60
  <ng-template [ngIf]="datasets.length">
61
61
  <tbody *ngFor="let item of datasets" class="hover:bg-gray-50">
62
- <tr class="hover:bg-gray-50">
63
- <td class="border-b whitespace-nowrap border-gray-200 px-4 py-2 text-sm font-medium text-gray-900">
62
+ <tr class="hover:bg-gray-50 cursor-pointer">
63
+ <td (click)="extend(item.id)" class="border-b whitespace-nowrap border-gray-200 px-4 py-2 text-sm font-medium text-gray-900">
64
64
  {{ (item.title || '').replace((nameReplaceString || ''), '') }}
65
65
  </td>
66
- <td class="border-b whitespace-nowrap border-gray-200 px-4 py-2 text-sm text-gray-500">
66
+ <td (click)="extend(item.id)" class="border-b whitespace-nowrap border-gray-200 px-4 py-2 text-sm text-gray-500">
67
67
  {{ item.owningAccountName }}
68
68
  </td>
69
69
  <td class="border-b whitespace-nowrap border-gray-200 text-right px-4 py-2 text-sm text-gray-500">
70
70
  <div class="flex items-center justify-end">
71
71
  <button mat-button color="primary" (click)="apiAccess(item)" [disabled]="item._loadingAPI">
72
- <span *ngIf="!item._loadingAPI">API Access</span>
72
+ <span *ngIf="!item._loadingAPI">API</span>
73
73
  <span *ngIf="item._loadingAPI" class="flex items-center">
74
74
  <svg class="animate-spin -ml-1 mr-2 h-4 w-4 text-gray-400"
75
75
  xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
@@ -84,7 +84,7 @@
84
84
 
85
85
  <div class="divider"></div>
86
86
  <button mat-button color="primary" (click)="extend(item.id)">
87
- Create Query
87
+ View
88
88
  </button>
89
89
  </div>
90
90
  </td>
@@ -30,6 +30,7 @@ export class SharedWithMeComponent implements OnInit {
30
30
  @Input() datasetEditorReadonly = false;
31
31
  @Input() nameReplaceString: string;
32
32
  @Input() feedUrl: string;
33
+ @Input() apiDocsUrl: string = '';
33
34
 
34
35
  public datasets: any = [];
35
36
  public searchText = new BehaviorSubject('');
@@ -98,7 +99,9 @@ export class SharedWithMeComponent implements OnInit {
98
99
  path: hash,
99
100
  datasetInstanceId: dataset.id,
100
101
  datasetLabel: dataset,
101
- exporterKey: 'json'
102
+ exporterKey: 'json',
103
+ advancedQuerying: true,
104
+ adhocFiltering: true
102
105
  };
103
106
 
104
107
  feedId = await this.feedService.saveFeed(feedData);
@@ -109,18 +112,23 @@ export class SharedWithMeComponent implements OnInit {
109
112
  const feed = await this.feedService.getFeed(feedId);
110
113
  dataset._loadingAPI = false;
111
114
 
112
- const dialog = this.dialog.open(FeedApiModalComponent, {
113
- width: '700px',
114
- height: '450px',
115
- data: {
116
- feed,
117
- feedUrl: this.feedUrl
118
- }
119
- });
115
+ if (this.apiDocsUrl) {
116
+ window.location.href = this.apiDocsUrl + "?sharedDatasetId=" + dataset.id;
117
+ } else {
118
+ const dialog = this.dialog.open(FeedApiModalComponent, {
119
+ width: '700px',
120
+ height: '650px',
121
+ data: {
122
+ feed,
123
+ feedUrl: this.feedUrl
124
+ }
125
+ });
126
+ }
120
127
  }
121
128
 
122
129
  public getDatasets() {
123
- return this.datasetService.getAccountSharedDatasets(this.searchText.getValue(), this.limit, this.offset).toPromise();
130
+ const searchString = this.nameReplaceString + this.searchText.getValue();
131
+ return this.datasetService.getAccountSharedDatasets(searchString, this.limit, this.offset).toPromise();
124
132
  }
125
133
 
126
134
  // Create extended dataset from source id.
@@ -35,10 +35,9 @@ export class DatasourceService {
35
35
  .toPromise();
36
36
  }
37
37
 
38
- public getDatasources(filterString = '', limit = '10', offset = '0', noProject = false) {
38
+ public getDatasources(filterString = '', limit = '10', offset = '0', noProject = false, projectKey = '') {
39
39
  const project = this.projectService.activeProject.getValue() ? this.projectService.activeProject.getValue().projectKey : '';
40
- const projectKey = noProject ? '' : project;
41
- return this.http.get(this.config.backendURL + '/datasource?projectKey=' + projectKey, {
40
+ return this.http.get(this.config.backendURL + '/datasource?projectKey=' + (noProject ? '' : projectKey || project), {
42
41
  params: {
43
42
  filterString, limit, offset
44
43
  }