diff --git a/package.json b/package.json index f28e3d0..3c3cfae 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "ng": "ng", "start": "ng serve --host 0.0.0.0 --port 4200 --publicHost http://0.0.0.0:4200 --disableHostCheck --proxy-config proxy.conf.json", - "build": "ng build --aot --prod", + "build": "ng build --aot --prod --output-hashing=bundles", "test": "ng test", "test-ci": "ng test --singleRun", "test-coverage": "ng test --singleRun --code-coverage --reporters=coverage-istanbul", @@ -24,7 +24,7 @@ "@angular/platform-browser": "4.3.1", "@angular/platform-browser-dynamic": "4.3.1", "@angular/router": "4.3.1", - "@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.28", + "@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.29", "angular-split": "^0.2.0", "animate.css": "^3.5.2", "bootstrap": "4.0.0-alpha.6", @@ -39,17 +39,17 @@ "moment": "^2.17.1", "ngx-clipboard": "^8.0.2", "open-sans-fontface": "^1.4.0", - "rxjs": "^5.1.0", + "rxjs": "^5.4.0", "tether": "^1.4.0", - "zone.js": "^0.8.4" + "zone.js": "^0.8.14" }, "devDependencies": { - "@angular/cli": "1.2.3", + "@angular/cli": "1.2.5", "@angular/compiler-cli": "4.3.1", "@angular/language-service": "4.3.1", "@types/codemirror": "^0.0.38", "@types/dagre": "^0.7.34", - "@types/jasmine": "2.5.45", + "@types/jasmine": "~2.5.53", "@types/jquery": "^3.2.6", "@types/js-yaml": "^3.5.31", "@types/node": "~6.0.60", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 06147f5..173359e 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -11,6 +11,7 @@ import {BrowserAnimationsModule} from "@angular/platform-browser/animations"; import {ExecutionsModule} from "./executions/executions.module"; import {MistralService} from "./engines/mistral/mistral.service"; import {AboutComponent} from "./about/about.component"; +import {FormsModule} from "@angular/forms"; @NgModule({ declarations: [ @@ -24,6 +25,7 @@ import {AboutComponent} from "./about/about.component"; BrowserAnimationsModule, HttpClientModule, ExecutionsModule, + FormsModule, ], providers: [ MistralService diff --git a/src/app/executions/executions-list/executions-list.component.html b/src/app/executions/executions-list/executions-list.component.html index 0e770ff..3586b3b 100644 --- a/src/app/executions/executions-list/executions-list.component.html +++ b/src/app/executions/executions-list/executions-list.component.html @@ -1,27 +1,29 @@
-

-

Showing {{executions.length}} Executions

+

+
State
Workflow
-
Created At
+
Created At
-
-
-
- {{execution.state}} +
+ +
+
+ {{execution.state}} +
+
{{execution.workflow_name}}
+
{{execution.created_at}}
-
{{execution.workflow_name}}
-
{{execution.created_at}}
-
+
\ No newline at end of file diff --git a/src/app/executions/executions-list/executions-list.component.ts b/src/app/executions/executions-list/executions-list.component.ts index 2eb719e..e837996 100644 --- a/src/app/executions/executions-list/executions-list.component.ts +++ b/src/app/executions/executions-list/executions-list.component.ts @@ -11,6 +11,7 @@ import {Execution} from "../../shared/models/execution"; }) export class ExecutionsListComponent implements OnInit { executions: Execution[] = []; + search: string; constructor(private service: MistralService) {} diff --git a/src/app/shared/filters/search.pipe.spec.ts b/src/app/shared/filters/search.pipe.spec.ts new file mode 100644 index 0000000..8c2fca6 --- /dev/null +++ b/src/app/shared/filters/search.pipe.spec.ts @@ -0,0 +1,89 @@ +// Copyright (C) 2017 Nokia + +import {SearchPipe} from './search.pipe'; + +describe('SearchPipe', () => { + let pipe: SearchPipe; + const input = [{animal: "Cat", age: 6}, {animal: "Dog", age: 12}]; + + beforeEach(() => { + pipe = new SearchPipe(); + }); + + it('return the whole array when search value is empty', () => { + expect(pipe.transform(input, "")).toEqual(input); + }); + + describe('Test empty arrays', () => { + it('return empty array on null', () => { + expect(pipe.transform(null, "")).toEqual([]); + }); + + it('return empty array on undefined', () => { + expect(pipe.transform(undefined, "")).toEqual([]); + }); + + it('return empty array on empty array', () => { + expect(pipe.transform([], "")).toEqual([]); + }); + }); + + describe('Array filter with field name', () => { + it('should find an item', () => { + const result = pipe.transform(input, "cat", "animal"); + expect(result.length).toEqual(1); + expect(result[0].age).toEqual(6); + }); + + it("shouldn't find an item", () => { + const result = pipe.transform(input, "jaguar", "animal"); + expect(result.length).toEqual(0); + }); + }); + + describe('Array filter on any field', () => { + it('should find an item', () => { + const result = pipe.transform(input, "12"); + expect(result.length).toEqual(1); + expect(result[0].animal).toEqual("Dog"); + }); + + it("Shouldn't find any items", () => { + const result = pipe.transform(input, "14"); + expect(result.length).toEqual(0); + }); + }); + + describe('Ignore case', () => { + it('should find an item', () => { + const result = pipe.transform(input, "cat"); + expect(result.length).toEqual(1); + expect(result[0].animal).toEqual("Cat"); + }); + + it("shouldn't find an item", () => { + const result = pipe.transform(input, "jaguar"); + expect(result.length).toEqual(0); + }); + }); + + describe('Partial input', () => { + it('should find 2 items', () => { + const input2 = [{name: "ABCD"}, {name: "FABCE"}, {name: "DCBA"}]; + const result = pipe.transform(input2, "ab"); + expect(result.length).toEqual(2); + }); + + it("shouldn't find any items", () => { + const input2 = [{name: "ABCD"}, {name: "FABCE"}, {name: "DCBA"}]; + const result = pipe.transform(input2, "abe"); + expect(result.length).toEqual(0); + }); + }); + + describe("Don't fail on null values of fields", () => { + it("Shouldn't fail on null value", () => { + expect(() => pipe.transform([{name: null}], "val")).not.toThrow(); + }); + }); +}); diff --git a/src/app/shared/filters/search.pipe.ts b/src/app/shared/filters/search.pipe.ts new file mode 100644 index 0000000..9d45ede --- /dev/null +++ b/src/app/shared/filters/search.pipe.ts @@ -0,0 +1,33 @@ +// Copyright (C) 2017 Nokia + +import {Pipe, PipeTransform} from '@angular/core'; + +@Pipe({ + name: 'search' +}) +export class SearchPipe implements PipeTransform { + + private static fieldMatch(item: any, fieldName: string, searchValue: string): boolean { + return item[fieldName] != null && + item[fieldName].toString().toLocaleLowerCase().includes(searchValue); + } + + private static anywhere(item: any, searchValue: string): boolean { + return Object.keys(item).some(key => SearchPipe.fieldMatch(item, key, searchValue)); + } + + private static matches(item: any, searchValue: string, fieldName?: string): boolean { + return fieldName ? SearchPipe.fieldMatch(item, fieldName, searchValue) : SearchPipe.anywhere(item, searchValue); + } + + transform(items: any[], searchValue: string, fieldName?: string): any { + if (!items) { + return []; + } + if (!searchValue) { + return items; + } + return items.filter(it => SearchPipe.matches(it, searchValue.toLocaleLowerCase(), fieldName)); + } + +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index e387b48..9cf200a 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -8,6 +8,7 @@ import {AngularSplitModule} from "angular-split"; import {CodeMirrorModule} from "./components/codemirror/codemirror.module"; import {ClipboardModule} from "ngx-clipboard/dist"; import {CopyableComponent} from "./components/copyable.component"; +import {SearchPipe} from './filters/search.pipe'; @NgModule({ imports: [ @@ -20,6 +21,7 @@ import {CopyableComponent} from "./components/copyable.component"; ], declarations: [ CopyableComponent, + SearchPipe, ], exports: [ CommonModule, @@ -28,7 +30,8 @@ import {CopyableComponent} from "./components/copyable.component"; AngularSplitModule, CodeMirrorModule, ClipboardModule, - CopyableComponent + CopyableComponent, + SearchPipe, ] }) export class SharedModule { diff --git a/src/app/shared/utils.spec.ts b/src/app/shared/utils.spec.ts index 79134af..8bf75e7 100644 --- a/src/app/shared/utils.spec.ts +++ b/src/app/shared/utils.spec.ts @@ -12,7 +12,6 @@ describe('Test utils', () => { it('should convert all values to strings', () => { const params = toUrlParams({id: 30}); expect(params.get("id")).toEqual("30"); - expect(params.get("id")).not.toEqual(30); }); }); diff --git a/yarn.lock b/yarn.lock index 46c9de9..4e82096 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8,14 +8,15 @@ dependencies: tslib "^1.7.1" -"@angular/cli@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-1.2.3.tgz#78ec7bece9865792b99745a54401749b48ff4ea8" +"@angular/cli@1.2.5": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-1.2.5.tgz#d73460a754a81b334421344841100c8665276a81" dependencies: "@ngtools/json-schema" "1.1.0" - "@ngtools/webpack" "1.5.2" + "@ngtools/webpack" "1.5.4" autoprefixer "^6.5.3" - chalk "^1.1.3" + chalk "^2.0.1" + circular-dependency-plugin "^3.0.0" common-tags "^1.3.1" core-object "^3.1.0" css-loader "^0.28.1" @@ -27,7 +28,7 @@ exports-loader "^0.6.3" extract-text-webpack-plugin "^2.1.0" file-loader "^0.10.0" - fs-extra "^3.0.1" + fs-extra "^4.0.0" get-caller-file "^1.0.0" glob "^7.0.3" heimdalljs "^0.2.4" @@ -37,7 +38,6 @@ inquirer "^3.0.0" isbinaryfile "^3.0.0" istanbul-instrumenter-loader "^2.0.0" - json-loader "^0.5.4" karma-source-map-support "^1.2.0" less "^2.7.2" less-loader "^4.0.2" @@ -47,7 +47,7 @@ minimatch "^3.0.3" node-modules-path "^1.0.0" nopt "^4.0.1" - opn "4.0.2" + opn "~5.1.0" portfinder "~1.0.12" postcss-loader "^1.3.3" postcss-url "^5.1.2" @@ -141,21 +141,21 @@ dependencies: tsickle "^0.21.0" -"@ng-bootstrap/ng-bootstrap@1.0.0-alpha.28": - version "1.0.0-alpha.28" - resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-1.0.0-alpha.28.tgz#30a6503bf7f94f9d3187591fb3267b59cc0cdaad" +"@ng-bootstrap/ng-bootstrap@1.0.0-alpha.29": + version "1.0.0-alpha.29" + resolved "https://registry.yarnpkg.com/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-1.0.0-alpha.29.tgz#ca2fa1d2dd94e8f077921e59d78ac51075bcdcd6" "@ngtools/json-schema@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@ngtools/json-schema/-/json-schema-1.1.0.tgz#c3a0c544d62392acc2813a42c8a0dc6f58f86922" -"@ngtools/webpack@1.5.2": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-1.5.2.tgz#fadef06ba6a9ac0daaf891d013dad031d6bf0c26" +"@ngtools/webpack@1.5.4": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-1.5.4.tgz#a281c95c07dba44c95c6a234d657880285af0ddd" dependencies: - enhanced-resolve "^3.1.0" + enhanced-resolve "3.3.0" loader-utils "^1.0.2" - magic-string "^0.19.0" + magic-string "^0.22.3" source-map "^0.5.6" "@types/codemirror@^0.0.38": @@ -166,9 +166,9 @@ version "0.7.34" resolved "https://registry.yarnpkg.com/@types/dagre/-/dagre-0.7.34.tgz#69becfabbd59d277cae8237bdc7fb887571bc500" -"@types/jasmine@2.5.45": - version "2.5.45" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.5.45.tgz#58928a621d014ce6ab59c5a9c41071f7328b0ca9" +"@types/jasmine@~2.5.53": + version "2.5.53" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.5.53.tgz#4e0cefad09df5ec48c8dd40433512f84b1568d61" "@types/jquery@^3.2.6": version "3.2.9" @@ -852,6 +852,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +circular-dependency-plugin@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/circular-dependency-plugin/-/circular-dependency-plugin-3.0.0.tgz#9b68692e35b0e3510998d0164b6ae5011bea5760" + clap@^1.0.9: version "1.2.0" resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.0.tgz#59c90fe3e137104746ff19469a27a634ff68c857" @@ -1558,7 +1562,7 @@ engine.io@1.8.3: engine.io-parser "1.3.2" ws "1.1.2" -enhanced-resolve@^3.0.0, enhanced-resolve@^3.1.0: +enhanced-resolve@3.3.0, enhanced-resolve@^3.0.0: version "3.3.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.3.0.tgz#950964ecc7f0332a42321b673b38dc8ff15535b3" dependencies: @@ -1872,9 +1876,9 @@ fs-extra@^0.23.1: path-is-absolute "^1.0.0" rimraf "^2.2.8" -fs-extra@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" +fs-extra@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.0.tgz#414fb4ca2d2170ba0014159d3a8aec3303418d9e" dependencies: graceful-fs "^4.1.2" jsonfile "^3.0.0" @@ -2500,6 +2504,10 @@ is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -2962,9 +2970,9 @@ macaddress@^0.2.8: version "0.2.8" resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" -magic-string@^0.19.0: - version "0.19.1" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.19.1.tgz#14d768013caf2ec8fdea16a49af82fc377e75201" +magic-string@^0.22.3: + version "0.22.3" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.3.tgz#047989d99bfc7cbdefba1604adc8912551cd7ef1" dependencies: vlq "^0.2.1" @@ -3375,6 +3383,12 @@ opn@4.0.2: object-assign "^4.0.1" pinkie-promise "^2.0.0" +opn@~5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.1.0.tgz#72ce2306a17dbea58ff1041853352b4a8fc77519" + dependencies: + is-wsl "^1.1.0" + optimist@^0.6.1, optimist@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" @@ -4245,7 +4259,7 @@ rx-lite@*, rx-lite@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" -rxjs@^5.0.1, rxjs@^5.0.2, rxjs@^5.1.0: +rxjs@^5.0.1, rxjs@^5.0.2, rxjs@^5.4.0: version "5.4.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.2.tgz#2a3236fcbf03df57bae06fd6972fd99e5c08fcf7" dependencies: