Skip to content

Commit 41abc8e

Browse files
committed
Add duplicate checking ui
1 parent c70f7f2 commit 41abc8e

7 files changed

Lines changed: 251 additions & 4 deletions

File tree

OpenFlow/src/public/Controllers.ts

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4012,4 +4012,168 @@ export class CredentialCtrl extends entityCtrl<Base> {
40124012
});
40134013
}
40144014

4015+
}
4016+
4017+
4018+
4019+
4020+
4021+
export class DuplicatesCtrl extends entitiesCtrl<Base> {
4022+
public collections: any;
4023+
public model: Base;
4024+
public uniqeness: string;
4025+
constructor(
4026+
public $scope: ng.IScope,
4027+
public $location: ng.ILocationService,
4028+
public $routeParams: ng.route.IRouteParamsService,
4029+
public $interval: ng.IIntervalService,
4030+
public WebSocketClientService: WebSocketClientService,
4031+
public api: api,
4032+
public userdata: userdata
4033+
) {
4034+
super($scope, $location, $routeParams, $interval, WebSocketClientService, api, userdata);
4035+
console.debug("DuplicatesCtrl");
4036+
this.autorefresh = true;
4037+
this.basequery = { _id: 'notthere' };
4038+
this.collection = $routeParams.collection;
4039+
this.baseprojection = { _type: 1, type: 1, name: 1, _created: 1, _createdby: 1, _modified: 1 };
4040+
this.postloadData = this.processdata;
4041+
if (this.userdata.data.DuplicatesCtrl) {
4042+
this.basequery = this.userdata.data.DuplicatesCtrl.basequery;
4043+
this.uniqeness = this.userdata.data.DuplicatesCtrl.uniqeness;
4044+
this.baseprojection = this.userdata.data.DuplicatesCtrl.baseprojection;
4045+
this.orderby = this.userdata.data.DuplicatesCtrl.orderby;
4046+
this.searchstring = this.userdata.data.DuplicatesCtrl.searchstring;
4047+
this.basequeryas = this.userdata.data.DuplicatesCtrl.basequeryas;
4048+
} else {
4049+
if (NoderedUtil.IsNullEmpty(this.collection)) {
4050+
console.log("1 redir to /Duplicates/entities");
4051+
this.$location.path("/Duplicates/entities");
4052+
if (!this.$scope.$$phase) { this.$scope.$apply(); }
4053+
return;
4054+
}
4055+
}
4056+
if (NoderedUtil.IsNullEmpty(this.collection)) {
4057+
console.log("2 redir to /Duplicates/entities");
4058+
this.$location.path("/Duplicates/entities");
4059+
if (!this.$scope.$$phase) { this.$scope.$apply(); }
4060+
return;
4061+
} else if (this.$location.path() != "/Duplicates/" + this.collection) {
4062+
console.log("3 redir from / to");
4063+
console.log(this.$location.path());
4064+
console.log("/Duplicates/" + this.collection);
4065+
this.$location.path("/Duplicates/" + this.collection);
4066+
if (!this.$scope.$$phase) { this.$scope.$apply(); }
4067+
return;
4068+
}
4069+
if (!this.$scope.$$phase) { this.$scope.$apply(); }
4070+
WebSocketClientService.onSignedin(async (user: TokenUser) => {
4071+
this.loadData();
4072+
});
4073+
}
4074+
async processdata() {
4075+
if (!NoderedUtil.IsNullEmpty(this.uniqeness)) {
4076+
var pipe: any[] = [];
4077+
var arr = this.uniqeness.split(",");
4078+
var group: any = { _id: {}, count: { "$sum": 1 } };
4079+
//if ("111".toLowerCase() == "22") {
4080+
group.items = {
4081+
$push: '$$ROOT._id'
4082+
}
4083+
//}
4084+
arr.forEach(field => {
4085+
if (field.trim() !== "") {
4086+
group._id[field] = "$" + field;
4087+
}
4088+
});
4089+
pipe.push({ "$group": group });
4090+
pipe.push({ "$match": { "count": { "$gte": 2 } } });
4091+
pipe.push({ "$limit": 100 });
4092+
pipe.push({ "$sort": this.orderby })
4093+
try {
4094+
this.models = await NoderedUtil.Aggregate(this.collection, pipe, null);
4095+
console.log(this.models);
4096+
} catch (error) {
4097+
console.log(pipe);
4098+
this.errormessage = JSON.stringify(error);
4099+
}
4100+
}
4101+
4102+
if (!this.userdata.data.DuplicatesCtrl) this.userdata.data.DuplicatesCtrl = {};
4103+
this.userdata.data.DuplicatesCtrl.basequery = this.basequery;
4104+
this.userdata.data.DuplicatesCtrl.uniqeness = this.uniqeness;
4105+
this.userdata.data.DuplicatesCtrl.baseprojection = this.baseprojection;
4106+
this.userdata.data.DuplicatesCtrl.orderby = this.orderby;
4107+
this.userdata.data.DuplicatesCtrl.searchstring = this.searchstring;
4108+
this.userdata.data.DuplicatesCtrl.basequeryas = this.basequeryas;
4109+
if (!this.$scope.$$phase) { this.$scope.$apply(); }
4110+
}
4111+
async ShowData(model) {
4112+
var modal: any = $("#exampleModal");
4113+
modal.modal();
4114+
this.model = model;
4115+
}
4116+
OpenEntity(id) {
4117+
var modal: any = $("#exampleModal");
4118+
modal.modal('hide');
4119+
this.$location.path("/Entity/" + this.collection + "/" + id);
4120+
if (!this.$scope.$$phase) { this.$scope.$apply(); }
4121+
return;
4122+
4123+
}
4124+
async MassDeleteOnlyOne() {
4125+
this.loading = true;
4126+
for (var x = 0; x < this.models.length; x++) {
4127+
var item = (this.models[x] as any);
4128+
console.log("deleting " + item.items[0]);
4129+
await NoderedUtil.DeleteOne(this.collection, item.items[0], null);
4130+
}
4131+
this.loading = false;
4132+
this.loadData();
4133+
}
4134+
async MassDeleteAllButOne() {
4135+
this.loading = true;
4136+
for (var x = 0; x < this.models.length; x++) {
4137+
var item = (this.models[x] as any);
4138+
for (var y = 1; y < item.items.length; y++) {
4139+
console.log("deleting " + item.items[y]);
4140+
await NoderedUtil.DeleteOne(this.collection, item.items[y], null);
4141+
}
4142+
}
4143+
this.loading = false;
4144+
this.loadData();
4145+
}
4146+
async MassDeleteAll() {
4147+
this.loading = true;
4148+
for (var x = 0; x < this.models.length; x++) {
4149+
var item = (this.models[x] as any);
4150+
for (var y = 0; y < item.items.length; y++) {
4151+
console.log("deleting " + item.items[y]);
4152+
await NoderedUtil.DeleteOne(this.collection, item.items[y], null);
4153+
}
4154+
}
4155+
this.loading = false;
4156+
this.loadData();
4157+
}
4158+
async DeleteOnlyOne(model) {
4159+
if (NoderedUtil.IsNullUndefinded(model)) return;
4160+
if (NoderedUtil.IsNullUndefinded(model.items)) return;
4161+
if (model.items.length < 2) return;
4162+
this.loading = true;
4163+
console.log("deleting " + model.items[0]);
4164+
await NoderedUtil.DeleteOne(this.collection, model.items[0], null);
4165+
this.loading = false;
4166+
this.loadData();
4167+
}
4168+
async DeleteAll(model) {
4169+
if (NoderedUtil.IsNullUndefinded(model)) return;
4170+
if (NoderedUtil.IsNullUndefinded(model.items)) return;
4171+
this.loading = true;
4172+
for (var i = 0; i < model.items.length; i++) {
4173+
console.log("deleting " + model.items[i]);
4174+
await NoderedUtil.DeleteOne(this.collection, model.items[i], null);
4175+
}
4176+
this.loading = false;
4177+
this.loadData();
4178+
}
40154179
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<div class="row">
2+
<h1 translate lib="web">duplicates tracking</h1>
3+
</div>
4+
5+
<div class=" col-md-6 text-right">
6+
<!-- <a ng-href="#/Duplicates/{{ctrl.collection}}" class="btn btn-info"><i class="fas fa-clone"></i></a>
7+
<a ng-href="#/Entity/{{ctrl.collection}}" class="btn btn-info"><i class="az-add-lg"></i></a> -->
8+
</div>
9+
</div>
10+
11+
<div ng-show="ctrl.errormessage != ''"" class=" alert alert-danger" role="alert">{{ctrl.errormessage}}</div>
12+
13+
<div class="form-group form-horizontal">
14+
<label class="sr-only">Uniqeness</label>
15+
<div class="input-group unframed-addons col-sm-9 ">
16+
<div class="input-group-addon"><i class="fas fa-search"></i></div>
17+
<input ng-model="ctrl.uniqeness" ng-change="ctrl.loadData()" class="form-control input-md"
18+
ng-model-options="{debounce: 400}" />
19+
<p class="col-md-1 lead"></p>
20+
<div class="text-right">
21+
<button class="btn btn-info" ng-click="ctrl.MassDeleteOnlyOne()"><i class="az-trash"></i> one</button>
22+
<button class="btn btn-info" ng-click="ctrl.MassDeleteAllButOne()"><i class="az-trash"></i> all but one</button>
23+
<button class="btn btn-info" ng-click="ctrl.MassDeleteAll()"><i class="az-trash"></i> all</button>
24+
</div>
25+
</div>
26+
</div>
27+
28+
</div>
29+
<table id=" table1" class="table table-striped table-hover table-sm" when-scrolled="ctrl.more()" style="width: 100%;">
30+
<thead class="thead-dark">
31+
<tr>
32+
<th scope="col" ng-click="ctrl.ToggleOrder('_id')"><b>_id</b></th>
33+
<th scope="col" ng-click="ctrl.ToggleOrder('count')"><b>count</b></th>
34+
<th></th>
35+
<th></th>
36+
<th></th>
37+
</tr>
38+
</thead>
39+
<tbody>
40+
<tr ng-repeat="model in ctrl.models" ng-click="ctrl.ShowData(model)">
41+
<td>{{model._id}}</td>
42+
<td>{{model.count}}</td>
43+
<td class="btn-cell">
44+
<!-- <a ng-href="#/History/{{ctrl.collection}}/{{model._id}}" class="table-btn">Hist</a> -->
45+
</td>
46+
<td class="btn-cell">
47+
<a href ng-click="ctrl.DeleteOnlyOne(model)" ng-disabled="ctrl.loading==true" class="table-btn"><i
48+
class="az-trash"></i> one</a>
49+
</td>
50+
<td class="btn-cell">
51+
<a href ng-click="ctrl.DeleteAll(model)" ng-disabled="ctrl.loading==true" class="table-btn"><i
52+
class="az-trash"></i> all</a>
53+
</td>
54+
</tr>
55+
</tbody>
56+
</table>
57+
58+
59+
60+
<div class="modal" tabindex="-1" role="dialog" id="exampleModal">
61+
<div class="modal-dialog" role="document">
62+
<div class="modal-content">
63+
<div class="modal-header">
64+
<h5 class="modal-title">{{ctrl.model.name}} </h5>
65+
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
66+
<span aria-hidden="true">&times;</span>
67+
</button>
68+
</div>
69+
<div class="modal-body">
70+
<div ng-repeat="model in ctrl.model.items">
71+
<a ng-click="ctrl.OpenEntity(model)" class="table-btn"><i class="az-edit"></i>{{ model }}</a>
72+
73+
</div>
74+
</div>
75+
<div class="modal-footer">
76+
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
77+
</div>
78+
</div>
79+
</div>
80+
</div>

OpenFlow/src/public/Entities.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ <h1 translate lib="web">entities</h1>
2828
</div>
2929
<div class=" col-md-6 text-right">
3030
<!-- <a ng-href="#/Entity/{{ctrl.collection}}" class="btn btn-info" translate lib="web">addentity</a> -->
31+
<a ng-href="#/Duplicates/{{ctrl.collection}}" class="btn btn-info"><i class="fas fa-clone"></i></a>
3132
<a ng-href="#/Entity/{{ctrl.collection}}" class="btn btn-info"><i class="az-add-lg"></i></a>
3233
</div>
3334
</div>

OpenFlow/src/public/app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { WebSocketClientService } from "./WebSocketClientService";
22
import angular = require("angular");
33
import { timesince, translate, textarea, fileread, userdata, api } from "./CommonControllers";
4-
import { MenuCtrl, ProvidersCtrl, MainCtrl, LoginCtrl, ProviderCtrl, UsersCtrl, UserCtrl, RolesCtrl, RoleCtrl, RPAWorkflowsCtrl, RPAWorkflowCtrl, WorkflowsCtrl, ReportsCtrl, jslogCtrl, EditFormCtrl, FormsCtrl, FormCtrl, FilesCtrl, EntitiesCtrl, EntityCtrl, HistoryCtrl, SocketCtrl, NoderedCtrl, hdrobotsCtrl, RobotsCtrl, AuditlogsCtrl, SignupCtrl, PaymentCtrl, QueuesCtrl, SocketsCtrl, QueueCtrl, CredentialsCtrl, CredentialCtrl } from "./Controllers";
4+
import { MenuCtrl, ProvidersCtrl, MainCtrl, LoginCtrl, ProviderCtrl, UsersCtrl, UserCtrl, RolesCtrl, RoleCtrl, RPAWorkflowsCtrl, RPAWorkflowCtrl, WorkflowsCtrl, ReportsCtrl, jslogCtrl, EditFormCtrl, FormsCtrl, FormCtrl, FilesCtrl, EntitiesCtrl, EntityCtrl, HistoryCtrl, SocketCtrl, NoderedCtrl, hdrobotsCtrl, RobotsCtrl, AuditlogsCtrl, SignupCtrl, PaymentCtrl, QueuesCtrl, SocketsCtrl, QueueCtrl, CredentialsCtrl, CredentialCtrl, DuplicatesCtrl } from "./Controllers";
55

66
/**
77
* @type {angular.Module}
@@ -71,6 +71,8 @@ module openflow {
7171
.when('/Entity/:collection', { templateUrl: 'Entity.html', controller: EntityCtrl, controllerAs: 'ctrl' })
7272
.when('/Entity/:collection/:id', { templateUrl: 'Entity.html', controller: EntityCtrl, controllerAs: 'ctrl' })
7373

74+
.when('/Duplicates/:collection', { templateUrl: 'Duplicates.html', controller: DuplicatesCtrl, controllerAs: 'ctrl' })
75+
7476
.when('/History/:collection/:id', { templateUrl: 'History.html', controller: HistoryCtrl, controllerAs: 'ctrl' })
7577

7678
.when('/Socket', { templateUrl: 'Socket.html', controller: SocketCtrl, controllerAs: 'ctrl' })

OpenFlowNodeRED/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openflow-nodered",
3-
"version": "1.1.21",
3+
"version": "1.1.22",
44
"description": "Simple wrapper around NodeRed, RabbitMQ and MongoDB to support a more scaleable NodeRed implementation.\r Also the \"backend\" for [OpenRPA](https://github.com/skadefro/OpenRPA)",
55
"main": "index.js",
66
"scripts": {

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.1.21
1+
1.1.22

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "openiap",
3-
"version": "1.1.21",
3+
"version": "1.1.22",
44
"description": "Simple wrapper around NodeRed, RabbitMQ and MongoDB to support a more scaleable NodeRed implementation.\r Also the \"backend\" for [OpenRPA](https://github.com/skadefro/OpenRPA)",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)