mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-20 17:30:46 +00:00
Prettier 2.0 (#393)
This commit is contained in:
@@ -1,327 +1,327 @@
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import * as Utilities from "../Utilities";
|
||||
|
||||
export default class ClauseGroup {
|
||||
public isRootGroup: boolean;
|
||||
public children = new Array();
|
||||
public parentGroup: ClauseGroup;
|
||||
private _id: string;
|
||||
|
||||
constructor(isRootGroup: boolean, parentGroup: ClauseGroup, id?: string) {
|
||||
this.isRootGroup = isRootGroup;
|
||||
this.parentGroup = parentGroup;
|
||||
this._id = id ? id : Utilities.guid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens the clause tree into an array, depth-first, left to right.
|
||||
*/
|
||||
public flattenClauses(targetArray: ko.ObservableArray<QueryClauseViewModel>): void {
|
||||
var tempArray = new Array<QueryClauseViewModel>();
|
||||
|
||||
this.flattenClausesImpl(this, tempArray);
|
||||
targetArray.removeAll();
|
||||
tempArray.forEach(element => {
|
||||
targetArray.push(element);
|
||||
});
|
||||
}
|
||||
|
||||
public insertClauseBefore(newClause: QueryClauseViewModel, insertBefore?: QueryClauseViewModel): void {
|
||||
if (!insertBefore) {
|
||||
newClause.clauseGroup = this;
|
||||
this.children.push(newClause);
|
||||
} else {
|
||||
var targetGroup = insertBefore.clauseGroup;
|
||||
|
||||
if (targetGroup) {
|
||||
var insertBeforeIndex = targetGroup.children.indexOf(insertBefore);
|
||||
newClause.clauseGroup = targetGroup;
|
||||
targetGroup.children.splice(insertBeforeIndex, 0, newClause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public deleteClause(clause: QueryClauseViewModel): void {
|
||||
var targetGroup = clause.clauseGroup;
|
||||
|
||||
if (targetGroup) {
|
||||
var index = targetGroup.children.indexOf(clause);
|
||||
targetGroup.children.splice(index, 1);
|
||||
clause.dispose();
|
||||
|
||||
if (targetGroup.children.length <= 1 && !targetGroup.isRootGroup) {
|
||||
var parent = targetGroup.parentGroup;
|
||||
var targetGroupIndex = parent.children.indexOf(targetGroup);
|
||||
|
||||
if (targetGroup.children.length === 1) {
|
||||
var orphan = targetGroup.children.shift();
|
||||
|
||||
if (orphan instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>orphan).clauseGroup = parent;
|
||||
} else if (orphan instanceof ClauseGroup) {
|
||||
(<ClauseGroup>orphan).parentGroup = parent;
|
||||
}
|
||||
|
||||
parent.children.splice(targetGroupIndex, 1, orphan);
|
||||
} else {
|
||||
parent.children.splice(targetGroupIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeAll(): void {
|
||||
var allClauses: QueryClauseViewModel[] = new Array<QueryClauseViewModel>();
|
||||
|
||||
this.flattenClausesImpl(this, allClauses);
|
||||
|
||||
while (allClauses.length > 0) {
|
||||
allClauses.shift().dispose();
|
||||
}
|
||||
|
||||
this.children = new Array<any>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups selected items. Returns True if a new group was created, otherwise False.
|
||||
*/
|
||||
public groupSelectedItems(): boolean {
|
||||
// Find the selection start & end, also check for gaps between selected items (if found, cannot proceed).
|
||||
var selection = this.getCheckedItemsInfo();
|
||||
|
||||
if (selection.canGroup) {
|
||||
var newGroup = new ClauseGroup(false, this);
|
||||
// Replace the selected items with the new group, and then move the selected items into the new group.
|
||||
var groupedItems = this.children.splice(selection.begin, selection.end - selection.begin + 1, newGroup);
|
||||
|
||||
groupedItems &&
|
||||
groupedItems.forEach(element => {
|
||||
newGroup.children.push(element);
|
||||
|
||||
if (element instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>element).clauseGroup = newGroup;
|
||||
} else if (element instanceof ClauseGroup) {
|
||||
(<ClauseGroup>element).parentGroup = newGroup;
|
||||
}
|
||||
});
|
||||
|
||||
this.unselectAll();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ungroup(): void {
|
||||
if (this.isRootGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parentGroup = this.parentGroup;
|
||||
var index = parentGroup.children.indexOf(this);
|
||||
|
||||
if (index >= 0) {
|
||||
parentGroup.children.splice(index, 1);
|
||||
|
||||
var toPromote = this.children.splice(0, this.children.length);
|
||||
|
||||
// Move all children one level up.
|
||||
toPromote &&
|
||||
toPromote.forEach(element => {
|
||||
if (element instanceof ClauseGroup) {
|
||||
(<ClauseGroup>element).parentGroup = parentGroup;
|
||||
} else if (element instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>element).clauseGroup = parentGroup;
|
||||
}
|
||||
|
||||
parentGroup.children.splice(index, 0, element);
|
||||
index++;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public canGroupSelectedItems(): boolean {
|
||||
return this.getCheckedItemsInfo().canGroup;
|
||||
}
|
||||
|
||||
public findDeepestGroupInChildren(skipIndex?: number): ClauseGroup {
|
||||
var deepest: ClauseGroup = this;
|
||||
var level: number = 0;
|
||||
var func = (currentGroup: ClauseGroup): void => {
|
||||
level++;
|
||||
if (currentGroup.getCurrentGroupDepth() > deepest.getCurrentGroupDepth()) {
|
||||
deepest = currentGroup;
|
||||
}
|
||||
|
||||
for (var i = 0; i < currentGroup.children.length; i++) {
|
||||
var currentItem = currentGroup.children[i];
|
||||
|
||||
if ((i !== skipIndex || level > 1) && currentItem instanceof ClauseGroup) {
|
||||
func(currentItem);
|
||||
}
|
||||
}
|
||||
level--;
|
||||
};
|
||||
|
||||
func(this);
|
||||
|
||||
return deepest;
|
||||
}
|
||||
|
||||
private getCheckedItemsInfo(): { canGroup: boolean; begin: number; end: number } {
|
||||
var beginIndex = -1;
|
||||
var endIndex = -1;
|
||||
// In order to perform group, all selected items must be next to each other.
|
||||
// If one or more items are not selected between the first and the last selected item, the gapFlag will be set to True, meaning cannot perform group.
|
||||
var gapFlag = false;
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
var subGroupSelectionState: { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean };
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
subGroupSelectionState = (<ClauseGroup>currentItem).getSelectionState();
|
||||
|
||||
if (subGroupSelectionState.partiallySelected) {
|
||||
gapFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
beginIndex < 0 &&
|
||||
endIndex < 0 &&
|
||||
((currentItem instanceof QueryClauseViewModel && currentItem.checkedForGrouping.peek()) ||
|
||||
(currentItem instanceof ClauseGroup && subGroupSelectionState.allSelected))
|
||||
) {
|
||||
beginIndex = i;
|
||||
}
|
||||
|
||||
if (
|
||||
beginIndex >= 0 &&
|
||||
endIndex < 0 &&
|
||||
((currentItem instanceof QueryClauseViewModel && !currentItem.checkedForGrouping.peek()) ||
|
||||
(currentItem instanceof ClauseGroup && !subGroupSelectionState.allSelected))
|
||||
) {
|
||||
endIndex = i - 1;
|
||||
}
|
||||
|
||||
if (beginIndex >= 0 && endIndex < 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (
|
||||
beginIndex >= 0 &&
|
||||
endIndex >= 0 &&
|
||||
((currentItem instanceof QueryClauseViewModel && currentItem.checkedForGrouping.peek()) ||
|
||||
(currentItem instanceof ClauseGroup && !subGroupSelectionState.nonSelected))
|
||||
) {
|
||||
gapFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gapFlag && endIndex < 0) {
|
||||
endIndex = this.children.length - 1;
|
||||
}
|
||||
|
||||
return {
|
||||
canGroup: beginIndex >= 0 && !gapFlag && count > 1,
|
||||
begin: beginIndex,
|
||||
end: endIndex
|
||||
};
|
||||
}
|
||||
|
||||
private getSelectionState(): { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean } {
|
||||
var selectedCount = 0;
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup && (<ClauseGroup>currentItem).getSelectionState().allSelected) {
|
||||
selectedCount++;
|
||||
}
|
||||
|
||||
if (
|
||||
currentItem instanceof QueryClauseViewModel &&
|
||||
(<QueryClauseViewModel>currentItem).checkedForGrouping.peek()
|
||||
) {
|
||||
selectedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
allSelected: selectedCount === this.children.length,
|
||||
partiallySelected: selectedCount > 0 && selectedCount < this.children.length,
|
||||
nonSelected: selectedCount === 0
|
||||
};
|
||||
}
|
||||
|
||||
private unselectAll(): void {
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
(<ClauseGroup>currentItem).unselectAll();
|
||||
}
|
||||
|
||||
if (currentItem instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>currentItem).checkedForGrouping(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private flattenClausesImpl(queryGroup: ClauseGroup, targetArray: QueryClauseViewModel[]): void {
|
||||
if (queryGroup.isRootGroup) {
|
||||
targetArray.splice(0, targetArray.length);
|
||||
}
|
||||
|
||||
for (var i = 0; i < queryGroup.children.length; i++) {
|
||||
var currentItem = queryGroup.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
this.flattenClausesImpl(currentItem, targetArray);
|
||||
}
|
||||
|
||||
if (currentItem instanceof QueryClauseViewModel) {
|
||||
targetArray.push(currentItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getTreeDepth(): number {
|
||||
var currentDepth = this.getCurrentGroupDepth();
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
var newDepth = (<ClauseGroup>currentItem).getTreeDepth();
|
||||
|
||||
if (newDepth > currentDepth) {
|
||||
currentDepth = newDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentDepth;
|
||||
}
|
||||
|
||||
public getCurrentGroupDepth(): number {
|
||||
var group = <ClauseGroup>this;
|
||||
var depth = 0;
|
||||
|
||||
while (!group.isRootGroup) {
|
||||
depth++;
|
||||
group = group.parentGroup;
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
}
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import * as Utilities from "../Utilities";
|
||||
|
||||
export default class ClauseGroup {
|
||||
public isRootGroup: boolean;
|
||||
public children = new Array();
|
||||
public parentGroup: ClauseGroup;
|
||||
private _id: string;
|
||||
|
||||
constructor(isRootGroup: boolean, parentGroup: ClauseGroup, id?: string) {
|
||||
this.isRootGroup = isRootGroup;
|
||||
this.parentGroup = parentGroup;
|
||||
this._id = id ? id : Utilities.guid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Flattens the clause tree into an array, depth-first, left to right.
|
||||
*/
|
||||
public flattenClauses(targetArray: ko.ObservableArray<QueryClauseViewModel>): void {
|
||||
var tempArray = new Array<QueryClauseViewModel>();
|
||||
|
||||
this.flattenClausesImpl(this, tempArray);
|
||||
targetArray.removeAll();
|
||||
tempArray.forEach((element) => {
|
||||
targetArray.push(element);
|
||||
});
|
||||
}
|
||||
|
||||
public insertClauseBefore(newClause: QueryClauseViewModel, insertBefore?: QueryClauseViewModel): void {
|
||||
if (!insertBefore) {
|
||||
newClause.clauseGroup = this;
|
||||
this.children.push(newClause);
|
||||
} else {
|
||||
var targetGroup = insertBefore.clauseGroup;
|
||||
|
||||
if (targetGroup) {
|
||||
var insertBeforeIndex = targetGroup.children.indexOf(insertBefore);
|
||||
newClause.clauseGroup = targetGroup;
|
||||
targetGroup.children.splice(insertBeforeIndex, 0, newClause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public deleteClause(clause: QueryClauseViewModel): void {
|
||||
var targetGroup = clause.clauseGroup;
|
||||
|
||||
if (targetGroup) {
|
||||
var index = targetGroup.children.indexOf(clause);
|
||||
targetGroup.children.splice(index, 1);
|
||||
clause.dispose();
|
||||
|
||||
if (targetGroup.children.length <= 1 && !targetGroup.isRootGroup) {
|
||||
var parent = targetGroup.parentGroup;
|
||||
var targetGroupIndex = parent.children.indexOf(targetGroup);
|
||||
|
||||
if (targetGroup.children.length === 1) {
|
||||
var orphan = targetGroup.children.shift();
|
||||
|
||||
if (orphan instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>orphan).clauseGroup = parent;
|
||||
} else if (orphan instanceof ClauseGroup) {
|
||||
(<ClauseGroup>orphan).parentGroup = parent;
|
||||
}
|
||||
|
||||
parent.children.splice(targetGroupIndex, 1, orphan);
|
||||
} else {
|
||||
parent.children.splice(targetGroupIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public removeAll(): void {
|
||||
var allClauses: QueryClauseViewModel[] = new Array<QueryClauseViewModel>();
|
||||
|
||||
this.flattenClausesImpl(this, allClauses);
|
||||
|
||||
while (allClauses.length > 0) {
|
||||
allClauses.shift().dispose();
|
||||
}
|
||||
|
||||
this.children = new Array<any>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups selected items. Returns True if a new group was created, otherwise False.
|
||||
*/
|
||||
public groupSelectedItems(): boolean {
|
||||
// Find the selection start & end, also check for gaps between selected items (if found, cannot proceed).
|
||||
var selection = this.getCheckedItemsInfo();
|
||||
|
||||
if (selection.canGroup) {
|
||||
var newGroup = new ClauseGroup(false, this);
|
||||
// Replace the selected items with the new group, and then move the selected items into the new group.
|
||||
var groupedItems = this.children.splice(selection.begin, selection.end - selection.begin + 1, newGroup);
|
||||
|
||||
groupedItems &&
|
||||
groupedItems.forEach((element) => {
|
||||
newGroup.children.push(element);
|
||||
|
||||
if (element instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>element).clauseGroup = newGroup;
|
||||
} else if (element instanceof ClauseGroup) {
|
||||
(<ClauseGroup>element).parentGroup = newGroup;
|
||||
}
|
||||
});
|
||||
|
||||
this.unselectAll();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public ungroup(): void {
|
||||
if (this.isRootGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parentGroup = this.parentGroup;
|
||||
var index = parentGroup.children.indexOf(this);
|
||||
|
||||
if (index >= 0) {
|
||||
parentGroup.children.splice(index, 1);
|
||||
|
||||
var toPromote = this.children.splice(0, this.children.length);
|
||||
|
||||
// Move all children one level up.
|
||||
toPromote &&
|
||||
toPromote.forEach((element) => {
|
||||
if (element instanceof ClauseGroup) {
|
||||
(<ClauseGroup>element).parentGroup = parentGroup;
|
||||
} else if (element instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>element).clauseGroup = parentGroup;
|
||||
}
|
||||
|
||||
parentGroup.children.splice(index, 0, element);
|
||||
index++;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public canGroupSelectedItems(): boolean {
|
||||
return this.getCheckedItemsInfo().canGroup;
|
||||
}
|
||||
|
||||
public findDeepestGroupInChildren(skipIndex?: number): ClauseGroup {
|
||||
var deepest: ClauseGroup = this;
|
||||
var level: number = 0;
|
||||
var func = (currentGroup: ClauseGroup): void => {
|
||||
level++;
|
||||
if (currentGroup.getCurrentGroupDepth() > deepest.getCurrentGroupDepth()) {
|
||||
deepest = currentGroup;
|
||||
}
|
||||
|
||||
for (var i = 0; i < currentGroup.children.length; i++) {
|
||||
var currentItem = currentGroup.children[i];
|
||||
|
||||
if ((i !== skipIndex || level > 1) && currentItem instanceof ClauseGroup) {
|
||||
func(currentItem);
|
||||
}
|
||||
}
|
||||
level--;
|
||||
};
|
||||
|
||||
func(this);
|
||||
|
||||
return deepest;
|
||||
}
|
||||
|
||||
private getCheckedItemsInfo(): { canGroup: boolean; begin: number; end: number } {
|
||||
var beginIndex = -1;
|
||||
var endIndex = -1;
|
||||
// In order to perform group, all selected items must be next to each other.
|
||||
// If one or more items are not selected between the first and the last selected item, the gapFlag will be set to True, meaning cannot perform group.
|
||||
var gapFlag = false;
|
||||
var count = 0;
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
var subGroupSelectionState: { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean };
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
subGroupSelectionState = (<ClauseGroup>currentItem).getSelectionState();
|
||||
|
||||
if (subGroupSelectionState.partiallySelected) {
|
||||
gapFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
beginIndex < 0 &&
|
||||
endIndex < 0 &&
|
||||
((currentItem instanceof QueryClauseViewModel && currentItem.checkedForGrouping.peek()) ||
|
||||
(currentItem instanceof ClauseGroup && subGroupSelectionState.allSelected))
|
||||
) {
|
||||
beginIndex = i;
|
||||
}
|
||||
|
||||
if (
|
||||
beginIndex >= 0 &&
|
||||
endIndex < 0 &&
|
||||
((currentItem instanceof QueryClauseViewModel && !currentItem.checkedForGrouping.peek()) ||
|
||||
(currentItem instanceof ClauseGroup && !subGroupSelectionState.allSelected))
|
||||
) {
|
||||
endIndex = i - 1;
|
||||
}
|
||||
|
||||
if (beginIndex >= 0 && endIndex < 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (
|
||||
beginIndex >= 0 &&
|
||||
endIndex >= 0 &&
|
||||
((currentItem instanceof QueryClauseViewModel && currentItem.checkedForGrouping.peek()) ||
|
||||
(currentItem instanceof ClauseGroup && !subGroupSelectionState.nonSelected))
|
||||
) {
|
||||
gapFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!gapFlag && endIndex < 0) {
|
||||
endIndex = this.children.length - 1;
|
||||
}
|
||||
|
||||
return {
|
||||
canGroup: beginIndex >= 0 && !gapFlag && count > 1,
|
||||
begin: beginIndex,
|
||||
end: endIndex,
|
||||
};
|
||||
}
|
||||
|
||||
private getSelectionState(): { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean } {
|
||||
var selectedCount = 0;
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup && (<ClauseGroup>currentItem).getSelectionState().allSelected) {
|
||||
selectedCount++;
|
||||
}
|
||||
|
||||
if (
|
||||
currentItem instanceof QueryClauseViewModel &&
|
||||
(<QueryClauseViewModel>currentItem).checkedForGrouping.peek()
|
||||
) {
|
||||
selectedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
allSelected: selectedCount === this.children.length,
|
||||
partiallySelected: selectedCount > 0 && selectedCount < this.children.length,
|
||||
nonSelected: selectedCount === 0,
|
||||
};
|
||||
}
|
||||
|
||||
private unselectAll(): void {
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
(<ClauseGroup>currentItem).unselectAll();
|
||||
}
|
||||
|
||||
if (currentItem instanceof QueryClauseViewModel) {
|
||||
(<QueryClauseViewModel>currentItem).checkedForGrouping(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private flattenClausesImpl(queryGroup: ClauseGroup, targetArray: QueryClauseViewModel[]): void {
|
||||
if (queryGroup.isRootGroup) {
|
||||
targetArray.splice(0, targetArray.length);
|
||||
}
|
||||
|
||||
for (var i = 0; i < queryGroup.children.length; i++) {
|
||||
var currentItem = queryGroup.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
this.flattenClausesImpl(currentItem, targetArray);
|
||||
}
|
||||
|
||||
if (currentItem instanceof QueryClauseViewModel) {
|
||||
targetArray.push(currentItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getTreeDepth(): number {
|
||||
var currentDepth = this.getCurrentGroupDepth();
|
||||
|
||||
for (var i = 0; i < this.children.length; i++) {
|
||||
var currentItem = this.children[i];
|
||||
|
||||
if (currentItem instanceof ClauseGroup) {
|
||||
var newDepth = (<ClauseGroup>currentItem).getTreeDepth();
|
||||
|
||||
if (newDepth > currentDepth) {
|
||||
currentDepth = newDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentDepth;
|
||||
}
|
||||
|
||||
public getCurrentGroupDepth(): number {
|
||||
var group = <ClauseGroup>this;
|
||||
var depth = 0;
|
||||
|
||||
while (!group.isRootGroup) {
|
||||
depth++;
|
||||
group = group.parentGroup;
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
import * as ko from "knockout";
|
||||
import ClauseGroup from "./ClauseGroup";
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import * as Constants from "../Constants";
|
||||
|
||||
/**
|
||||
* View model for showing group indicators on UI, contains information such as group color and border styles.
|
||||
*/
|
||||
export default class ClauseGroupViewModel {
|
||||
public ungroupClausesLabel = "Ungroup clauses"; // localize
|
||||
|
||||
public backgroundColor: ko.Observable<string>;
|
||||
public canUngroup: ko.Observable<boolean>;
|
||||
public showTopBorder: ko.Observable<boolean>;
|
||||
public showLeftBorder: ko.Observable<boolean>;
|
||||
public showBottomBorder: ko.Observable<boolean>;
|
||||
public depth: ko.Observable<number>; // for debugging purpose only, now showing the number on UI.
|
||||
public borderBackgroundColor: ko.Observable<string>;
|
||||
|
||||
private _clauseGroup: ClauseGroup;
|
||||
private _queryBuilderViewModel: QueryBuilderViewModel;
|
||||
|
||||
constructor(clauseGroup: ClauseGroup, canUngroup: boolean, queryBuilderViewModel: QueryBuilderViewModel) {
|
||||
this._clauseGroup = clauseGroup;
|
||||
this._queryBuilderViewModel = queryBuilderViewModel;
|
||||
this.backgroundColor = ko.observable<string>(this.getGroupBackgroundColor(clauseGroup));
|
||||
this.canUngroup = ko.observable<boolean>(canUngroup);
|
||||
this.showTopBorder = ko.observable<boolean>(false);
|
||||
this.showLeftBorder = ko.observable<boolean>(false);
|
||||
this.showBottomBorder = ko.observable<boolean>(false);
|
||||
this.depth = ko.observable<number>(clauseGroup.getCurrentGroupDepth());
|
||||
this.borderBackgroundColor = ko.observable<string>("solid thin " + this.getGroupBackgroundColor(clauseGroup));
|
||||
}
|
||||
|
||||
public ungroupClauses = (): void => {
|
||||
this._clauseGroup.ungroup();
|
||||
this._queryBuilderViewModel.updateClauseArray();
|
||||
};
|
||||
|
||||
private getGroupBackgroundColor(group: ClauseGroup): string {
|
||||
var colorCount = Constants.clauseGroupColors.length;
|
||||
|
||||
if (group.isRootGroup) {
|
||||
return Constants.transparentColor;
|
||||
} else {
|
||||
return Constants.clauseGroupColors[group.getCurrentGroupDepth() % colorCount];
|
||||
}
|
||||
}
|
||||
}
|
||||
import * as ko from "knockout";
|
||||
import ClauseGroup from "./ClauseGroup";
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import * as Constants from "../Constants";
|
||||
|
||||
/**
|
||||
* View model for showing group indicators on UI, contains information such as group color and border styles.
|
||||
*/
|
||||
export default class ClauseGroupViewModel {
|
||||
public ungroupClausesLabel = "Ungroup clauses"; // localize
|
||||
|
||||
public backgroundColor: ko.Observable<string>;
|
||||
public canUngroup: ko.Observable<boolean>;
|
||||
public showTopBorder: ko.Observable<boolean>;
|
||||
public showLeftBorder: ko.Observable<boolean>;
|
||||
public showBottomBorder: ko.Observable<boolean>;
|
||||
public depth: ko.Observable<number>; // for debugging purpose only, now showing the number on UI.
|
||||
public borderBackgroundColor: ko.Observable<string>;
|
||||
|
||||
private _clauseGroup: ClauseGroup;
|
||||
private _queryBuilderViewModel: QueryBuilderViewModel;
|
||||
|
||||
constructor(clauseGroup: ClauseGroup, canUngroup: boolean, queryBuilderViewModel: QueryBuilderViewModel) {
|
||||
this._clauseGroup = clauseGroup;
|
||||
this._queryBuilderViewModel = queryBuilderViewModel;
|
||||
this.backgroundColor = ko.observable<string>(this.getGroupBackgroundColor(clauseGroup));
|
||||
this.canUngroup = ko.observable<boolean>(canUngroup);
|
||||
this.showTopBorder = ko.observable<boolean>(false);
|
||||
this.showLeftBorder = ko.observable<boolean>(false);
|
||||
this.showBottomBorder = ko.observable<boolean>(false);
|
||||
this.depth = ko.observable<number>(clauseGroup.getCurrentGroupDepth());
|
||||
this.borderBackgroundColor = ko.observable<string>("solid thin " + this.getGroupBackgroundColor(clauseGroup));
|
||||
}
|
||||
|
||||
public ungroupClauses = (): void => {
|
||||
this._clauseGroup.ungroup();
|
||||
this._queryBuilderViewModel.updateClauseArray();
|
||||
};
|
||||
|
||||
private getGroupBackgroundColor(group: ClauseGroup): string {
|
||||
var colorCount = Constants.clauseGroupColors.length;
|
||||
|
||||
if (group.isRootGroup) {
|
||||
return Constants.transparentColor;
|
||||
} else {
|
||||
return Constants.clauseGroupColors[group.getCurrentGroupDepth() % colorCount];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,377 +1,377 @@
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import * as DateTimeUtilities from "./DateTimeUtilities";
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
export var utc = "utc";
|
||||
export var local = "local";
|
||||
|
||||
export interface ITimestampQuery {
|
||||
queryType: string; // valid values are "last" and "range"
|
||||
lastNumber: number; // number value of a custom timestamp using the last option
|
||||
lastTimeUnit: string; // timeunit of a custom timestamp using the last option
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
timeZone: string; // timezone of custom range timestamp, valid values are "local" and "utc"
|
||||
}
|
||||
|
||||
export interface ILastQuery {
|
||||
lastNumber: number;
|
||||
lastTimeUnit: string;
|
||||
}
|
||||
|
||||
export enum TimeUnit {
|
||||
Seconds,
|
||||
Minutes,
|
||||
Hours,
|
||||
Days
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting helpers
|
||||
*/
|
||||
|
||||
export function addRangeTimestamp(
|
||||
timestamp: ITimestampQuery,
|
||||
queryBuilderViewModel: QueryBuilderViewModel,
|
||||
queryClauseViewModel: QueryClauseViewModel
|
||||
): void {
|
||||
queryBuilderViewModel.addCustomRange(timestamp, queryClauseViewModel);
|
||||
}
|
||||
|
||||
export function getDefaultStart(localTime: boolean, durationHours: number = 24): string {
|
||||
var startTimestamp: string;
|
||||
|
||||
var utcNowString: string = new Date().toISOString();
|
||||
var yesterday: Date = new Date(utcNowString);
|
||||
|
||||
yesterday.setHours(yesterday.getHours() - durationHours);
|
||||
startTimestamp = yesterday.toISOString();
|
||||
|
||||
if (localTime) {
|
||||
startTimestamp = localFromUtcDateString(startTimestamp);
|
||||
}
|
||||
|
||||
return startTimestamp;
|
||||
}
|
||||
|
||||
export function getDefaultEnd(localTime: boolean): string {
|
||||
var endTimestamp: string;
|
||||
|
||||
var utcNowString: string = new Date().toISOString();
|
||||
|
||||
endTimestamp = utcNowString;
|
||||
|
||||
if (localTime) {
|
||||
endTimestamp = localFromUtcDateString(endTimestamp);
|
||||
}
|
||||
|
||||
return endTimestamp;
|
||||
}
|
||||
|
||||
export function parseDate(dateString: string, isUTC: boolean): Date {
|
||||
// TODO validate dateString
|
||||
var date: Date = null;
|
||||
|
||||
if (dateString) {
|
||||
try {
|
||||
// Date string is assumed to be UTC in Storage Explorer Standalone.
|
||||
// Behavior may vary in other browsers.
|
||||
// Here's an example of how the string looks like "2015-10-24T21:44:12"
|
||||
var millisecondTime = Date.parse(dateString),
|
||||
parsed: Date = new Date(millisecondTime);
|
||||
|
||||
if (isUTC) {
|
||||
date = parsed;
|
||||
} else {
|
||||
// Since we parsed in UTC, accessors are flipped - we get local time from the getUTC* group
|
||||
// Reinstating, the date is parsed above as UTC, and here we are creating a new date object
|
||||
// in local time.
|
||||
var year = parsed.getUTCFullYear(),
|
||||
month = parsed.getUTCMonth(),
|
||||
day = parsed.getUTCDate(),
|
||||
hours = parsed.getUTCHours(),
|
||||
minutes = parsed.getUTCMinutes(),
|
||||
seconds = parsed.getUTCSeconds(),
|
||||
milliseconds = parsed.getUTCMilliseconds();
|
||||
|
||||
date = new Date(year, month, day, hours, minutes, seconds, milliseconds);
|
||||
}
|
||||
} catch (error) {
|
||||
//Debug.error("Error parsing date string: ", dateString, error);
|
||||
}
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
export function utcFromLocalDateString(localDateString: string): string {
|
||||
// TODO validate localDateString
|
||||
var localDate = parseDate(localDateString, false),
|
||||
utcDateString: string = null;
|
||||
|
||||
if (localDate) {
|
||||
utcDateString = localDate.toISOString();
|
||||
}
|
||||
|
||||
return utcDateString;
|
||||
}
|
||||
|
||||
function padIfNeeded(value: number): string {
|
||||
var padded: string = String(value);
|
||||
|
||||
if (0 <= value && value < 10) {
|
||||
padded = "0" + padded;
|
||||
}
|
||||
|
||||
return padded;
|
||||
}
|
||||
|
||||
function toLocalDateString(date: Date): string {
|
||||
var localDateString: string = null;
|
||||
|
||||
if (date) {
|
||||
localDateString =
|
||||
date.getFullYear() +
|
||||
"-" +
|
||||
padIfNeeded(date.getMonth() + 1) +
|
||||
"-" +
|
||||
padIfNeeded(date.getDate()) +
|
||||
"T" +
|
||||
padIfNeeded(date.getHours()) +
|
||||
":" +
|
||||
padIfNeeded(date.getMinutes()) +
|
||||
":" +
|
||||
padIfNeeded(date.getSeconds());
|
||||
}
|
||||
|
||||
return localDateString;
|
||||
}
|
||||
|
||||
export function localFromUtcDateString(utcDateString: string): string {
|
||||
// TODO validate utcDateString
|
||||
var utcDate: Date = parseDate(utcDateString, true),
|
||||
localDateString: string = null;
|
||||
|
||||
if (utcDate) {
|
||||
localDateString = toLocalDateString(utcDate);
|
||||
}
|
||||
|
||||
return localDateString;
|
||||
}
|
||||
|
||||
export function tryChangeTimestampTimeZone(koTimestamp: ko.Observable<string>, toUTC: boolean): void {
|
||||
if (koTimestamp) {
|
||||
var currentDateString: string = koTimestamp(),
|
||||
newDateString: string;
|
||||
|
||||
if (currentDateString) {
|
||||
if (toUTC) {
|
||||
newDateString = utcFromLocalDateString(currentDateString);
|
||||
// removing last character because cannot format it to html binding with the 'Z' at the end
|
||||
newDateString = newDateString.substring(0, newDateString.length - 1);
|
||||
} else {
|
||||
newDateString = localFromUtcDateString(currentDateString);
|
||||
}
|
||||
|
||||
// utcFromLocalDateString and localFromUtcDateString could return null if currentDateString is invalid.
|
||||
// Hence, only set koTimestamp if newDateString is not null.
|
||||
if (newDateString) {
|
||||
koTimestamp(newDateString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Input validation helpers
|
||||
*/
|
||||
|
||||
export var noTooltip = "",
|
||||
invalidStartTimeTooltip = "Please provide a valid start time.", // localize
|
||||
invalidExpiryTimeRequiredTooltip = "Required field. Please provide a valid expiry time.", // localize
|
||||
invalidExpiryTimeGreaterThanStartTimeTooltip = "The expiry time must be greater than the start time."; // localize
|
||||
|
||||
export function isDateString(dateString: string): boolean {
|
||||
var success: boolean = false;
|
||||
|
||||
if (dateString) {
|
||||
var date: number = Date.parse(dateString);
|
||||
|
||||
success = $.isNumeric(date);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Is date string and earlier than expiry time; or is empty
|
||||
// export function isInvalidStartTimeInput(startTimestamp: string, expiryTimestamp: string, isUTC: boolean): DialogsCommon.IValidationResult {
|
||||
// var tooltip: string = noTooltip,
|
||||
// isValid: boolean = isDateString(startTimestamp),
|
||||
// startDate: Date,
|
||||
// expiryDate: Date;
|
||||
|
||||
// if (!isValid) {
|
||||
// isValid = (startTimestamp === "");
|
||||
// }
|
||||
|
||||
// if (!isValid) {
|
||||
// tooltip = invalidStartTimeTooltip;
|
||||
// }
|
||||
|
||||
// if (isValid && !!startTimestamp && isDateString(expiryTimestamp)) {
|
||||
// startDate = parseDate(startTimestamp, isUTC);
|
||||
// expiryDate = parseDate(expiryTimestamp, isUTC);
|
||||
|
||||
// isValid = (startDate < expiryDate);
|
||||
|
||||
// if (!isValid) {
|
||||
// tooltip = invalidExpiryTimeGreaterThanStartTimeTooltip;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return { isInvalid: !isValid, help: tooltip };
|
||||
// }
|
||||
|
||||
// Is date string, and later than start time (if any)
|
||||
// export function isInvalidExpiryTimeInput(startTimestamp: string, expiryTimestamp: string, isUTC: boolean): DialogsCommon.IValidationResult {
|
||||
// var isValid: boolean = isDateString(expiryTimestamp),
|
||||
// tooltip: string = isValid ? noTooltip : invalidExpiryTimeRequiredTooltip,
|
||||
// startDate: Date,
|
||||
// expiryDate: Date;
|
||||
|
||||
// if (isValid && startTimestamp) {
|
||||
// if (isDateString(startTimestamp)) {
|
||||
// startDate = parseDate(startTimestamp, isUTC);
|
||||
// expiryDate = parseDate(expiryTimestamp, isUTC);
|
||||
// isValid = (startDate < expiryDate);
|
||||
|
||||
// if (!isValid) {
|
||||
// tooltip = invalidExpiryTimeGreaterThanStartTimeTooltip;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return { isInvalid: !isValid, help: tooltip };
|
||||
// }
|
||||
|
||||
/**
|
||||
* Functions to calculate DateTime Strings
|
||||
*/
|
||||
|
||||
function _getLocalIsoDateTimeString(time: Date): string {
|
||||
// yyyy-mm-ddThh:mm:ss.sss
|
||||
// Not using the timezone offset (or 'Z'), which will make the
|
||||
// date/time represent local time by default.
|
||||
// var formatted = _string.sprintf(
|
||||
// "%sT%02d:%02d:%02d.%03d",
|
||||
// _getLocalIsoDateString(time),
|
||||
// time.getHours(),
|
||||
// time.getMinutes(),
|
||||
// time.getSeconds(),
|
||||
// time.getMilliseconds()
|
||||
// );
|
||||
// return formatted;
|
||||
return (
|
||||
_getLocalIsoDateString(time) +
|
||||
"T" +
|
||||
DateTimeUtilities.ensureDoubleDigits(time.getHours()) +
|
||||
":" +
|
||||
DateTimeUtilities.ensureDoubleDigits(time.getMinutes()) +
|
||||
":" +
|
||||
DateTimeUtilities.ensureDoubleDigits(time.getSeconds()) +
|
||||
"." +
|
||||
DateTimeUtilities.ensureTripleDigits(time.getMilliseconds())
|
||||
);
|
||||
}
|
||||
|
||||
function _getLocalIsoDateString(date: Date): string {
|
||||
return _getLocalIsoDateStringFromParts(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
}
|
||||
|
||||
function _getLocalIsoDateStringFromParts(
|
||||
fullYear: number,
|
||||
month: number /* 0..11 */,
|
||||
date: number /* 1..31 */
|
||||
): string {
|
||||
month = month + 1;
|
||||
return (
|
||||
fullYear + "-" + DateTimeUtilities.ensureDoubleDigits(month) + "-" + DateTimeUtilities.ensureDoubleDigits(date)
|
||||
);
|
||||
// return _string.sprintf(
|
||||
// "%04d-%02d-%02d",
|
||||
// fullYear,
|
||||
// month + 1, // JS month is 0..11
|
||||
// date); // but date is 1..31
|
||||
}
|
||||
|
||||
function _addDaysHours(time: Date, days: number, hours: number): Date {
|
||||
var msPerHour = 1000 * 60 * 60;
|
||||
var daysMs = days * msPerHour * 24;
|
||||
var hoursMs = hours * msPerHour;
|
||||
var newTimeMs = time.getTime() + daysMs + hoursMs;
|
||||
return new Date(newTimeMs);
|
||||
}
|
||||
|
||||
function _daysHoursBeforeNow(days: number, hours: number): Date {
|
||||
return _addDaysHours(new Date(), -days, -hours);
|
||||
}
|
||||
|
||||
export function _queryLastDaysHours(days: number, hours: number): string {
|
||||
/* tslint:disable: no-unused-variable */
|
||||
var daysHoursAgo = _getLocalIsoDateTimeString(_daysHoursBeforeNow(days, hours));
|
||||
daysHoursAgo = DateTimeUtilities.getUTCDateTime(daysHoursAgo);
|
||||
|
||||
return daysHoursAgo;
|
||||
/* tslint:enable: no-unused-variable */
|
||||
}
|
||||
|
||||
export function _queryCurrentMonthLocal(): string {
|
||||
var now = new Date();
|
||||
var start = _getLocalIsoDateStringFromParts(now.getFullYear(), now.getMonth(), 1);
|
||||
start = DateTimeUtilities.getUTCDateTime(start);
|
||||
return start;
|
||||
}
|
||||
|
||||
export function _queryCurrentYearLocal(): string {
|
||||
var now = new Date();
|
||||
var start = _getLocalIsoDateStringFromParts(now.getFullYear(), 0, 1); // Month is 0..11, date is 1..31
|
||||
start = DateTimeUtilities.getUTCDateTime(start);
|
||||
return start;
|
||||
}
|
||||
|
||||
function _addTime(time: Date, lastNumber: number, timeUnit: string): Date {
|
||||
var timeMS: number;
|
||||
switch (TimeUnit[Number(timeUnit)]) {
|
||||
case TimeUnit.Days.toString():
|
||||
timeMS = lastNumber * 1000 * 60 * 60 * 24;
|
||||
break;
|
||||
case TimeUnit.Hours.toString():
|
||||
timeMS = lastNumber * 1000 * 60 * 60;
|
||||
break;
|
||||
case TimeUnit.Minutes.toString():
|
||||
timeMS = lastNumber * 1000 * 60;
|
||||
break;
|
||||
case TimeUnit.Seconds.toString():
|
||||
timeMS = lastNumber * 1000;
|
||||
break;
|
||||
default:
|
||||
//throw new Errors.ArgumentOutOfRangeError(timeUnit);
|
||||
}
|
||||
var newTimeMS = time.getTime() + timeMS;
|
||||
return new Date(newTimeMS);
|
||||
}
|
||||
|
||||
function _timeBeforeNow(lastNumber: number, timeUnit: string): Date {
|
||||
return _addTime(new Date(), -lastNumber, timeUnit);
|
||||
}
|
||||
|
||||
export function _queryLastTime(lastNumber: number, timeUnit: string): string {
|
||||
/* tslint:disable: no-unused-variable */
|
||||
var daysHoursAgo = _getLocalIsoDateTimeString(_timeBeforeNow(lastNumber, timeUnit));
|
||||
daysHoursAgo = DateTimeUtilities.getUTCDateTime(daysHoursAgo);
|
||||
return daysHoursAgo;
|
||||
/* tslint:enable: no-unused-variable */
|
||||
}
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import * as DateTimeUtilities from "./DateTimeUtilities";
|
||||
|
||||
/**
|
||||
* Constants
|
||||
*/
|
||||
export var utc = "utc";
|
||||
export var local = "local";
|
||||
|
||||
export interface ITimestampQuery {
|
||||
queryType: string; // valid values are "last" and "range"
|
||||
lastNumber: number; // number value of a custom timestamp using the last option
|
||||
lastTimeUnit: string; // timeunit of a custom timestamp using the last option
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
timeZone: string; // timezone of custom range timestamp, valid values are "local" and "utc"
|
||||
}
|
||||
|
||||
export interface ILastQuery {
|
||||
lastNumber: number;
|
||||
lastTimeUnit: string;
|
||||
}
|
||||
|
||||
export enum TimeUnit {
|
||||
Seconds,
|
||||
Minutes,
|
||||
Hours,
|
||||
Days,
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting helpers
|
||||
*/
|
||||
|
||||
export function addRangeTimestamp(
|
||||
timestamp: ITimestampQuery,
|
||||
queryBuilderViewModel: QueryBuilderViewModel,
|
||||
queryClauseViewModel: QueryClauseViewModel
|
||||
): void {
|
||||
queryBuilderViewModel.addCustomRange(timestamp, queryClauseViewModel);
|
||||
}
|
||||
|
||||
export function getDefaultStart(localTime: boolean, durationHours: number = 24): string {
|
||||
var startTimestamp: string;
|
||||
|
||||
var utcNowString: string = new Date().toISOString();
|
||||
var yesterday: Date = new Date(utcNowString);
|
||||
|
||||
yesterday.setHours(yesterday.getHours() - durationHours);
|
||||
startTimestamp = yesterday.toISOString();
|
||||
|
||||
if (localTime) {
|
||||
startTimestamp = localFromUtcDateString(startTimestamp);
|
||||
}
|
||||
|
||||
return startTimestamp;
|
||||
}
|
||||
|
||||
export function getDefaultEnd(localTime: boolean): string {
|
||||
var endTimestamp: string;
|
||||
|
||||
var utcNowString: string = new Date().toISOString();
|
||||
|
||||
endTimestamp = utcNowString;
|
||||
|
||||
if (localTime) {
|
||||
endTimestamp = localFromUtcDateString(endTimestamp);
|
||||
}
|
||||
|
||||
return endTimestamp;
|
||||
}
|
||||
|
||||
export function parseDate(dateString: string, isUTC: boolean): Date {
|
||||
// TODO validate dateString
|
||||
var date: Date = null;
|
||||
|
||||
if (dateString) {
|
||||
try {
|
||||
// Date string is assumed to be UTC in Storage Explorer Standalone.
|
||||
// Behavior may vary in other browsers.
|
||||
// Here's an example of how the string looks like "2015-10-24T21:44:12"
|
||||
var millisecondTime = Date.parse(dateString),
|
||||
parsed: Date = new Date(millisecondTime);
|
||||
|
||||
if (isUTC) {
|
||||
date = parsed;
|
||||
} else {
|
||||
// Since we parsed in UTC, accessors are flipped - we get local time from the getUTC* group
|
||||
// Reinstating, the date is parsed above as UTC, and here we are creating a new date object
|
||||
// in local time.
|
||||
var year = parsed.getUTCFullYear(),
|
||||
month = parsed.getUTCMonth(),
|
||||
day = parsed.getUTCDate(),
|
||||
hours = parsed.getUTCHours(),
|
||||
minutes = parsed.getUTCMinutes(),
|
||||
seconds = parsed.getUTCSeconds(),
|
||||
milliseconds = parsed.getUTCMilliseconds();
|
||||
|
||||
date = new Date(year, month, day, hours, minutes, seconds, milliseconds);
|
||||
}
|
||||
} catch (error) {
|
||||
//Debug.error("Error parsing date string: ", dateString, error);
|
||||
}
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
export function utcFromLocalDateString(localDateString: string): string {
|
||||
// TODO validate localDateString
|
||||
var localDate = parseDate(localDateString, false),
|
||||
utcDateString: string = null;
|
||||
|
||||
if (localDate) {
|
||||
utcDateString = localDate.toISOString();
|
||||
}
|
||||
|
||||
return utcDateString;
|
||||
}
|
||||
|
||||
function padIfNeeded(value: number): string {
|
||||
var padded: string = String(value);
|
||||
|
||||
if (0 <= value && value < 10) {
|
||||
padded = "0" + padded;
|
||||
}
|
||||
|
||||
return padded;
|
||||
}
|
||||
|
||||
function toLocalDateString(date: Date): string {
|
||||
var localDateString: string = null;
|
||||
|
||||
if (date) {
|
||||
localDateString =
|
||||
date.getFullYear() +
|
||||
"-" +
|
||||
padIfNeeded(date.getMonth() + 1) +
|
||||
"-" +
|
||||
padIfNeeded(date.getDate()) +
|
||||
"T" +
|
||||
padIfNeeded(date.getHours()) +
|
||||
":" +
|
||||
padIfNeeded(date.getMinutes()) +
|
||||
":" +
|
||||
padIfNeeded(date.getSeconds());
|
||||
}
|
||||
|
||||
return localDateString;
|
||||
}
|
||||
|
||||
export function localFromUtcDateString(utcDateString: string): string {
|
||||
// TODO validate utcDateString
|
||||
var utcDate: Date = parseDate(utcDateString, true),
|
||||
localDateString: string = null;
|
||||
|
||||
if (utcDate) {
|
||||
localDateString = toLocalDateString(utcDate);
|
||||
}
|
||||
|
||||
return localDateString;
|
||||
}
|
||||
|
||||
export function tryChangeTimestampTimeZone(koTimestamp: ko.Observable<string>, toUTC: boolean): void {
|
||||
if (koTimestamp) {
|
||||
var currentDateString: string = koTimestamp(),
|
||||
newDateString: string;
|
||||
|
||||
if (currentDateString) {
|
||||
if (toUTC) {
|
||||
newDateString = utcFromLocalDateString(currentDateString);
|
||||
// removing last character because cannot format it to html binding with the 'Z' at the end
|
||||
newDateString = newDateString.substring(0, newDateString.length - 1);
|
||||
} else {
|
||||
newDateString = localFromUtcDateString(currentDateString);
|
||||
}
|
||||
|
||||
// utcFromLocalDateString and localFromUtcDateString could return null if currentDateString is invalid.
|
||||
// Hence, only set koTimestamp if newDateString is not null.
|
||||
if (newDateString) {
|
||||
koTimestamp(newDateString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Input validation helpers
|
||||
*/
|
||||
|
||||
export var noTooltip = "",
|
||||
invalidStartTimeTooltip = "Please provide a valid start time.", // localize
|
||||
invalidExpiryTimeRequiredTooltip = "Required field. Please provide a valid expiry time.", // localize
|
||||
invalidExpiryTimeGreaterThanStartTimeTooltip = "The expiry time must be greater than the start time."; // localize
|
||||
|
||||
export function isDateString(dateString: string): boolean {
|
||||
var success: boolean = false;
|
||||
|
||||
if (dateString) {
|
||||
var date: number = Date.parse(dateString);
|
||||
|
||||
success = $.isNumeric(date);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Is date string and earlier than expiry time; or is empty
|
||||
// export function isInvalidStartTimeInput(startTimestamp: string, expiryTimestamp: string, isUTC: boolean): DialogsCommon.IValidationResult {
|
||||
// var tooltip: string = noTooltip,
|
||||
// isValid: boolean = isDateString(startTimestamp),
|
||||
// startDate: Date,
|
||||
// expiryDate: Date;
|
||||
|
||||
// if (!isValid) {
|
||||
// isValid = (startTimestamp === "");
|
||||
// }
|
||||
|
||||
// if (!isValid) {
|
||||
// tooltip = invalidStartTimeTooltip;
|
||||
// }
|
||||
|
||||
// if (isValid && !!startTimestamp && isDateString(expiryTimestamp)) {
|
||||
// startDate = parseDate(startTimestamp, isUTC);
|
||||
// expiryDate = parseDate(expiryTimestamp, isUTC);
|
||||
|
||||
// isValid = (startDate < expiryDate);
|
||||
|
||||
// if (!isValid) {
|
||||
// tooltip = invalidExpiryTimeGreaterThanStartTimeTooltip;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return { isInvalid: !isValid, help: tooltip };
|
||||
// }
|
||||
|
||||
// Is date string, and later than start time (if any)
|
||||
// export function isInvalidExpiryTimeInput(startTimestamp: string, expiryTimestamp: string, isUTC: boolean): DialogsCommon.IValidationResult {
|
||||
// var isValid: boolean = isDateString(expiryTimestamp),
|
||||
// tooltip: string = isValid ? noTooltip : invalidExpiryTimeRequiredTooltip,
|
||||
// startDate: Date,
|
||||
// expiryDate: Date;
|
||||
|
||||
// if (isValid && startTimestamp) {
|
||||
// if (isDateString(startTimestamp)) {
|
||||
// startDate = parseDate(startTimestamp, isUTC);
|
||||
// expiryDate = parseDate(expiryTimestamp, isUTC);
|
||||
// isValid = (startDate < expiryDate);
|
||||
|
||||
// if (!isValid) {
|
||||
// tooltip = invalidExpiryTimeGreaterThanStartTimeTooltip;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return { isInvalid: !isValid, help: tooltip };
|
||||
// }
|
||||
|
||||
/**
|
||||
* Functions to calculate DateTime Strings
|
||||
*/
|
||||
|
||||
function _getLocalIsoDateTimeString(time: Date): string {
|
||||
// yyyy-mm-ddThh:mm:ss.sss
|
||||
// Not using the timezone offset (or 'Z'), which will make the
|
||||
// date/time represent local time by default.
|
||||
// var formatted = _string.sprintf(
|
||||
// "%sT%02d:%02d:%02d.%03d",
|
||||
// _getLocalIsoDateString(time),
|
||||
// time.getHours(),
|
||||
// time.getMinutes(),
|
||||
// time.getSeconds(),
|
||||
// time.getMilliseconds()
|
||||
// );
|
||||
// return formatted;
|
||||
return (
|
||||
_getLocalIsoDateString(time) +
|
||||
"T" +
|
||||
DateTimeUtilities.ensureDoubleDigits(time.getHours()) +
|
||||
":" +
|
||||
DateTimeUtilities.ensureDoubleDigits(time.getMinutes()) +
|
||||
":" +
|
||||
DateTimeUtilities.ensureDoubleDigits(time.getSeconds()) +
|
||||
"." +
|
||||
DateTimeUtilities.ensureTripleDigits(time.getMilliseconds())
|
||||
);
|
||||
}
|
||||
|
||||
function _getLocalIsoDateString(date: Date): string {
|
||||
return _getLocalIsoDateStringFromParts(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
}
|
||||
|
||||
function _getLocalIsoDateStringFromParts(
|
||||
fullYear: number,
|
||||
month: number /* 0..11 */,
|
||||
date: number /* 1..31 */
|
||||
): string {
|
||||
month = month + 1;
|
||||
return (
|
||||
fullYear + "-" + DateTimeUtilities.ensureDoubleDigits(month) + "-" + DateTimeUtilities.ensureDoubleDigits(date)
|
||||
);
|
||||
// return _string.sprintf(
|
||||
// "%04d-%02d-%02d",
|
||||
// fullYear,
|
||||
// month + 1, // JS month is 0..11
|
||||
// date); // but date is 1..31
|
||||
}
|
||||
|
||||
function _addDaysHours(time: Date, days: number, hours: number): Date {
|
||||
var msPerHour = 1000 * 60 * 60;
|
||||
var daysMs = days * msPerHour * 24;
|
||||
var hoursMs = hours * msPerHour;
|
||||
var newTimeMs = time.getTime() + daysMs + hoursMs;
|
||||
return new Date(newTimeMs);
|
||||
}
|
||||
|
||||
function _daysHoursBeforeNow(days: number, hours: number): Date {
|
||||
return _addDaysHours(new Date(), -days, -hours);
|
||||
}
|
||||
|
||||
export function _queryLastDaysHours(days: number, hours: number): string {
|
||||
/* tslint:disable: no-unused-variable */
|
||||
var daysHoursAgo = _getLocalIsoDateTimeString(_daysHoursBeforeNow(days, hours));
|
||||
daysHoursAgo = DateTimeUtilities.getUTCDateTime(daysHoursAgo);
|
||||
|
||||
return daysHoursAgo;
|
||||
/* tslint:enable: no-unused-variable */
|
||||
}
|
||||
|
||||
export function _queryCurrentMonthLocal(): string {
|
||||
var now = new Date();
|
||||
var start = _getLocalIsoDateStringFromParts(now.getFullYear(), now.getMonth(), 1);
|
||||
start = DateTimeUtilities.getUTCDateTime(start);
|
||||
return start;
|
||||
}
|
||||
|
||||
export function _queryCurrentYearLocal(): string {
|
||||
var now = new Date();
|
||||
var start = _getLocalIsoDateStringFromParts(now.getFullYear(), 0, 1); // Month is 0..11, date is 1..31
|
||||
start = DateTimeUtilities.getUTCDateTime(start);
|
||||
return start;
|
||||
}
|
||||
|
||||
function _addTime(time: Date, lastNumber: number, timeUnit: string): Date {
|
||||
var timeMS: number;
|
||||
switch (TimeUnit[Number(timeUnit)]) {
|
||||
case TimeUnit.Days.toString():
|
||||
timeMS = lastNumber * 1000 * 60 * 60 * 24;
|
||||
break;
|
||||
case TimeUnit.Hours.toString():
|
||||
timeMS = lastNumber * 1000 * 60 * 60;
|
||||
break;
|
||||
case TimeUnit.Minutes.toString():
|
||||
timeMS = lastNumber * 1000 * 60;
|
||||
break;
|
||||
case TimeUnit.Seconds.toString():
|
||||
timeMS = lastNumber * 1000;
|
||||
break;
|
||||
default:
|
||||
//throw new Errors.ArgumentOutOfRangeError(timeUnit);
|
||||
}
|
||||
var newTimeMS = time.getTime() + timeMS;
|
||||
return new Date(newTimeMS);
|
||||
}
|
||||
|
||||
function _timeBeforeNow(lastNumber: number, timeUnit: string): Date {
|
||||
return _addTime(new Date(), -lastNumber, timeUnit);
|
||||
}
|
||||
|
||||
export function _queryLastTime(lastNumber: number, timeUnit: string): string {
|
||||
/* tslint:disable: no-unused-variable */
|
||||
var daysHoursAgo = _getLocalIsoDateTimeString(_timeBeforeNow(lastNumber, timeUnit));
|
||||
daysHoursAgo = DateTimeUtilities.getUTCDateTime(daysHoursAgo);
|
||||
return daysHoursAgo;
|
||||
/* tslint:enable: no-unused-variable */
|
||||
}
|
||||
|
||||
@@ -1,67 +1,67 @@
|
||||
const epochTicks = 621355968000000000;
|
||||
const ticksPerMillisecond = 10000;
|
||||
|
||||
export function getLocalDateTime(dateTime: string): string {
|
||||
var dateTimeObject: Date = new Date(dateTime);
|
||||
var year: number = dateTimeObject.getFullYear();
|
||||
var month: string = ensureDoubleDigits(dateTimeObject.getMonth() + 1); // Month ranges from 0 to 11
|
||||
var day: string = ensureDoubleDigits(dateTimeObject.getDate());
|
||||
var hours: string = ensureDoubleDigits(dateTimeObject.getHours());
|
||||
var minutes: string = ensureDoubleDigits(dateTimeObject.getMinutes());
|
||||
var seconds: string = ensureDoubleDigits(dateTimeObject.getSeconds());
|
||||
var milliseconds: string = ensureTripleDigits(dateTimeObject.getMilliseconds());
|
||||
|
||||
var localDateTime: string = `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}`;
|
||||
return localDateTime;
|
||||
}
|
||||
|
||||
export function getUTCDateTime(dateTime: string): string {
|
||||
var dateTimeObject: Date = new Date(dateTime);
|
||||
return dateTimeObject.toISOString();
|
||||
}
|
||||
|
||||
export function ensureDoubleDigits(num: number): string {
|
||||
var doubleDigitsString: string = num.toString();
|
||||
if (num < 10) {
|
||||
doubleDigitsString = `0${doubleDigitsString}`;
|
||||
} else if (num > 99) {
|
||||
doubleDigitsString = doubleDigitsString.substring(0, 2);
|
||||
}
|
||||
return doubleDigitsString;
|
||||
}
|
||||
|
||||
export function ensureTripleDigits(num: number): string {
|
||||
var tripleDigitsString: string = num.toString();
|
||||
if (num < 10) {
|
||||
tripleDigitsString = `00${tripleDigitsString}`;
|
||||
} else if (num < 100) {
|
||||
tripleDigitsString = `0${tripleDigitsString}`;
|
||||
} else if (num > 999) {
|
||||
tripleDigitsString = tripleDigitsString.substring(0, 3);
|
||||
}
|
||||
return tripleDigitsString;
|
||||
}
|
||||
|
||||
export function convertUnixToJSDate(unixTime: number): Date {
|
||||
return new Date(unixTime * 1000);
|
||||
}
|
||||
|
||||
export function convertJSDateToUnix(dateTime: string): number {
|
||||
return Number((new Date(dateTime).getTime() / 1000).toFixed(0));
|
||||
}
|
||||
|
||||
export function convertTicksToJSDate(ticks: string): Date {
|
||||
var ticksJSBased = Number(ticks) - epochTicks;
|
||||
var timeInMillisecond = ticksJSBased / ticksPerMillisecond;
|
||||
return new Date(timeInMillisecond);
|
||||
}
|
||||
|
||||
export function convertJSDateToTicksWithPadding(dateTime: string): string {
|
||||
var ticks = epochTicks + new Date(dateTime).getTime() * ticksPerMillisecond;
|
||||
return padDateTicksWithZeros(ticks.toString());
|
||||
}
|
||||
|
||||
function padDateTicksWithZeros(value: string): string {
|
||||
var s = "0000000000000000000" + value;
|
||||
return s.substr(s.length - 20);
|
||||
}
|
||||
const epochTicks = 621355968000000000;
|
||||
const ticksPerMillisecond = 10000;
|
||||
|
||||
export function getLocalDateTime(dateTime: string): string {
|
||||
var dateTimeObject: Date = new Date(dateTime);
|
||||
var year: number = dateTimeObject.getFullYear();
|
||||
var month: string = ensureDoubleDigits(dateTimeObject.getMonth() + 1); // Month ranges from 0 to 11
|
||||
var day: string = ensureDoubleDigits(dateTimeObject.getDate());
|
||||
var hours: string = ensureDoubleDigits(dateTimeObject.getHours());
|
||||
var minutes: string = ensureDoubleDigits(dateTimeObject.getMinutes());
|
||||
var seconds: string = ensureDoubleDigits(dateTimeObject.getSeconds());
|
||||
var milliseconds: string = ensureTripleDigits(dateTimeObject.getMilliseconds());
|
||||
|
||||
var localDateTime: string = `${year}-${month}-${day}T${hours}:${minutes}:${seconds}.${milliseconds}`;
|
||||
return localDateTime;
|
||||
}
|
||||
|
||||
export function getUTCDateTime(dateTime: string): string {
|
||||
var dateTimeObject: Date = new Date(dateTime);
|
||||
return dateTimeObject.toISOString();
|
||||
}
|
||||
|
||||
export function ensureDoubleDigits(num: number): string {
|
||||
var doubleDigitsString: string = num.toString();
|
||||
if (num < 10) {
|
||||
doubleDigitsString = `0${doubleDigitsString}`;
|
||||
} else if (num > 99) {
|
||||
doubleDigitsString = doubleDigitsString.substring(0, 2);
|
||||
}
|
||||
return doubleDigitsString;
|
||||
}
|
||||
|
||||
export function ensureTripleDigits(num: number): string {
|
||||
var tripleDigitsString: string = num.toString();
|
||||
if (num < 10) {
|
||||
tripleDigitsString = `00${tripleDigitsString}`;
|
||||
} else if (num < 100) {
|
||||
tripleDigitsString = `0${tripleDigitsString}`;
|
||||
} else if (num > 999) {
|
||||
tripleDigitsString = tripleDigitsString.substring(0, 3);
|
||||
}
|
||||
return tripleDigitsString;
|
||||
}
|
||||
|
||||
export function convertUnixToJSDate(unixTime: number): Date {
|
||||
return new Date(unixTime * 1000);
|
||||
}
|
||||
|
||||
export function convertJSDateToUnix(dateTime: string): number {
|
||||
return Number((new Date(dateTime).getTime() / 1000).toFixed(0));
|
||||
}
|
||||
|
||||
export function convertTicksToJSDate(ticks: string): Date {
|
||||
var ticksJSBased = Number(ticks) - epochTicks;
|
||||
var timeInMillisecond = ticksJSBased / ticksPerMillisecond;
|
||||
return new Date(timeInMillisecond);
|
||||
}
|
||||
|
||||
export function convertJSDateToTicksWithPadding(dateTime: string): string {
|
||||
var ticks = epochTicks + new Date(dateTime).getTime() * ticksPerMillisecond;
|
||||
return padDateTicksWithZeros(ticks.toString());
|
||||
}
|
||||
|
||||
function padDateTicksWithZeros(value: string): string {
|
||||
var s = "0000000000000000000" + value;
|
||||
return s.substr(s.length - 20);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,285 +1,285 @@
|
||||
import * as ko from "knockout";
|
||||
import _ from "underscore";
|
||||
import * as QueryBuilderConstants from "../Constants";
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import ClauseGroup from "./ClauseGroup";
|
||||
import * as Utilities from "../Utilities";
|
||||
|
||||
export default class QueryClauseViewModel {
|
||||
public checkedForGrouping: ko.Observable<boolean>;
|
||||
public isFirstInGroup: ko.Observable<boolean>;
|
||||
public clauseGroup: ClauseGroup;
|
||||
public and_or: ko.Observable<string>;
|
||||
public field: ko.Observable<string>;
|
||||
public type: ko.Observable<string>;
|
||||
public operator: ko.Observable<string>;
|
||||
public value: ko.Observable<any>;
|
||||
public timeValue: ko.Observable<string>;
|
||||
public customTimeValue: ko.Observable<string>;
|
||||
public canAnd: ko.Observable<boolean>;
|
||||
public timestampType: ko.Observable<string>;
|
||||
//public customLastTimestamp: ko.Observable<CustomTimestampHelper.ILastQuery>;
|
||||
public isLocal: ko.Observable<boolean>;
|
||||
public isOperaterEditable: ko.PureComputed<boolean>;
|
||||
public isTypeEditable: ko.PureComputed<boolean>;
|
||||
public isValue: ko.Observable<boolean>;
|
||||
public isTimestamp: ko.Observable<boolean>;
|
||||
public isCustomLastTimestamp: ko.Observable<boolean>;
|
||||
public isCustomRangeTimestamp: ko.Observable<boolean>;
|
||||
private _queryBuilderViewModel: QueryBuilderViewModel;
|
||||
private _groupCheckSubscription: ko.Subscription;
|
||||
private _id: string;
|
||||
public isAndOrFocused: ko.Observable<boolean>;
|
||||
public isDeleteButtonFocused: ko.Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
queryBuilderViewModel: QueryBuilderViewModel,
|
||||
and_or: string,
|
||||
field: string,
|
||||
type: string,
|
||||
operator: string,
|
||||
value: any,
|
||||
canAnd: boolean,
|
||||
timeValue: string,
|
||||
customTimeValue: string,
|
||||
timestampType: string,
|
||||
//customLastTimestamp: CustomTimestampHelper.ILastQuery,
|
||||
isLocal: boolean,
|
||||
id?: string
|
||||
) {
|
||||
this._queryBuilderViewModel = queryBuilderViewModel;
|
||||
this.checkedForGrouping = ko.observable<boolean>(false);
|
||||
this.isFirstInGroup = ko.observable<boolean>(false);
|
||||
this.and_or = ko.observable<string>(and_or);
|
||||
this.field = ko.observable<string>(field);
|
||||
this.type = ko.observable<string>(type);
|
||||
this.operator = ko.observable<string>(operator);
|
||||
this.value = ko.observable<string>(value);
|
||||
this.timeValue = ko.observable<string>(timeValue);
|
||||
this.customTimeValue = ko.observable<string>(customTimeValue);
|
||||
this.canAnd = ko.observable<boolean>(canAnd);
|
||||
this.isLocal = ko.observable<boolean>(isLocal);
|
||||
this._id = id ? id : Utilities.guid();
|
||||
|
||||
//this.customLastTimestamp = ko.observable<CustomTimestampHelper.ILastQuery>(customLastTimestamp);
|
||||
//this.setCustomLastTimestamp();
|
||||
|
||||
this.timestampType = ko.observable<string>(timestampType);
|
||||
this.getValueType();
|
||||
|
||||
this.isOperaterEditable = ko.pureComputed<boolean>(() => {
|
||||
const isPreferredApiCassandra = this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra();
|
||||
const cassandraKeys = isPreferredApiCassandra
|
||||
? this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.collection.cassandraKeys.partitionKeys.map(
|
||||
key => key.property
|
||||
)
|
||||
: [];
|
||||
return (
|
||||
(this.isValue() || this.isCustomRangeTimestamp()) &&
|
||||
(!isPreferredApiCassandra || !_.contains(cassandraKeys, this.field()))
|
||||
);
|
||||
});
|
||||
this.isTypeEditable = ko.pureComputed<boolean>(
|
||||
() =>
|
||||
this.field() !== "Timestamp" &&
|
||||
this.field() !== "PartitionKey" &&
|
||||
this.field() !== "RowKey" &&
|
||||
!this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra()
|
||||
);
|
||||
|
||||
this.and_or.subscribe(value => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this.field.subscribe(value => {
|
||||
this.changeField();
|
||||
});
|
||||
this.type.subscribe(value => {
|
||||
this.changeType();
|
||||
});
|
||||
this.timeValue.subscribe(value => {
|
||||
// if (this.timeValue() === QueryBuilderConstants.timeOptions.custom) {
|
||||
// this.customTimestampDialog();
|
||||
// }
|
||||
});
|
||||
this.customTimeValue.subscribe(value => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this.value.subscribe(value => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this.operator.subscribe(value => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this._groupCheckSubscription = this.checkedForGrouping.subscribe(value => {
|
||||
this._queryBuilderViewModel.updateCanGroupClauses();
|
||||
});
|
||||
this.isAndOrFocused = ko.observable<boolean>(false);
|
||||
this.isDeleteButtonFocused = ko.observable<boolean>(false);
|
||||
}
|
||||
|
||||
// private setCustomLastTimestamp() : void {
|
||||
// if (this.customLastTimestamp() === null) {
|
||||
// var lastNumberandType: CustomTimestampHelper.ILastQuery = {
|
||||
// lastNumber: 7,
|
||||
// lastTimeUnit: "Days"
|
||||
// };
|
||||
// this.customLastTimestamp(lastNumberandType);
|
||||
// }
|
||||
// }
|
||||
|
||||
private getValueType(): void {
|
||||
switch (this.timestampType()) {
|
||||
case "time":
|
||||
this.isValue = ko.observable<boolean>(false);
|
||||
this.isTimestamp = ko.observable<boolean>(true);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(false);
|
||||
break;
|
||||
case "last":
|
||||
this.isValue = ko.observable<boolean>(false);
|
||||
this.isTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(true);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(false);
|
||||
break;
|
||||
case "range":
|
||||
this.isValue = ko.observable<boolean>(false);
|
||||
this.isTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(true);
|
||||
break;
|
||||
default:
|
||||
this.isValue = ko.observable<boolean>(true);
|
||||
this.isTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(false);
|
||||
}
|
||||
}
|
||||
|
||||
private changeField(): void {
|
||||
this.isCustomLastTimestamp(false);
|
||||
this.isCustomRangeTimestamp(false);
|
||||
|
||||
if (this.field() === "Timestamp") {
|
||||
this.isValue(false);
|
||||
this.isTimestamp(true);
|
||||
this.type(QueryBuilderConstants.TableType.DateTime);
|
||||
this.operator(QueryBuilderConstants.Operator.GreaterThanOrEqualTo);
|
||||
this.timestampType("time");
|
||||
} else if (this.field() === "PartitionKey" || this.field() === "RowKey") {
|
||||
this.resetFromTimestamp();
|
||||
this.type(QueryBuilderConstants.TableType.String);
|
||||
} else {
|
||||
this.resetFromTimestamp();
|
||||
if (this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra()) {
|
||||
const cassandraSchema = this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.collection
|
||||
.cassandraSchema;
|
||||
for (let i = 0, len = cassandraSchema.length; i < len; i++) {
|
||||
if (cassandraSchema[i].property === this.field()) {
|
||||
this.type(cassandraSchema[i].type);
|
||||
i = len;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.type(QueryBuilderConstants.TableType.String);
|
||||
}
|
||||
}
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
}
|
||||
|
||||
private resetFromTimestamp(): void {
|
||||
this.isValue(true);
|
||||
this.isTimestamp(false);
|
||||
this.operator(QueryBuilderConstants.Operator.Equal);
|
||||
this.value("");
|
||||
this.timestampType("");
|
||||
this.timeValue("");
|
||||
this.customTimeValue("");
|
||||
}
|
||||
|
||||
private changeType(): void {
|
||||
this.isCustomLastTimestamp(false);
|
||||
this.isCustomRangeTimestamp(false);
|
||||
|
||||
if (this.type() === QueryBuilderConstants.TableType.DateTime) {
|
||||
this.isValue(false);
|
||||
this.isTimestamp(true);
|
||||
this.operator(QueryBuilderConstants.Operator.GreaterThanOrEqualTo);
|
||||
this.timestampType("time");
|
||||
} else {
|
||||
this.isValue(true);
|
||||
this.isTimestamp(false);
|
||||
this.timeValue("");
|
||||
this.operator(QueryBuilderConstants.Operator.EqualTo);
|
||||
this.value("");
|
||||
this.timestampType("");
|
||||
this.timeValue("");
|
||||
this.customTimeValue("");
|
||||
}
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
}
|
||||
|
||||
// private customTimestampDialog(): Promise<any> {
|
||||
// var lastNumber = this.customLastTimestamp().lastNumber;
|
||||
// var lastTimeUnit = this.customLastTimestamp().lastTimeUnit;
|
||||
|
||||
// return this._host.executeOperation("Environment.openDialog", [{
|
||||
// id: AzureConstants.registeredDialogs.customTimestampQueryDialog,
|
||||
// width: 500,
|
||||
// height: 300,
|
||||
// parameters: { lastNumber, lastTimeUnit }
|
||||
// }]).then((timestamp: CustomTimestampHelper.ITimestampQuery) => {
|
||||
// if (timestamp) {
|
||||
// this.isValue(false);
|
||||
// this.isTimestamp(false);
|
||||
// this.timestampType(timestamp.queryType);
|
||||
|
||||
// if (timestamp.queryType === "last") {
|
||||
// this.isCustomLastTimestamp(true);
|
||||
// this.isCustomRangeTimestamp(false);
|
||||
|
||||
// var lastNumberandType: CustomTimestampHelper.ILastQuery = {
|
||||
// lastNumber: timestamp.lastNumber,
|
||||
// lastTimeUnit: timestamp.lastTimeUnit
|
||||
// };
|
||||
|
||||
// this.customLastTimestamp(lastNumberandType);
|
||||
// this.customTimeValue(`Last ${timestamp.lastNumber} ${timestamp.lastTimeUnit}`);
|
||||
|
||||
// } else {
|
||||
// if (timestamp.timeZone === "local") {
|
||||
// this.isLocal = ko.observable(true);
|
||||
// } else {
|
||||
// this.isLocal = ko.observable(false);
|
||||
// }
|
||||
// this.isCustomLastTimestamp(false);
|
||||
// this.isCustomRangeTimestamp(true);
|
||||
// this.customTimeValue(timestamp.startTime);
|
||||
// CustomTimestampHelper.addRangeTimestamp(timestamp, this._queryBuilderViewModel, this);
|
||||
// }
|
||||
// } else {
|
||||
// this.timeValue(QueryBuilderConstants.timeOptions.lastHour);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get groupDepth(): number {
|
||||
if (this.clauseGroup) {
|
||||
return this.clauseGroup.getCurrentGroupDepth();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this._groupCheckSubscription) {
|
||||
this._groupCheckSubscription.dispose();
|
||||
}
|
||||
|
||||
this.clauseGroup = null;
|
||||
this._queryBuilderViewModel = null;
|
||||
}
|
||||
}
|
||||
import * as ko from "knockout";
|
||||
import _ from "underscore";
|
||||
import * as QueryBuilderConstants from "../Constants";
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import ClauseGroup from "./ClauseGroup";
|
||||
import * as Utilities from "../Utilities";
|
||||
|
||||
export default class QueryClauseViewModel {
|
||||
public checkedForGrouping: ko.Observable<boolean>;
|
||||
public isFirstInGroup: ko.Observable<boolean>;
|
||||
public clauseGroup: ClauseGroup;
|
||||
public and_or: ko.Observable<string>;
|
||||
public field: ko.Observable<string>;
|
||||
public type: ko.Observable<string>;
|
||||
public operator: ko.Observable<string>;
|
||||
public value: ko.Observable<any>;
|
||||
public timeValue: ko.Observable<string>;
|
||||
public customTimeValue: ko.Observable<string>;
|
||||
public canAnd: ko.Observable<boolean>;
|
||||
public timestampType: ko.Observable<string>;
|
||||
//public customLastTimestamp: ko.Observable<CustomTimestampHelper.ILastQuery>;
|
||||
public isLocal: ko.Observable<boolean>;
|
||||
public isOperaterEditable: ko.PureComputed<boolean>;
|
||||
public isTypeEditable: ko.PureComputed<boolean>;
|
||||
public isValue: ko.Observable<boolean>;
|
||||
public isTimestamp: ko.Observable<boolean>;
|
||||
public isCustomLastTimestamp: ko.Observable<boolean>;
|
||||
public isCustomRangeTimestamp: ko.Observable<boolean>;
|
||||
private _queryBuilderViewModel: QueryBuilderViewModel;
|
||||
private _groupCheckSubscription: ko.Subscription;
|
||||
private _id: string;
|
||||
public isAndOrFocused: ko.Observable<boolean>;
|
||||
public isDeleteButtonFocused: ko.Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
queryBuilderViewModel: QueryBuilderViewModel,
|
||||
and_or: string,
|
||||
field: string,
|
||||
type: string,
|
||||
operator: string,
|
||||
value: any,
|
||||
canAnd: boolean,
|
||||
timeValue: string,
|
||||
customTimeValue: string,
|
||||
timestampType: string,
|
||||
//customLastTimestamp: CustomTimestampHelper.ILastQuery,
|
||||
isLocal: boolean,
|
||||
id?: string
|
||||
) {
|
||||
this._queryBuilderViewModel = queryBuilderViewModel;
|
||||
this.checkedForGrouping = ko.observable<boolean>(false);
|
||||
this.isFirstInGroup = ko.observable<boolean>(false);
|
||||
this.and_or = ko.observable<string>(and_or);
|
||||
this.field = ko.observable<string>(field);
|
||||
this.type = ko.observable<string>(type);
|
||||
this.operator = ko.observable<string>(operator);
|
||||
this.value = ko.observable<string>(value);
|
||||
this.timeValue = ko.observable<string>(timeValue);
|
||||
this.customTimeValue = ko.observable<string>(customTimeValue);
|
||||
this.canAnd = ko.observable<boolean>(canAnd);
|
||||
this.isLocal = ko.observable<boolean>(isLocal);
|
||||
this._id = id ? id : Utilities.guid();
|
||||
|
||||
//this.customLastTimestamp = ko.observable<CustomTimestampHelper.ILastQuery>(customLastTimestamp);
|
||||
//this.setCustomLastTimestamp();
|
||||
|
||||
this.timestampType = ko.observable<string>(timestampType);
|
||||
this.getValueType();
|
||||
|
||||
this.isOperaterEditable = ko.pureComputed<boolean>(() => {
|
||||
const isPreferredApiCassandra = this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra();
|
||||
const cassandraKeys = isPreferredApiCassandra
|
||||
? this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.collection.cassandraKeys.partitionKeys.map(
|
||||
(key) => key.property
|
||||
)
|
||||
: [];
|
||||
return (
|
||||
(this.isValue() || this.isCustomRangeTimestamp()) &&
|
||||
(!isPreferredApiCassandra || !_.contains(cassandraKeys, this.field()))
|
||||
);
|
||||
});
|
||||
this.isTypeEditable = ko.pureComputed<boolean>(
|
||||
() =>
|
||||
this.field() !== "Timestamp" &&
|
||||
this.field() !== "PartitionKey" &&
|
||||
this.field() !== "RowKey" &&
|
||||
!this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra()
|
||||
);
|
||||
|
||||
this.and_or.subscribe((value) => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this.field.subscribe((value) => {
|
||||
this.changeField();
|
||||
});
|
||||
this.type.subscribe((value) => {
|
||||
this.changeType();
|
||||
});
|
||||
this.timeValue.subscribe((value) => {
|
||||
// if (this.timeValue() === QueryBuilderConstants.timeOptions.custom) {
|
||||
// this.customTimestampDialog();
|
||||
// }
|
||||
});
|
||||
this.customTimeValue.subscribe((value) => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this.value.subscribe((value) => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this.operator.subscribe((value) => {
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
});
|
||||
this._groupCheckSubscription = this.checkedForGrouping.subscribe((value) => {
|
||||
this._queryBuilderViewModel.updateCanGroupClauses();
|
||||
});
|
||||
this.isAndOrFocused = ko.observable<boolean>(false);
|
||||
this.isDeleteButtonFocused = ko.observable<boolean>(false);
|
||||
}
|
||||
|
||||
// private setCustomLastTimestamp() : void {
|
||||
// if (this.customLastTimestamp() === null) {
|
||||
// var lastNumberandType: CustomTimestampHelper.ILastQuery = {
|
||||
// lastNumber: 7,
|
||||
// lastTimeUnit: "Days"
|
||||
// };
|
||||
// this.customLastTimestamp(lastNumberandType);
|
||||
// }
|
||||
// }
|
||||
|
||||
private getValueType(): void {
|
||||
switch (this.timestampType()) {
|
||||
case "time":
|
||||
this.isValue = ko.observable<boolean>(false);
|
||||
this.isTimestamp = ko.observable<boolean>(true);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(false);
|
||||
break;
|
||||
case "last":
|
||||
this.isValue = ko.observable<boolean>(false);
|
||||
this.isTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(true);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(false);
|
||||
break;
|
||||
case "range":
|
||||
this.isValue = ko.observable<boolean>(false);
|
||||
this.isTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(true);
|
||||
break;
|
||||
default:
|
||||
this.isValue = ko.observable<boolean>(true);
|
||||
this.isTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomLastTimestamp = ko.observable<boolean>(false);
|
||||
this.isCustomRangeTimestamp = ko.observable<boolean>(false);
|
||||
}
|
||||
}
|
||||
|
||||
private changeField(): void {
|
||||
this.isCustomLastTimestamp(false);
|
||||
this.isCustomRangeTimestamp(false);
|
||||
|
||||
if (this.field() === "Timestamp") {
|
||||
this.isValue(false);
|
||||
this.isTimestamp(true);
|
||||
this.type(QueryBuilderConstants.TableType.DateTime);
|
||||
this.operator(QueryBuilderConstants.Operator.GreaterThanOrEqualTo);
|
||||
this.timestampType("time");
|
||||
} else if (this.field() === "PartitionKey" || this.field() === "RowKey") {
|
||||
this.resetFromTimestamp();
|
||||
this.type(QueryBuilderConstants.TableType.String);
|
||||
} else {
|
||||
this.resetFromTimestamp();
|
||||
if (this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.container.isPreferredApiCassandra()) {
|
||||
const cassandraSchema = this._queryBuilderViewModel.tableEntityListViewModel.queryTablesTab.collection
|
||||
.cassandraSchema;
|
||||
for (let i = 0, len = cassandraSchema.length; i < len; i++) {
|
||||
if (cassandraSchema[i].property === this.field()) {
|
||||
this.type(cassandraSchema[i].type);
|
||||
i = len;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.type(QueryBuilderConstants.TableType.String);
|
||||
}
|
||||
}
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
}
|
||||
|
||||
private resetFromTimestamp(): void {
|
||||
this.isValue(true);
|
||||
this.isTimestamp(false);
|
||||
this.operator(QueryBuilderConstants.Operator.Equal);
|
||||
this.value("");
|
||||
this.timestampType("");
|
||||
this.timeValue("");
|
||||
this.customTimeValue("");
|
||||
}
|
||||
|
||||
private changeType(): void {
|
||||
this.isCustomLastTimestamp(false);
|
||||
this.isCustomRangeTimestamp(false);
|
||||
|
||||
if (this.type() === QueryBuilderConstants.TableType.DateTime) {
|
||||
this.isValue(false);
|
||||
this.isTimestamp(true);
|
||||
this.operator(QueryBuilderConstants.Operator.GreaterThanOrEqualTo);
|
||||
this.timestampType("time");
|
||||
} else {
|
||||
this.isValue(true);
|
||||
this.isTimestamp(false);
|
||||
this.timeValue("");
|
||||
this.operator(QueryBuilderConstants.Operator.EqualTo);
|
||||
this.value("");
|
||||
this.timestampType("");
|
||||
this.timeValue("");
|
||||
this.customTimeValue("");
|
||||
}
|
||||
this._queryBuilderViewModel.checkIfClauseChanged(this);
|
||||
}
|
||||
|
||||
// private customTimestampDialog(): Promise<any> {
|
||||
// var lastNumber = this.customLastTimestamp().lastNumber;
|
||||
// var lastTimeUnit = this.customLastTimestamp().lastTimeUnit;
|
||||
|
||||
// return this._host.executeOperation("Environment.openDialog", [{
|
||||
// id: AzureConstants.registeredDialogs.customTimestampQueryDialog,
|
||||
// width: 500,
|
||||
// height: 300,
|
||||
// parameters: { lastNumber, lastTimeUnit }
|
||||
// }]).then((timestamp: CustomTimestampHelper.ITimestampQuery) => {
|
||||
// if (timestamp) {
|
||||
// this.isValue(false);
|
||||
// this.isTimestamp(false);
|
||||
// this.timestampType(timestamp.queryType);
|
||||
|
||||
// if (timestamp.queryType === "last") {
|
||||
// this.isCustomLastTimestamp(true);
|
||||
// this.isCustomRangeTimestamp(false);
|
||||
|
||||
// var lastNumberandType: CustomTimestampHelper.ILastQuery = {
|
||||
// lastNumber: timestamp.lastNumber,
|
||||
// lastTimeUnit: timestamp.lastTimeUnit
|
||||
// };
|
||||
|
||||
// this.customLastTimestamp(lastNumberandType);
|
||||
// this.customTimeValue(`Last ${timestamp.lastNumber} ${timestamp.lastTimeUnit}`);
|
||||
|
||||
// } else {
|
||||
// if (timestamp.timeZone === "local") {
|
||||
// this.isLocal = ko.observable(true);
|
||||
// } else {
|
||||
// this.isLocal = ko.observable(false);
|
||||
// }
|
||||
// this.isCustomLastTimestamp(false);
|
||||
// this.isCustomRangeTimestamp(true);
|
||||
// this.customTimeValue(timestamp.startTime);
|
||||
// CustomTimestampHelper.addRangeTimestamp(timestamp, this._queryBuilderViewModel, this);
|
||||
// }
|
||||
// } else {
|
||||
// this.timeValue(QueryBuilderConstants.timeOptions.lastHour);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
public getId(): string {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public get groupDepth(): number {
|
||||
if (this.clauseGroup) {
|
||||
return this.clauseGroup.getCurrentGroupDepth();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this._groupCheckSubscription) {
|
||||
this._groupCheckSubscription.dispose();
|
||||
}
|
||||
|
||||
this.clauseGroup = null;
|
||||
this._queryBuilderViewModel = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,237 +1,237 @@
|
||||
import * as ko from "knockout";
|
||||
import * as _ from "underscore";
|
||||
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import TableEntityListViewModel from "../DataTable/TableEntityListViewModel";
|
||||
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
||||
import * as DataTableUtilities from "../DataTable/DataTableUtilities";
|
||||
import { KeyCodes } from "../../../Common/Constants";
|
||||
import { getQuotedCqlIdentifier } from "../CqlUtilities";
|
||||
|
||||
export default class QueryViewModel {
|
||||
public topValueLimitMessage: string = "Please input a number between 0 and 1000.";
|
||||
public queryBuilderViewModel = ko.observable<QueryBuilderViewModel>();
|
||||
public isHelperActive = ko.observable<boolean>(true);
|
||||
public isEditorActive = ko.observable<boolean>(false);
|
||||
public isExpanded = ko.observable<boolean>(false);
|
||||
public isWarningBox = ko.observable<boolean>();
|
||||
public hasQueryError: ko.Computed<boolean>;
|
||||
public queryErrorMessage: ko.Computed<string>;
|
||||
public isSaveEnabled: ko.PureComputed<boolean>;
|
||||
public isExceedingLimit: ko.Computed<boolean>;
|
||||
public canRunQuery: ko.Computed<boolean>;
|
||||
public queryTextIsReadOnly: ko.Computed<boolean>;
|
||||
public queryText = ko.observable<string>();
|
||||
public topValue = ko.observable<number>();
|
||||
public selectText = ko.observableArray<string>();
|
||||
public unchangedText = ko.observable<string>();
|
||||
public unchangedSaveText = ko.observable<string>();
|
||||
public unchangedSaveTop = ko.observable<number>();
|
||||
public unchangedSaveSelect = ko.observableArray<string>();
|
||||
public focusTopResult: ko.Observable<boolean>;
|
||||
public focusExpandIcon: ko.Observable<boolean>;
|
||||
|
||||
public savedQueryName = ko.observable<string>();
|
||||
public selectMessage = ko.observable<string>();
|
||||
|
||||
public columnOptions: ko.ObservableArray<string>;
|
||||
|
||||
public queryTablesTab: QueryTablesTab;
|
||||
public id: string;
|
||||
private _tableEntityListViewModel: TableEntityListViewModel;
|
||||
|
||||
constructor(queryTablesTab: QueryTablesTab) {
|
||||
this.queryTablesTab = queryTablesTab;
|
||||
this.id = `queryViewModel${this.queryTablesTab.tabId}`;
|
||||
this._tableEntityListViewModel = queryTablesTab.tableEntityListViewModel();
|
||||
|
||||
this.queryTextIsReadOnly = ko.computed<boolean>(() => {
|
||||
return !this.queryTablesTab.container.isPreferredApiCassandra();
|
||||
});
|
||||
let initialOptions = this._tableEntityListViewModel.headers;
|
||||
this.columnOptions = ko.observableArray<string>(initialOptions);
|
||||
this.focusTopResult = ko.observable<boolean>(false);
|
||||
this.focusExpandIcon = ko.observable<boolean>(false);
|
||||
|
||||
this.queryBuilderViewModel(new QueryBuilderViewModel(this, this._tableEntityListViewModel));
|
||||
|
||||
this.isSaveEnabled = ko.pureComputed<boolean>(
|
||||
() =>
|
||||
this.queryText() !== this.unchangedSaveText() ||
|
||||
this.selectText() !== this.unchangedSaveSelect() ||
|
||||
this.topValue() !== this.unchangedSaveTop()
|
||||
);
|
||||
|
||||
this.queryBuilderViewModel().clauseArray.subscribe(value => {
|
||||
this.setFilter();
|
||||
});
|
||||
|
||||
this.isExceedingLimit = ko.computed<boolean>(() => {
|
||||
var currentTopValue: number = this.topValue();
|
||||
return currentTopValue < 0 || currentTopValue > 1000;
|
||||
});
|
||||
|
||||
this.canRunQuery = ko.computed<boolean>(() => {
|
||||
return !this.isExceedingLimit();
|
||||
});
|
||||
|
||||
this.hasQueryError = ko.computed<boolean>(() => {
|
||||
return !!this._tableEntityListViewModel.queryErrorMessage();
|
||||
});
|
||||
|
||||
this.queryErrorMessage = ko.computed<string>(() => {
|
||||
return this._tableEntityListViewModel.queryErrorMessage();
|
||||
});
|
||||
}
|
||||
|
||||
public selectHelper = (): void => {
|
||||
this.isHelperActive(true);
|
||||
this.isEditorActive(false);
|
||||
DataTableUtilities.forceRecalculateTableSize();
|
||||
};
|
||||
|
||||
public selectEditor = (): void => {
|
||||
this.setFilter();
|
||||
if (!this.isEditorActive()) {
|
||||
this.unchangedText(this.queryText());
|
||||
}
|
||||
this.isEditorActive(true);
|
||||
this.isHelperActive(false);
|
||||
DataTableUtilities.forceRecalculateTableSize();
|
||||
};
|
||||
|
||||
public toggleAdvancedOptions = () => {
|
||||
this.isExpanded(!this.isExpanded());
|
||||
if (this.isExpanded()) {
|
||||
this.focusTopResult(true);
|
||||
} else {
|
||||
this.focusExpandIcon(true);
|
||||
}
|
||||
DataTableUtilities.forceRecalculateTableSize(); // Fix for 261924, forces the resize event so DataTableBindingManager will redo the calculation on table size.
|
||||
};
|
||||
|
||||
public ontoggleAdvancedOptionsKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.toggleAdvancedOptions();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
private _getSelectedResults = (): Array<string> => {
|
||||
return this.selectText();
|
||||
};
|
||||
|
||||
private setFilter = (): string => {
|
||||
var queryString = this.isEditorActive()
|
||||
? this.queryText()
|
||||
: this.queryTablesTab.container.isPreferredApiCassandra()
|
||||
? this.queryBuilderViewModel().getCqlFilterFromClauses()
|
||||
: this.queryBuilderViewModel().getODataFilterFromClauses();
|
||||
var filter = queryString;
|
||||
this.queryText(filter);
|
||||
return this.queryText();
|
||||
};
|
||||
|
||||
private setSqlFilter = (): string => {
|
||||
var filter = this.queryBuilderViewModel().getSqlFilterFromClauses();
|
||||
return filter;
|
||||
};
|
||||
|
||||
private setCqlFilter = (): string => {
|
||||
var filter = this.queryBuilderViewModel().getCqlFilterFromClauses();
|
||||
return filter;
|
||||
};
|
||||
|
||||
public isHelperEnabled = ko
|
||||
.computed<boolean>(() => {
|
||||
return (
|
||||
this.queryText() === this.unchangedText() ||
|
||||
this.queryText() === null ||
|
||||
this.queryText() === "" ||
|
||||
this.isHelperActive()
|
||||
);
|
||||
})
|
||||
.extend({
|
||||
notify: "always"
|
||||
});
|
||||
|
||||
public runQuery = (): DataTables.DataTable => {
|
||||
var filter = this.setFilter();
|
||||
if (filter && !this.queryTablesTab.container.isPreferredApiCassandra()) {
|
||||
filter = filter.replace(/"/g, "'");
|
||||
}
|
||||
var top = this.topValue();
|
||||
var selectOptions = this._getSelectedResults();
|
||||
var select = selectOptions;
|
||||
this._tableEntityListViewModel.tableQuery.filter = filter;
|
||||
this._tableEntityListViewModel.tableQuery.top = top;
|
||||
this._tableEntityListViewModel.tableQuery.select = select;
|
||||
this._tableEntityListViewModel.oDataQuery(filter);
|
||||
this._tableEntityListViewModel.sqlQuery(this.setSqlFilter());
|
||||
this._tableEntityListViewModel.cqlQuery(filter);
|
||||
|
||||
return this._tableEntityListViewModel.reloadTable(/*useSetting*/ false, /*resetHeaders*/ false);
|
||||
};
|
||||
|
||||
public clearQuery = (): DataTables.DataTable => {
|
||||
this.queryText(null);
|
||||
this.topValue(null);
|
||||
this.selectText(null);
|
||||
this.selectMessage("");
|
||||
// clears the queryBuilder and adds a new blank clause
|
||||
this.queryBuilderViewModel().queryClauses.removeAll();
|
||||
this.queryBuilderViewModel().addNewClause();
|
||||
this._tableEntityListViewModel.tableQuery.filter = null;
|
||||
this._tableEntityListViewModel.tableQuery.top = null;
|
||||
this._tableEntityListViewModel.tableQuery.select = null;
|
||||
this._tableEntityListViewModel.oDataQuery("");
|
||||
this._tableEntityListViewModel.sqlQuery("SELECT * FROM c");
|
||||
this._tableEntityListViewModel.cqlQuery(
|
||||
`SELECT * FROM ${getQuotedCqlIdentifier(this.queryTablesTab.collection.databaseId)}.${getQuotedCqlIdentifier(
|
||||
this.queryTablesTab.collection.id()
|
||||
)}`
|
||||
);
|
||||
return this._tableEntityListViewModel.reloadTable(false);
|
||||
};
|
||||
|
||||
public selectQueryOptions(): Promise<any> {
|
||||
this.queryTablesTab.container.querySelectPane.queryViewModel = this;
|
||||
this.queryTablesTab.container.querySelectPane.open();
|
||||
return null;
|
||||
}
|
||||
|
||||
public onselectQueryOptionsKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.selectQueryOptions();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
public getSelectMessage(): void {
|
||||
if (_.isEmpty(this.selectText()) || this.selectText() === null) {
|
||||
this.selectMessage("");
|
||||
} else {
|
||||
this.selectMessage(`${this.selectText().length} of ${this.columnOptions().length} columns selected.`);
|
||||
}
|
||||
}
|
||||
|
||||
public isSelected = ko.computed<boolean>(() => {
|
||||
return !(_.isEmpty(this.selectText()) || this.selectText() === null);
|
||||
});
|
||||
|
||||
private setCheckToSave(): void {
|
||||
this.unchangedSaveText(this.setFilter());
|
||||
this.unchangedSaveTop(this.topValue());
|
||||
this.unchangedSaveSelect(this.selectText());
|
||||
this.isSaveEnabled(false);
|
||||
}
|
||||
|
||||
public checkIfBuilderChanged(clause: QueryClauseViewModel): void {
|
||||
this.setFilter();
|
||||
}
|
||||
}
|
||||
import * as ko from "knockout";
|
||||
import * as _ from "underscore";
|
||||
|
||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||
import TableEntityListViewModel from "../DataTable/TableEntityListViewModel";
|
||||
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
||||
import * as DataTableUtilities from "../DataTable/DataTableUtilities";
|
||||
import { KeyCodes } from "../../../Common/Constants";
|
||||
import { getQuotedCqlIdentifier } from "../CqlUtilities";
|
||||
|
||||
export default class QueryViewModel {
|
||||
public topValueLimitMessage: string = "Please input a number between 0 and 1000.";
|
||||
public queryBuilderViewModel = ko.observable<QueryBuilderViewModel>();
|
||||
public isHelperActive = ko.observable<boolean>(true);
|
||||
public isEditorActive = ko.observable<boolean>(false);
|
||||
public isExpanded = ko.observable<boolean>(false);
|
||||
public isWarningBox = ko.observable<boolean>();
|
||||
public hasQueryError: ko.Computed<boolean>;
|
||||
public queryErrorMessage: ko.Computed<string>;
|
||||
public isSaveEnabled: ko.PureComputed<boolean>;
|
||||
public isExceedingLimit: ko.Computed<boolean>;
|
||||
public canRunQuery: ko.Computed<boolean>;
|
||||
public queryTextIsReadOnly: ko.Computed<boolean>;
|
||||
public queryText = ko.observable<string>();
|
||||
public topValue = ko.observable<number>();
|
||||
public selectText = ko.observableArray<string>();
|
||||
public unchangedText = ko.observable<string>();
|
||||
public unchangedSaveText = ko.observable<string>();
|
||||
public unchangedSaveTop = ko.observable<number>();
|
||||
public unchangedSaveSelect = ko.observableArray<string>();
|
||||
public focusTopResult: ko.Observable<boolean>;
|
||||
public focusExpandIcon: ko.Observable<boolean>;
|
||||
|
||||
public savedQueryName = ko.observable<string>();
|
||||
public selectMessage = ko.observable<string>();
|
||||
|
||||
public columnOptions: ko.ObservableArray<string>;
|
||||
|
||||
public queryTablesTab: QueryTablesTab;
|
||||
public id: string;
|
||||
private _tableEntityListViewModel: TableEntityListViewModel;
|
||||
|
||||
constructor(queryTablesTab: QueryTablesTab) {
|
||||
this.queryTablesTab = queryTablesTab;
|
||||
this.id = `queryViewModel${this.queryTablesTab.tabId}`;
|
||||
this._tableEntityListViewModel = queryTablesTab.tableEntityListViewModel();
|
||||
|
||||
this.queryTextIsReadOnly = ko.computed<boolean>(() => {
|
||||
return !this.queryTablesTab.container.isPreferredApiCassandra();
|
||||
});
|
||||
let initialOptions = this._tableEntityListViewModel.headers;
|
||||
this.columnOptions = ko.observableArray<string>(initialOptions);
|
||||
this.focusTopResult = ko.observable<boolean>(false);
|
||||
this.focusExpandIcon = ko.observable<boolean>(false);
|
||||
|
||||
this.queryBuilderViewModel(new QueryBuilderViewModel(this, this._tableEntityListViewModel));
|
||||
|
||||
this.isSaveEnabled = ko.pureComputed<boolean>(
|
||||
() =>
|
||||
this.queryText() !== this.unchangedSaveText() ||
|
||||
this.selectText() !== this.unchangedSaveSelect() ||
|
||||
this.topValue() !== this.unchangedSaveTop()
|
||||
);
|
||||
|
||||
this.queryBuilderViewModel().clauseArray.subscribe((value) => {
|
||||
this.setFilter();
|
||||
});
|
||||
|
||||
this.isExceedingLimit = ko.computed<boolean>(() => {
|
||||
var currentTopValue: number = this.topValue();
|
||||
return currentTopValue < 0 || currentTopValue > 1000;
|
||||
});
|
||||
|
||||
this.canRunQuery = ko.computed<boolean>(() => {
|
||||
return !this.isExceedingLimit();
|
||||
});
|
||||
|
||||
this.hasQueryError = ko.computed<boolean>(() => {
|
||||
return !!this._tableEntityListViewModel.queryErrorMessage();
|
||||
});
|
||||
|
||||
this.queryErrorMessage = ko.computed<string>(() => {
|
||||
return this._tableEntityListViewModel.queryErrorMessage();
|
||||
});
|
||||
}
|
||||
|
||||
public selectHelper = (): void => {
|
||||
this.isHelperActive(true);
|
||||
this.isEditorActive(false);
|
||||
DataTableUtilities.forceRecalculateTableSize();
|
||||
};
|
||||
|
||||
public selectEditor = (): void => {
|
||||
this.setFilter();
|
||||
if (!this.isEditorActive()) {
|
||||
this.unchangedText(this.queryText());
|
||||
}
|
||||
this.isEditorActive(true);
|
||||
this.isHelperActive(false);
|
||||
DataTableUtilities.forceRecalculateTableSize();
|
||||
};
|
||||
|
||||
public toggleAdvancedOptions = () => {
|
||||
this.isExpanded(!this.isExpanded());
|
||||
if (this.isExpanded()) {
|
||||
this.focusTopResult(true);
|
||||
} else {
|
||||
this.focusExpandIcon(true);
|
||||
}
|
||||
DataTableUtilities.forceRecalculateTableSize(); // Fix for 261924, forces the resize event so DataTableBindingManager will redo the calculation on table size.
|
||||
};
|
||||
|
||||
public ontoggleAdvancedOptionsKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.toggleAdvancedOptions();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
private _getSelectedResults = (): Array<string> => {
|
||||
return this.selectText();
|
||||
};
|
||||
|
||||
private setFilter = (): string => {
|
||||
var queryString = this.isEditorActive()
|
||||
? this.queryText()
|
||||
: this.queryTablesTab.container.isPreferredApiCassandra()
|
||||
? this.queryBuilderViewModel().getCqlFilterFromClauses()
|
||||
: this.queryBuilderViewModel().getODataFilterFromClauses();
|
||||
var filter = queryString;
|
||||
this.queryText(filter);
|
||||
return this.queryText();
|
||||
};
|
||||
|
||||
private setSqlFilter = (): string => {
|
||||
var filter = this.queryBuilderViewModel().getSqlFilterFromClauses();
|
||||
return filter;
|
||||
};
|
||||
|
||||
private setCqlFilter = (): string => {
|
||||
var filter = this.queryBuilderViewModel().getCqlFilterFromClauses();
|
||||
return filter;
|
||||
};
|
||||
|
||||
public isHelperEnabled = ko
|
||||
.computed<boolean>(() => {
|
||||
return (
|
||||
this.queryText() === this.unchangedText() ||
|
||||
this.queryText() === null ||
|
||||
this.queryText() === "" ||
|
||||
this.isHelperActive()
|
||||
);
|
||||
})
|
||||
.extend({
|
||||
notify: "always",
|
||||
});
|
||||
|
||||
public runQuery = (): DataTables.DataTable => {
|
||||
var filter = this.setFilter();
|
||||
if (filter && !this.queryTablesTab.container.isPreferredApiCassandra()) {
|
||||
filter = filter.replace(/"/g, "'");
|
||||
}
|
||||
var top = this.topValue();
|
||||
var selectOptions = this._getSelectedResults();
|
||||
var select = selectOptions;
|
||||
this._tableEntityListViewModel.tableQuery.filter = filter;
|
||||
this._tableEntityListViewModel.tableQuery.top = top;
|
||||
this._tableEntityListViewModel.tableQuery.select = select;
|
||||
this._tableEntityListViewModel.oDataQuery(filter);
|
||||
this._tableEntityListViewModel.sqlQuery(this.setSqlFilter());
|
||||
this._tableEntityListViewModel.cqlQuery(filter);
|
||||
|
||||
return this._tableEntityListViewModel.reloadTable(/*useSetting*/ false, /*resetHeaders*/ false);
|
||||
};
|
||||
|
||||
public clearQuery = (): DataTables.DataTable => {
|
||||
this.queryText(null);
|
||||
this.topValue(null);
|
||||
this.selectText(null);
|
||||
this.selectMessage("");
|
||||
// clears the queryBuilder and adds a new blank clause
|
||||
this.queryBuilderViewModel().queryClauses.removeAll();
|
||||
this.queryBuilderViewModel().addNewClause();
|
||||
this._tableEntityListViewModel.tableQuery.filter = null;
|
||||
this._tableEntityListViewModel.tableQuery.top = null;
|
||||
this._tableEntityListViewModel.tableQuery.select = null;
|
||||
this._tableEntityListViewModel.oDataQuery("");
|
||||
this._tableEntityListViewModel.sqlQuery("SELECT * FROM c");
|
||||
this._tableEntityListViewModel.cqlQuery(
|
||||
`SELECT * FROM ${getQuotedCqlIdentifier(this.queryTablesTab.collection.databaseId)}.${getQuotedCqlIdentifier(
|
||||
this.queryTablesTab.collection.id()
|
||||
)}`
|
||||
);
|
||||
return this._tableEntityListViewModel.reloadTable(false);
|
||||
};
|
||||
|
||||
public selectQueryOptions(): Promise<any> {
|
||||
this.queryTablesTab.container.querySelectPane.queryViewModel = this;
|
||||
this.queryTablesTab.container.querySelectPane.open();
|
||||
return null;
|
||||
}
|
||||
|
||||
public onselectQueryOptionsKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||
this.selectQueryOptions();
|
||||
event.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
public getSelectMessage(): void {
|
||||
if (_.isEmpty(this.selectText()) || this.selectText() === null) {
|
||||
this.selectMessage("");
|
||||
} else {
|
||||
this.selectMessage(`${this.selectText().length} of ${this.columnOptions().length} columns selected.`);
|
||||
}
|
||||
}
|
||||
|
||||
public isSelected = ko.computed<boolean>(() => {
|
||||
return !(_.isEmpty(this.selectText()) || this.selectText() === null);
|
||||
});
|
||||
|
||||
private setCheckToSave(): void {
|
||||
this.unchangedSaveText(this.setFilter());
|
||||
this.unchangedSaveTop(this.topValue());
|
||||
this.unchangedSaveSelect(this.selectText());
|
||||
this.isSaveEnabled(false);
|
||||
}
|
||||
|
||||
public checkIfBuilderChanged(clause: QueryClauseViewModel): void {
|
||||
this.setFilter();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user