[ARVADOS-WORKBENCH2] updated: 1.2.0-951-g89c3c64

Git user git at public.curoverse.com
Mon Nov 26 15:14:14 EST 2018


Summary of changes:
 src/common/webdav.ts                               |  34 ++++-
 src/components/chips-input/chips-input.tsx         |   3 +
 src/components/chips/chips.tsx                     |   4 +-
 .../confirmation-dialog/confirmation-dialog.tsx    |   8 +-
 src/components/data-explorer/data-explorer.tsx     |   4 +-
 src/components/icon/icon.tsx                       |   4 +
 src/index.tsx                                      |   4 +
 src/models/collection-file.ts                      |  15 +-
 src/models/repositories.ts                         |  10 ++
 src/models/resource.ts                             |   7 +-
 src/models/ssh-key.ts                              |  17 +++
 src/models/tree.test.ts                            |  10 +-
 src/models/tree.ts                                 |   9 +-
 src/models/workflow.ts                             |   2 +
 src/routes/route-change-handlers.ts                |  10 +-
 src/routes/routes.ts                               |  12 +-
 .../authorized-keys-service.ts                     |  34 +++++
 .../collection-service-files-response.ts           |   2 +-
 .../collection-service/collection-service.ts       |   4 +-
 .../common-service/common-resource-service.ts      |   3 +
 src/services/groups-service/groups-service.ts      |   2 +-
 src/services/project-service/project-service.ts    |  26 +++-
 .../repositories-service/repositories-service.ts   |  22 +++
 src/services/services.ts                           |   6 +
 src/store/advanced-tab/advanced-tab.ts             | 113 ++++++++-------
 src/store/auth/auth-action.ts                      |  98 ++++++++++++-
 src/store/auth/auth-actions.test.ts                |   1 +
 src/store/auth/auth-reducer.test.ts                |   7 +-
 src/store/auth/auth-reducer.ts                     |  21 ++-
 .../collection-panel-files-actions.ts              |  28 +++-
 src/store/collections/collection-copy-actions.ts   |   2 +
 src/store/collections/collection-create-actions.ts |  14 +-
 src/store/collections/collection-move-actions.ts   |   2 +
 .../collections/collection-partial-copy-actions.ts |   2 +
 src/store/collections/collection-upload-actions.ts |   9 +-
 src/store/context-menu/context-menu-actions.ts     |  34 ++++-
 src/store/data-explorer/data-explorer-reducer.ts   |   5 +-
 src/store/details-panel/details-panel-action.ts    |  63 ++++++++-
 .../favorite-panel-middleware-service.ts           |   3 +-
 src/store/navigation/navigation-action.ts          |   4 +
 src/store/processes/process-command-actions.ts     |   2 +-
 src/store/processes/process-copy-actions.ts        |  22 ++-
 src/store/processes/process-input-actions.ts       |  19 +++
 src/store/processes/process-move-actions.ts        |  19 +--
 src/store/processes/process-update-actions.ts      |   5 +-
 src/store/processes/processes-actions.ts           |  30 +++-
 .../project-panel-middleware-service.ts            |   3 +-
 src/store/projects/project-move-actions.ts         |   2 +
 src/store/repositories/repositories-actions.ts     | 107 ++++++++++++++
 src/store/repositories/repositories-reducer.ts     |  20 +++
 .../run-process-panel/run-process-panel-actions.ts |  50 +++++--
 .../run-process-panel/run-process-panel-reducer.ts |   3 +
 src/store/search-bar/search-bar-actions.test.ts    |   6 +-
 src/store/search-bar/search-bar-actions.ts         |  14 +-
 .../search-results-middleware-service.ts           |   3 +-
 .../shared-with-me-middleware-service.ts           |  14 +-
 src/store/sharing-dialog/sharing-dialog-actions.ts |   1 +
 .../side-panel-tree/side-panel-tree-actions.ts     |  19 +--
 src/store/store.ts                                 |   4 +-
 .../trash-panel/trash-panel-middleware-service.ts  |   3 +-
 src/store/tree-picker/picker-id.tsx                |  16 +++
 src/store/tree-picker/tree-picker-actions.ts       |  39 +++---
 src/store/tree-picker/tree-picker-reducer.ts       |  25 +++-
 src/store/workbench/workbench-actions.ts           |  39 ++++--
 .../workflow-panel/workflow-middleware-service.ts  |   3 +-
 src/validators/is-rsa-key.tsx                      |  10 ++
 src/validators/validators.tsx                      |   8 +-
 .../advanced-tab-dialog/advanced-tab-dialog.tsx    |   6 +-
 .../advanced-tab-dialog/metadataTab.tsx            |   9 +-
 .../action-sets/collection-action-set.ts           |   3 +-
 .../action-sets/collection-resource-action-set.ts  |   3 +-
 .../context-menu/action-sets/process-action-set.ts |   6 +-
 .../action-sets/process-resource-action-set.ts     |  19 +--
 .../context-menu/action-sets/project-action-set.ts |   4 +-
 .../action-sets/repository-action-set.ts           |  35 +++++
 .../context-menu/action-sets/ssh-key-action-set.ts |  27 ++++
 .../action-sets/trashed-collection-action-set.ts   |   4 +-
 src/views-components/context-menu/context-menu.tsx |   4 +-
 src/views-components/data-explorer/renderers.tsx   |  30 ++--
 .../details-panel/details-panel.tsx                |   5 +-
 .../details-panel/project-details.tsx              |  87 +++++++++---
 .../dialog-copy/dialog-collection-partial-copy.tsx |  19 ++-
 src/views-components/dialog-copy/dialog-copy.tsx   |  31 +++--
 .../dialog-create/dialog-repository-create.tsx     |  21 +++
 .../dialog-create/dialog-ssh-key-create.tsx        |  25 ++++
 .../dialog-forms/copy-collection-dialog.ts         |   4 +-
 .../dialog-forms/copy-process-dialog.ts            |   4 +-
 .../dialog-forms/create-repository-dialog.ts       |  19 +++
 .../dialog-forms/create-ssh-key-dialog.ts          |  19 +++
 .../dialog-forms/move-collection-dialog.ts         |   4 +-
 .../dialog-forms/move-process-dialog.ts            |   4 +-
 .../dialog-forms/move-project-dialog.ts            |   4 +-
 .../dialog-forms/partial-copy-collection-dialog.ts |   5 +-
 .../dialog-move/dialog-move-to.tsx                 |  18 ++-
 .../form-fields/collection-form-fields.tsx         |  13 +-
 .../form-fields/repository-form-fields.tsx         |  30 ++++
 .../form-fields/ssh-key-form-fields.tsx            |  25 ++++
 src/views-components/main-app-bar/account-menu.tsx |   8 +-
 .../main-content-bar/main-content-bar.tsx          |  24 +++-
 .../process-command-dialog.tsx                     |   2 +-
 .../process-input-dialog/process-input-dialog.tsx  |  82 +++++++++++
 .../process-remove-dialog.tsx}                     |  13 +-
 .../project-properties-dialog.tsx                  |  73 ++++++++++
 .../project-properties-form.tsx                    |  95 +++++++++++++
 .../project-tree-picker/project-tree-picker.tsx    |  17 ++-
 .../generic-projects-tree-picker.tsx               |  15 +-
 .../projects-tree-picker/projects-tree-picker.tsx  |  18 ++-
 .../repositories-sample-git-dialog.tsx             |  78 +++++++++++
 .../repository-attributes-dialog.tsx               |  89 ++++++++++++
 .../repository-remove-dialog.ts                    |  20 +++
 .../rich-text-editor-dialog.tsx                    |   4 +-
 .../run-process-dialog/change-workflow-dialog.ts   |  34 +++++
 .../ssh-keys-dialog/attributes-dialog.tsx          |  69 +++++++++
 .../ssh-keys-dialog/public-key-dialog.tsx          |  55 ++++++++
 .../remove-dialog.tsx}                             |  14 +-
 .../process-panel/process-information-card.tsx     |   8 +-
 src/views/process-panel/process-panel-root.tsx     |   6 +-
 src/views/process-panel/process-panel.tsx          |   4 +-
 .../repositories-panel/repositories-panel.tsx      | 154 +++++++++++++++++++++
 .../run-process-panel/inputs/boolean-input.tsx     |   3 +-
 .../inputs/directory-array-input.tsx               |   9 +-
 .../run-process-panel/inputs/directory-input.tsx   |   5 +-
 src/views/run-process-panel/inputs/enum-input.tsx  |   3 +-
 .../run-process-panel/inputs/file-array-input.tsx  |   7 +-
 src/views/run-process-panel/inputs/file-input.tsx  |   5 +-
 .../run-process-panel/inputs/float-array-input.tsx |  11 +-
 src/views/run-process-panel/inputs/float-input.tsx |   8 +-
 .../run-process-panel/inputs/generic-input.tsx     |   4 +-
 .../run-process-panel/inputs/int-array-input.tsx   |  11 +-
 src/views/run-process-panel/inputs/int-input.tsx   |   9 +-
 .../inputs/string-array-input.tsx                  |  10 +-
 .../run-process-panel/inputs/string-input.tsx      |   6 +-
 .../run-process-panel/run-process-inputs-form.tsx  |   2 +-
 src/views/run-process-panel/run-process-panel.tsx  |   4 +-
 src/views/ssh-key-panel/ssh-key-panel-root.tsx     | 116 ++++++++++++++++
 src/views/ssh-key-panel/ssh-key-panel.tsx          |  31 +++++
 src/views/workbench/workbench.tsx                  |  28 ++++
 .../workflow-panel/workflow-description-card.tsx   |  12 +-
 src/views/workflow-panel/workflow-graph.tsx        |  12 +-
 139 files changed, 2415 insertions(+), 394 deletions(-)
 create mode 100644 src/models/repositories.ts
 create mode 100644 src/models/ssh-key.ts
 create mode 100644 src/services/authorized-keys-service/authorized-keys-service.ts
 create mode 100644 src/services/repositories-service/repositories-service.ts
 create mode 100644 src/store/processes/process-input-actions.ts
 create mode 100644 src/store/repositories/repositories-actions.ts
 create mode 100644 src/store/repositories/repositories-reducer.ts
 create mode 100644 src/store/tree-picker/picker-id.tsx
 create mode 100644 src/validators/is-rsa-key.tsx
 create mode 100644 src/views-components/context-menu/action-sets/repository-action-set.ts
 create mode 100644 src/views-components/context-menu/action-sets/ssh-key-action-set.ts
 create mode 100644 src/views-components/dialog-create/dialog-repository-create.tsx
 create mode 100644 src/views-components/dialog-create/dialog-ssh-key-create.tsx
 create mode 100644 src/views-components/dialog-forms/create-repository-dialog.ts
 create mode 100644 src/views-components/dialog-forms/create-ssh-key-dialog.ts
 create mode 100644 src/views-components/form-fields/repository-form-fields.tsx
 create mode 100644 src/views-components/form-fields/ssh-key-form-fields.tsx
 create mode 100644 src/views-components/process-input-dialog/process-input-dialog.tsx
 copy src/views-components/{file-remove-dialog/multiple-files-remove-dialog.ts => process-remove-dialog/process-remove-dialog.tsx} (51%)
 create mode 100644 src/views-components/project-properties-dialog/project-properties-dialog.tsx
 create mode 100644 src/views-components/project-properties-dialog/project-properties-form.tsx
 create mode 100644 src/views-components/repositories-sample-git-dialog/repositories-sample-git-dialog.tsx
 create mode 100644 src/views-components/repository-attributes-dialog/repository-attributes-dialog.tsx
 create mode 100644 src/views-components/repository-remove-dialog/repository-remove-dialog.ts
 create mode 100644 src/views-components/run-process-dialog/change-workflow-dialog.ts
 create mode 100644 src/views-components/ssh-keys-dialog/attributes-dialog.tsx
 create mode 100644 src/views-components/ssh-keys-dialog/public-key-dialog.tsx
 copy src/views-components/{file-remove-dialog/multiple-files-remove-dialog.ts => ssh-keys-dialog/remove-dialog.tsx} (51%)
 create mode 100644 src/views/repositories-panel/repositories-panel.tsx
 create mode 100644 src/views/ssh-key-panel/ssh-key-panel-root.tsx
 create mode 100644 src/views/ssh-key-panel/ssh-key-panel.tsx

       via  89c3c647797787377f4d950b38d320ee3b28e92c (commit)
       via  fec23dba0d04028d842cc0e2f832ec84828f5bae (commit)
       via  34a6a12ac17833b645b18b47eb5c2411bc55a375 (commit)
       via  f6fae0a00b6e891069f7d81bd2917dbd3d55239b (commit)
       via  c9d00b6432a095f83647995df33a62d842fde8e1 (commit)
       via  4c551ecb7e6c888f783708604cfa3f8f340de03e (commit)
       via  827833da07f797f9ee445c62c301cbfbe01200dc (commit)
       via  ff91f7f0b03da40313191745848a3c297370376c (commit)
       via  4ab30205d4a2ea82d6fd4a71798ec2e1eba4ac0a (commit)
       via  a2e786b48045eb414c39c3265ab2992712706711 (commit)
       via  3a3de86b86ef60fc86f1190d42bc8a2471ab5276 (commit)
       via  931554500996a510fd9d31dddfda6e008ad65bea (commit)
       via  aebc1ac220838aa4f849473f3dda8d121f6118af (commit)
       via  425a9687b585517385d0ae5d62c5de26e06d3193 (commit)
       via  5fa46194c4a94e58a2b92de83f410112ef4c9150 (commit)
       via  d9c7613b436dad495a2b5a3d06b58c5cd5ef9592 (commit)
       via  da61c0b626bfef292175bb0c623213cb1efad63d (commit)
       via  dab7bbaf5fdee0e4e56c0bbfe14da5ad42b5869d (commit)
       via  d4068786fd7136cfe21c3ef3ad3040f57ed3385a (commit)
       via  aed25c0fef7e65b307d702e8ee515567d6c2a7c1 (commit)
       via  b56fac763b24e34c5c2ba42cf9e183ffcc2014fc (commit)
       via  3bb5a602028d5ace55da8af3637a7f9d4eb48c00 (commit)
       via  9eaee66663fa21962f46e301ba6257ab63a9b10c (commit)
       via  65bdf250e5a09633e482bacd968666861643c150 (commit)
       via  c27efd822acfd3bd93fc3e2e3e24a24146811eb7 (commit)
       via  e4bb589377e9be89787f1b3cc15a0cd2f17a6f7a (commit)
       via  e858ef67d3d17323b31eeb92e99ff8de70b5d591 (commit)
       via  13bf073c77ca9fcf75ebd31098a9bf538e96c9c9 (commit)
       via  42db83a0075f9704dcbfb2cd29821c97ff0fe34b (commit)
       via  62ff5a943865229c1630c66366f824511048ce63 (commit)
       via  856192df2e78cb7182122a77592044f5e51b1888 (commit)
       via  e3d13624759c128c326b64e9e0e60996bd28aadf (commit)
       via  cab8fbece33e9c6188b911552790f459c740f4cd (commit)
       via  c31b1e6d6d213bbae060d1111e3831c728433466 (commit)
       via  2de62809f717c64091505a01961b517ee6ccc9d4 (commit)
       via  a0aedfcf68e7b3d4caeee3e36d776ca0b34780bf (commit)
       via  f06b0aa5faeecdc4dfbc803170635ecfc19293de (commit)
       via  70bf37e9881a433b740cc70376d4b6680a582910 (commit)
       via  ead22eaffc696e9619d0ba7a71c8d54099200685 (commit)
       via  1a59e5dcc15a9a1aebfd15a08903fcb75efd2aac (commit)
       via  0a0db4ca8433ae210df5cf1475dd2b77e4aabec9 (commit)
       via  82908c571a492f19f2ea402e033fa84b6df15b61 (commit)
       via  abf8502a9a1f061f58586b966a4012674d9cb71e (commit)
       via  123bae90530147cf31e220066999b416d3610ae2 (commit)
       via  9e1596de7ac6ed8286b17c5e3d2b39bc0c03fa8f (commit)
       via  6e7601cf151b8384b353b3c90134e4bbb4939d2f (commit)
       via  ed5c052b271d357da4b85a10db33edd10d43685d (commit)
       via  2636921500b01485584eb43263815957b867122a (commit)
       via  aed4e6256e6d5ecb5edc60a04a5aab6f04d9fb99 (commit)
       via  185f57cf4371e7811077bee56976028dd640688d (commit)
       via  fcda82dca52aa45926f8e656c45baf892acdc634 (commit)
       via  fc05ea3e89e7618ea0a52d88a377533512d5ec32 (commit)
       via  de434883528ce218d384686092e82742a18491c7 (commit)
       via  ea4c952433d2ee3906999f629b8bc2076e0af13c (commit)
       via  2edee5acc1ef219dd90a7314c87df5683569afaa (commit)
       via  6f08c46e8d91662aab3b3e600868328c1bd1bacd (commit)
       via  a5f55ef0fa6bd61ba5678d5ccdbf26589c093212 (commit)
       via  6d1da474f9ae85108bbde00fe341cca65fd0ca06 (commit)
       via  f528f6f6ca52c8654b52f84e52339da8e91a9d9c (commit)
       via  c1b42ed027b39f04d4bf61b27d0603818cdd2bee (commit)
       via  db6ff2ea8246badb7bdcfb0ec0ad169134c5c7ba (commit)
       via  dd00886a1098e82a70b814d7d4c2f30d3e6e69c7 (commit)
       via  fa8e4468481efa1d43065b73ae1fa08fb0e851a7 (commit)
       via  c4fb72d1ddf4080cae66e296b873e5605e83e326 (commit)
       via  0101b0b9c7416f7aadb94ca71258b4d4e60af58a (commit)
       via  a2783c48c8210410de72bd17a32ab72d0f364cde (commit)
       via  90f56604ead086b6acc582bcb745a75e8bde5267 (commit)
       via  59ddd20573eab6116c590c2a692c0131fa2f3f4f (commit)
       via  02e77918141f173e5a61b17623c8cad0e8a1bae3 (commit)
       via  807660c78edbb1672af8b60348961896e48487b6 (commit)
       via  61eb34ae0ce62f67769baeba02b4e15971873e34 (commit)
       via  1eb2cc60cbf40d86db2304e11a678c3aa51af321 (commit)
       via  8e44d7f9d688d4d42b9d76f1a3c68924e927405c (commit)
       via  bb89fb18a6edfd90e80470abf040f6a5b9f6da1d (commit)
       via  00ec76eb43a0f27c02669cbfce16d0d2211ff0b4 (commit)
       via  d1231b6ce7e8d40498b15011b88117812acdf632 (commit)
       via  ce19ce10f479c168f72003495696fdd0f01ecc52 (commit)
       via  165d40cdee00c0d8ae11f711c898498c032b1374 (commit)
       via  ec9081aafdd4b8c251e935edd047126ad411767e (commit)
       via  9da0da6012b6c4b80db90fdd5862d37ad2113aa4 (commit)
       via  abee9c2585e30a4217b5adc3b40d298227f6a650 (commit)
       via  546052817ac18623f5389914a3077e8cc6a3d4f4 (commit)
       via  6c40105be37e95350ad0537c38401d58e6f84e2c (commit)
       via  c32547d76b1f7358617a1e674ecc4f20a4482868 (commit)
       via  297b0846754e931979ec37cc3479e2263e3b0458 (commit)
       via  b448c1c81f6e79c7afb2e99f68b152e3eb7f18e1 (commit)
       via  fbbc53779fb3adf15d70936477aab771ee7caf42 (commit)
       via  7da8834efcac17c997d6a7f7a557b7865b1c1137 (commit)
       via  3385e026886b5ad3dd7b20675a1ad79f8a3b4947 (commit)
       via  48e644dd9a39ec0641eb4d1907700d348a560421 (commit)
       via  1f9a8ec32f818d8e78d683ad5569b9e4ae0f693a (commit)
       via  1b99184996d54eb68c7a7be6bdc14e2bcdc06e5c (commit)
       via  da050efb3aea15f768e1873f80459e55a56f55e7 (commit)
       via  5e5ccecda9c67459a5da3afeb4dabf37949a13eb (commit)
       via  8c5e0acf680bb7f3527be8f474160c5f431fe581 (commit)
       via  44e89f6c8f0bb6d2ededea8ef107766f65b9bb6a (commit)
       via  59213045f0a135ef97249ff69e1737ea88123007 (commit)
       via  bf801d31a42b40e6bfa5e99d2d2e17b236a372c2 (commit)
       via  60df7056b536f7a333299638ca19bc12aee94d47 (commit)
       via  c1d96828aa5050c9026afcd243c162bcf354b52b (commit)
       via  7a2f0082071947bfec27ed4f2a16250e1d611d21 (commit)
       via  341b552800f6866fc3f73b4f6c1468425e485694 (commit)
       via  853d8c61628e6c948406aa7ad4b9c4a6e11ef25a (commit)
       via  859357091e1b7ed2566fc9da772fb64af0e9e9cf (commit)
       via  23180724fefb8b4b31e2c07e711101367942f721 (commit)
       via  01a728d112f5728b9552c7e63f074487a4d056f0 (commit)
       via  33e245270a23dd593c8a068253456976a2bc23c9 (commit)
       via  6f316731d603520d6e911641447ffb74f0cc6b61 (commit)
       via  1326c2ee2772e5e6191e49773bcb00840153e559 (commit)
       via  c4d4006610c9ebeee1b61e3867f5ec8459180231 (commit)
       via  35c2b0aa20a24768ae34c7a3788b1e5b43cdfdac (commit)
       via  2275f9352df4a782d3e73a450a7ff12a99ae711e (commit)
       via  16cba0902c3f450bd958fe77125bb583ed53b8a4 (commit)
       via  f27157a0cd7178ee83e69bc2778c1730aed14335 (commit)
       via  955b37033e9818617af82241e9d1c2d482c47dac (commit)
       via  c00eef5dc15d93f40a8b24753688c8c40c69d819 (commit)
       via  0eaad7ee985d2534e030e2d2839392435c33bba2 (commit)
       via  bde866ac574bdf34e17c1d8124f2dc36e854ad3c (commit)
       via  ba27bdf218da8894df4ffa6174c67c1fb3e70c81 (commit)
       via  1f5cb5f90f9064034a55fe76a89bc4f76ad72335 (commit)
       via  95563e85e95cae6a4ef6d2c2137fe1a3533ef8db (commit)
       via  b9cd512debf45e62d9b81a12b4ac64fde998c356 (commit)
      from  72b6c853b95b1ef3da2a0beca3a31e4838a17896 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 89c3c647797787377f4d950b38d320ee3b28e92c
Merge: 72b6c85 fec23db
Author: Daniel Kos <daniel.kos at contractors.roche.com>
Date:   Mon Nov 26 21:14:06 2018 +0100

    refs #master Merge branch 'origin/master' into 14280-query-language
    
    # Conflicts:
    #       src/store/collections/collection-create-actions.ts
    #       src/store/processes/process-move-actions.ts
    #       src/store/processes/process-update-actions.ts
    
    Arvados-DCO-1.1-Signed-off-by: Daniel Kos <daniel.kos at contractors.roche.com>

diff --cc src/models/resource.ts
index f8028c7,5fa6179..7852a73
--- a/src/models/resource.ts
+++ b/src/models/resource.ts
@@@ -77,22 -82,3 +82,22 @@@ export const extractUuidKind = (uuid: s
              return undefined;
      }
  };
 +
 +export const getResourceKind = (kind?: string) => {
 +    switch (kind) {
 +        case "arvados#collection":
 +            return ResourceKind.COLLECTION;
 +        case "arvados#container":
 +            return ResourceKind.CONTAINER;
 +        case "arvados#containerRequest":
 +            return ResourceKind.CONTAINER_REQUEST;
 +        case "arvados#group":
 +            return ResourceKind.GROUP;
 +        case "arvados#log":
 +            return ResourceKind.LOG;
 +        case "arvados#workflow":
 +            return ResourceKind.WORKFLOW;
 +        default:
 +            return undefined;
 +    }
- }
++};
diff --cc src/store/auth/auth-action.ts
index ac2e0b7,28559b1..9aadd5b
--- a/src/store/auth/auth-action.ts
+++ b/src/store/auth/auth-action.ts
@@@ -4,10 -4,16 +4,16 @@@
  
  import { ofType, unionize, UnionOf } from '~/common/unionize';
  import { Dispatch } from "redux";
- import { User } from "~/models/user";
 -import { reset, stopSubmit, startSubmit } from 'redux-form';
++import { reset, stopSubmit, startSubmit, FormErrors } from 'redux-form';
+ import { AxiosInstance } from "axios";
  import { RootState } from "../store";
+ import { snackbarActions } from '~/store/snackbar/snackbar-actions';
+ import { dialogActions } from '~/store/dialog/dialog-actions';
+ import { setBreadcrumbs } from '~/store/breadcrumbs/breadcrumbs-actions';
  import { ServiceRepository } from "~/services/services";
- import { AxiosInstance } from "axios";
+ import { getAuthorizedKeysServiceError, AuthorizedKeysServiceError } from '~/services/authorized-keys-service/authorized-keys-service';
+ import { KeyType, SshKeyResource } from '~/models/ssh-key';
+ import { User } from "~/models/user";
  
  export const authActions = unionize({
      SAVE_API_TOKEN: ofType<string>(),
@@@ -70,4 -89,77 +89,77 @@@ export const getUserDetails = () => (di
      });
  };
  
+ export const openSshKeyCreateDialog = () => dialogActions.OPEN_DIALOG({ id: SSH_KEY_CREATE_FORM_NAME, data: {} });
+ 
+ export const openPublicKeyDialog = (name: string, publicKey: string) =>
+     dialogActions.OPEN_DIALOG({ id: SSH_KEY_PUBLIC_KEY_DIALOG, data: { name, publicKey } });
+ 
+ export const openSshKeyAttributesDialog = (index: number) =>
+     (dispatch: Dispatch, getState: () => RootState) => {
+         const sshKey = getState().auth.sshKeys[index];
+         dispatch(dialogActions.OPEN_DIALOG({ id: SSH_KEY_ATTRIBUTES_DIALOG, data: { sshKey } }));
+     };
+ 
+ export const openSshKeyRemoveDialog = (uuid: string) =>
+     (dispatch: Dispatch, getState: () => RootState) => {
+         dispatch(dialogActions.OPEN_DIALOG({
+             id: SSH_KEY_REMOVE_DIALOG,
+             data: {
+                 title: 'Remove public key',
+                 text: 'Are you sure you want to remove this public key?',
+                 confirmButtonLabel: 'Remove',
+                 uuid
+             }
+         }));
+     };
+ 
+ export const removeSshKey = (uuid: string) =>
+     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
+         await services.authorizedKeysService.delete(uuid);
+         dispatch(authActions.REMOVE_SSH_KEY(uuid));
+         dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Public Key has been successfully removed.', hideDuration: 2000 }));
+     };
+ 
+ export const createSshKey = (data: SshKeyCreateFormDialogData) =>
+     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         const userUuid = getState().auth.user!.uuid;
+         const { name, publicKey } = data;
+         dispatch(startSubmit(SSH_KEY_CREATE_FORM_NAME));
+         try {
+             const newSshKey = await services.authorizedKeysService.create({
+                 name,
+                 publicKey,
+                 keyType: KeyType.SSH,
+                 authorizedUserUuid: userUuid
+             });
+             dispatch(authActions.ADD_SSH_KEY(newSshKey));
+             dispatch(dialogActions.CLOSE_DIALOG({ id: SSH_KEY_CREATE_FORM_NAME }));
+             dispatch(reset(SSH_KEY_CREATE_FORM_NAME));
+             dispatch(snackbarActions.OPEN_SNACKBAR({
+                 message: "Public key has been successfully created.",
+                 hideDuration: 2000
+             }));
+         } catch (e) {
+             const error = getAuthorizedKeysServiceError(e);
+             if (error === AuthorizedKeysServiceError.UNIQUE_PUBLIC_KEY) {
 -                dispatch(stopSubmit(SSH_KEY_CREATE_FORM_NAME, { publicKey: 'Public key already exists.' }));
++                dispatch(stopSubmit(SSH_KEY_CREATE_FORM_NAME, { publicKey: 'Public key already exists.' } as FormErrors));
+             } else if (error === AuthorizedKeysServiceError.INVALID_PUBLIC_KEY) {
 -                dispatch(stopSubmit(SSH_KEY_CREATE_FORM_NAME, { publicKey: 'Public key is invalid' }));
++                dispatch(stopSubmit(SSH_KEY_CREATE_FORM_NAME, { publicKey: 'Public key is invalid' } as FormErrors));
+             }
+         }
+     };
+ 
+ export const loadSshKeysPanel = () =>
+     async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+         try {
+             dispatch(setBreadcrumbs([{ label: 'SSH Keys'}]));
+             const response = await services.authorizedKeysService.list();
+             dispatch(authActions.SET_SSH_KEYS(response.items));
+         } catch (e) {
+             return;
+         }
+     };
+ 
+ 
  export type AuthAction = UnionOf<typeof authActions>;
diff --cc src/store/collections/collection-create-actions.ts
index c61e8da,f437568..8d1e9ba
--- a/src/store/collections/collection-create-actions.ts
+++ b/src/store/collections/collection-create-actions.ts
@@@ -38,9 -40,10 +40,10 @@@ export const openCollectionCreateDialo
  export const createCollection = (data: CollectionCreateFormDialogData) =>
      async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
          dispatch(startSubmit(COLLECTION_CREATE_FORM_NAME));
 -        let newCollection: CollectionResource | null = null;
++        let newCollection: CollectionResource;
          try {
              dispatch(progressIndicatorActions.START_WORKING(COLLECTION_CREATE_FORM_NAME));
-             const newCollection = await services.collectionService.create(data);
+             newCollection = await services.collectionService.create(data);
              await dispatch<any>(uploadCollectionFiles(newCollection.uuid));
              dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_CREATE_FORM_NAME }));
              dispatch(reset(COLLECTION_CREATE_FORM_NAME));
@@@ -49,7 -52,16 +52,16 @@@
          } catch (e) {
              const error = getCommonResourceServiceError(e);
              if (error === CommonResourceServiceError.UNIQUE_VIOLATION) {
 -                dispatch(stopSubmit(COLLECTION_CREATE_FORM_NAME, { name: 'Collection with the same name already exists.' }));
 +                dispatch(stopSubmit(COLLECTION_CREATE_FORM_NAME, { name: 'Collection with the same name already exists.' } as FormErrors));
+             } else if (error === CommonResourceServiceError.NONE) {
+                 dispatch(stopSubmit(COLLECTION_CREATE_FORM_NAME));
+                 dispatch(dialogActions.CLOSE_DIALOG({ id: COLLECTION_CREATE_FORM_NAME }));
+                 dispatch(snackbarActions.OPEN_SNACKBAR({
+                     message: 'Collection has not been created.',
+                     hideDuration: 2000,
+                     kind: SnackbarKind.ERROR
+                 }));
+                 await services.collectionService.delete(newCollection!.uuid);
              }
              dispatch(progressIndicatorActions.STOP_WORKING(COLLECTION_CREATE_FORM_NAME));
              return;
diff --cc src/store/processes/process-move-actions.ts
index 89dc0ef,7e65bcc..dcf9718
--- a/src/store/processes/process-move-actions.ts
+++ b/src/store/processes/process-move-actions.ts
@@@ -45,9 -42,7 +42,7 @@@ export const moveProcess = (resource: M
          } catch (e) {
              const error = getCommonResourceServiceError(e);
              if (error === CommonResourceServiceError.UNIQUE_VIOLATION) {
 -                dispatch(stopSubmit(PROCESS_MOVE_FORM_NAME, { ownerUuid: 'A process with the same name already exists in the target project.' }));
 +                dispatch(stopSubmit(PROCESS_MOVE_FORM_NAME, { ownerUuid: 'A process with the same name already exists in the target project.' } as FormErrors));
-             } else if (error === CommonResourceServiceError.MODIFYING_CONTAINER_REQUEST_FINAL_STATE) {
-                 dispatch(stopSubmit(PROCESS_MOVE_FORM_NAME, { ownerUuid: 'You can move only draft processes.' } as FormErrors));
              } else {
                  dispatch(dialogActions.CLOSE_DIALOG({ id: PROCESS_MOVE_FORM_NAME }));
                  dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not move the process.', hideDuration: 2000 }));
diff --cc src/store/processes/process-update-actions.ts
index dfd548b,2063f11..372e188
--- a/src/store/processes/process-update-actions.ts
+++ b/src/store/processes/process-update-actions.ts
@@@ -42,9 -41,7 +41,7 @@@ export const updateProcess = (resource
          } catch (e) {
              const error = getCommonResourceServiceError(e);
              if (error === CommonResourceServiceError.UNIQUE_VIOLATION) {
 -                dispatch(stopSubmit(PROCESS_UPDATE_FORM_NAME, { name: 'Process with the same name already exists.' }));
 +                dispatch(stopSubmit(PROCESS_UPDATE_FORM_NAME, { name: 'Process with the same name already exists.' } as FormErrors));
-             } else if (error === CommonResourceServiceError.MODIFYING_CONTAINER_REQUEST_FINAL_STATE) {
-                 dispatch(stopSubmit(PROCESS_UPDATE_FORM_NAME, { name: 'You cannot modified in "Final" state.' } as FormErrors));
              } else {
                  dispatch(dialogActions.CLOSE_DIALOG({ id: PROCESS_UPDATE_FORM_NAME }));
                  dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Could not update the process.', hideDuration: 2000 }));
diff --cc src/store/repositories/repositories-actions.ts
index 0000000,a672738..dd80f8d
mode 000000,100644..100644
--- a/src/store/repositories/repositories-actions.ts
+++ b/src/store/repositories/repositories-actions.ts
@@@ -1,0 -1,107 +1,107 @@@
+ // Copyright (C) The Arvados Authors. All rights reserved.
+ //
+ // SPDX-License-Identifier: AGPL-3.0
+ 
+ import { Dispatch } from "redux";
+ import { bindDataExplorerActions } from '~/store/data-explorer/data-explorer-action';
+ import { RootState } from '~/store/store';
+ import { ServiceRepository } from "~/services/services";
+ import { navigateToRepositories } from "~/store/navigation/navigation-action";
+ import { unionize, ofType, UnionOf } from "~/common/unionize";
+ import { dialogActions } from '~/store/dialog/dialog-actions';
+ import { RepositoryResource } from "~/models/repositories";
 -import { startSubmit, reset, stopSubmit } from "redux-form";
++import { startSubmit, reset, stopSubmit, FormErrors } from "redux-form";
+ import { getCommonResourceServiceError, CommonResourceServiceError } from "~/services/common-service/common-resource-service";
+ import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
+ 
+ export const repositoriesActions = unionize({
+     SET_REPOSITORIES: ofType<any>(),
+ });
+ 
+ export type RepositoriesActions = UnionOf<typeof repositoriesActions>;
+ 
+ export const REPOSITORIES_PANEL = 'repositoriesPanel';
+ export const REPOSITORIES_SAMPLE_GIT_DIALOG = 'repositoriesSampleGitDialog';
+ export const REPOSITORY_ATTRIBUTES_DIALOG = 'repositoryAttributesDialog';
+ export const REPOSITORY_CREATE_FORM_NAME = 'repositoryCreateFormName';
+ export const REPOSITORY_REMOVE_DIALOG = 'repositoryRemoveDialog';
+ 
+ export const openRepositoriesSampleGitDialog = () =>
+     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         const uuidPrefix = getState().properties.uuidPrefix;
+         dispatch(dialogActions.OPEN_DIALOG({ id: REPOSITORIES_SAMPLE_GIT_DIALOG, data: { uuidPrefix } }));
+     };
+ 
+ export const openRepositoryAttributes = (index: number) =>
+     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         const repositoryData = getState().repositories.items[index];
+         dispatch(dialogActions.OPEN_DIALOG({ id: REPOSITORY_ATTRIBUTES_DIALOG, data: { repositoryData } }));
+     };
+ 
+ export const openRepositoryCreateDialog = () =>
+     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         const userUuid = await services.authService.getUuid();
+         const user = await services.userService.get(userUuid!);
+         dispatch(reset(REPOSITORY_CREATE_FORM_NAME));
+         dispatch(dialogActions.OPEN_DIALOG({ id: REPOSITORY_CREATE_FORM_NAME, data: { user } }));
+     };
+ 
+ export const createRepository = (repository: RepositoryResource) =>
+     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         const userUuid = await services.authService.getUuid();
+         const user = await services.userService.get(userUuid!);
+         dispatch(startSubmit(REPOSITORY_CREATE_FORM_NAME));
+         try {
+             const newRepository = await services.repositoriesService.create({ name: `${user.username}/${repository.name}` });
+             dispatch(dialogActions.CLOSE_DIALOG({ id: REPOSITORY_CREATE_FORM_NAME }));
+             dispatch(reset(REPOSITORY_CREATE_FORM_NAME));
 -            dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Repository has been successfully created.", hideDuration: 2000, kind: SnackbarKind.SUCCESS })); 
 -            dispatch<any>(loadRepositoriesData());     
++            dispatch(snackbarActions.OPEN_SNACKBAR({ message: "Repository has been successfully created.", hideDuration: 2000, kind: SnackbarKind.SUCCESS }));
++            dispatch<any>(loadRepositoriesData());
+             return newRepository;
+         } catch (e) {
+             const error = getCommonResourceServiceError(e);
+             if (error === CommonResourceServiceError.NAME_HAS_ALREADY_BEEN_TAKEN) {
 -                dispatch(stopSubmit(REPOSITORY_CREATE_FORM_NAME, { name: 'Repository with the same name already exists.' }));
++                dispatch(stopSubmit(REPOSITORY_CREATE_FORM_NAME, { name: 'Repository with the same name already exists.' } as FormErrors));
+             }
+             return undefined;
+         }
+     };
+ 
+ export const openRemoveRepositoryDialog = (uuid: string) =>
+     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         dispatch(dialogActions.OPEN_DIALOG({
+             id: REPOSITORY_REMOVE_DIALOG,
+             data: {
+                 title: 'Remove repository',
+                 text: 'Are you sure you want to remove this repository?',
+                 confirmButtonLabel: 'Remove',
+                 uuid
+             }
+         }));
+     };
+ 
+ export const removeRepository = (uuid: string) =>
+     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removing ...' }));
+         await services.repositoriesService.delete(uuid);
+         dispatch(snackbarActions.OPEN_SNACKBAR({ message: 'Removed.', hideDuration: 2000 }));
+         dispatch<any>(loadRepositoriesData());
+     };
+ 
+ const repositoriesBindedActions = bindDataExplorerActions(REPOSITORIES_PANEL);
+ 
+ export const openRepositoriesPanel = () =>
+     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         dispatch<any>(navigateToRepositories);
+     };
+ 
+ export const loadRepositoriesData = () =>
+     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
+         const repositories = await services.repositoriesService.list();
+         dispatch(repositoriesActions.SET_REPOSITORIES(repositories.items));
+     };
+ 
+ export const loadRepositoriesPanel = () =>
+     (dispatch: Dispatch) => {
+         dispatch(repositoriesBindedActions.REQUEST_ITEMS());
 -    };
++    };
diff --cc src/store/search-bar/search-bar-actions.test.ts
index 48dfeec,0000000..d936caf
mode 100644,000000..100644
--- a/src/store/search-bar/search-bar-actions.test.ts
+++ b/src/store/search-bar/search-bar-actions.test.ts
@@@ -1,137 -1,0 +1,137 @@@
 +// Copyright (C) The Arvados Authors. All rights reserved.
 +//
 +// SPDX-License-Identifier: AGPL-3.0
 +
 +import { getAdvancedDataFromQuery, getQueryFromAdvancedData, parseQuery } from "~/store/search-bar/search-bar-actions";
 +import { ResourceKind } from "~/models/resource";
 +import { ClusterObjectType } from "~/models/search-bar";
 +
 +describe('search-bar-actions', () => {
 +    describe('parseQuery', () => {
 +        it('should correctly parse query #1', () => {
 +            const q = 'val0 is:trashed val1';
 +            const r = parseQuery(q);
 +            expect(r.hasKeywords).toBeTruthy();
 +            expect(r.values).toEqual(['val0', 'val1']);
 +            expect(r.properties).toEqual({
 +                is: ['trashed']
 +            });
 +        });
 +
 +        it('should correctly parse query #2 (value with keyword should be ignored)', () => {
 +            const q = 'val0 is:from:trashed val1';
 +            const r = parseQuery(q);
 +            expect(r.hasKeywords).toBeTruthy();
 +            expect(r.values).toEqual(['val0', 'val1']);
 +            expect(r.properties).toEqual({
 +                from: ['trashed']
 +            });
 +        });
 +
 +        it('should correctly parse query #3 (many keywords)', () => {
 +            const q = 'val0 is:trashed val2 from:2017-04-01 val1';
 +            const r = parseQuery(q);
 +            expect(r.hasKeywords).toBeTruthy();
 +            expect(r.values).toEqual(['val0', 'val2', 'val1']);
 +            expect(r.properties).toEqual({
 +                is: ['trashed'],
 +                from: ['2017-04-01']
 +            });
 +        });
 +
 +        it('should correctly parse query #4 (no duplicated values)', () => {
 +            const q = 'val0 is:trashed val2 val2 val0';
 +            const r = parseQuery(q);
 +            expect(r.hasKeywords).toBeTruthy();
 +            expect(r.values).toEqual(['val0', 'val2']);
 +            expect(r.properties).toEqual({
 +                is: ['trashed']
 +            });
 +        });
 +
 +        it('should correctly parse query #5 (properties)', () => {
 +            const q = 'val0 has:filesize:100mb val2 val2 val0';
 +            const r = parseQuery(q);
 +            expect(r.hasKeywords).toBeTruthy();
 +            expect(r.values).toEqual(['val0', 'val2']);
 +            expect(r.properties).toEqual({
 +                'has': ['filesize:100mb']
 +            });
 +        });
 +
 +        it('should correctly parse query #6 (multiple properties, multiple is)', () => {
 +            const q = 'val0 has:filesize:100mb val2 has:user:daniel is:starred val2 val0 is:trashed';
 +            const r = parseQuery(q);
 +            expect(r.hasKeywords).toBeTruthy();
 +            expect(r.values).toEqual(['val0', 'val2']);
 +            expect(r.properties).toEqual({
 +                'has': ['filesize:100mb', 'user:daniel'],
 +                'is': ['starred', 'trashed']
 +            });
 +        });
 +    });
 +
 +    describe('getAdvancedDataFromQuery', () => {
 +        it('should correctly build advanced data record from query #1', () => {
 +            const r = getAdvancedDataFromQuery('val0 has:filesize:100mb val2 has:user:daniel is:starred val2 val0 is:trashed');
 +            expect(r).toEqual({
 +                searchValue: 'val0 val2',
 +                type: undefined,
 +                cluster: undefined,
 +                projectUuid: undefined,
 +                inTrash: true,
 +                dateFrom: undefined,
 +                dateTo: undefined,
 +                properties: [{
 +                    key: 'filesize',
 +                    value: '100mb'
 +                }, {
 +                    key: 'user',
 +                    value: 'daniel'
 +                }],
 +                saveQuery: false,
 +                queryName: ''
-             })
++            });
 +        });
 +
 +        it('should correctly build advanced data record from query #2', () => {
 +            const r = getAdvancedDataFromQuery('document from:2017-08-01 pdf has:filesize:101mb is:trashed type:arvados#collection cluster:indianapolis');
 +            expect(r).toEqual({
 +                searchValue: 'document pdf',
 +                type: ResourceKind.COLLECTION,
 +                cluster: ClusterObjectType.INDIANAPOLIS,
 +                projectUuid: undefined,
 +                inTrash: true,
 +                dateFrom: '2017-08-01',
 +                dateTo: undefined,
 +                properties: [{
 +                    key: 'filesize',
 +                    value: '101mb'
 +                }],
 +                saveQuery: false,
 +                queryName: ''
-             })
++            });
 +        });
 +    });
 +
 +    describe('getQueryFromAdvancedData', () => {
 +        it('should build query from advanced data', () => {
 +            const q = getQueryFromAdvancedData({
 +                searchValue: 'document pdf',
 +                type: ResourceKind.COLLECTION,
 +                cluster: ClusterObjectType.INDIANAPOLIS,
 +                projectUuid: undefined,
 +                inTrash: true,
 +                dateFrom: '2017-08-01',
 +                dateTo: '',
 +                properties: [{
 +                    key: 'filesize',
 +                    value: '101mb'
 +                }],
 +                saveQuery: false,
 +                queryName: ''
 +            });
 +            expect(q).toBe('document pdf type:arvados#collection cluster:indianapolis is:trashed from:2017-08-01 has:filesize:101mb');
-         })
++        });
 +    });
 +});
diff --cc src/store/search-bar/search-bar-actions.ts
index 1746c95,165392c..2ad9b28
--- a/src/store/search-bar/search-bar-actions.ts
+++ b/src/store/search-bar/search-bar-actions.ts
@@@ -10,15 -10,14 +10,15 @@@ import { RootState } from '~/store/stor
  import { initUserProject } from '~/store/tree-picker/tree-picker-actions';
  import { ServiceRepository } from '~/services/services';
  import { FilterBuilder } from "~/services/api/filter-builder";
 -import { ResourceKind } from '~/models/resource';
 +import { getResourceKind, ResourceKind } from '~/models/resource';
  import { GroupClass } from '~/models/group';
  import { SearchView } from '~/store/search-bar/search-bar-reducer';
 -import { navigateToSearchResults, navigateTo } from '~/store/navigation/navigation-action';
 +import { navigateTo, navigateToSearchResults } from '~/store/navigation/navigation-action';
  import { snackbarActions, SnackbarKind } from '~/store/snackbar/snackbar-actions';
- import { ClusterObjectType, getClusterObjectType, PropertyValues, SearchBarAdvanceFormData } from '~/models/search-bar';
 -import { initialize } from 'redux-form';
 -import { SearchBarAdvanceFormData, PropertyValues } from '~/models/search-bar';
++import { getClusterObjectType, PropertyValues, SearchBarAdvanceFormData } from '~/models/search-bar';
  import { debounce } from 'debounce';
 +import * as _ from "lodash";
 +import { getModifiedKeysValues } from "~/common/objects";
  
  export const searchBarActions = unionize({
      SET_CURRENT_VIEW: ofType<string>(),
@@@ -202,228 -191,15 +202,228 @@@ const searchGroups = (searchValue: stri
          }
      };
  
 -export const getFilters = (filterName: string, searchValue: string, props: any): string => {
 -    const { resourceKind, dateTo, dateFrom } = props;
 -    return new FilterBuilder()
 -        .addIsA("uuid", buildUuidFilter(resourceKind))
 -        .addILike(filterName, searchValue, GroupContentsResourcePrefix.COLLECTION)
 -        .addILike(filterName, searchValue, GroupContentsResourcePrefix.PROCESS)
 -        .addILike(filterName, searchValue, GroupContentsResourcePrefix.PROJECT)
 -        .addLte('modified_at', buildDateFilter(dateTo))
 -        .addGte('modified_at', buildDateFilter(dateFrom))
 +const buildQueryFromKeyMap = (data: any, keyMap: string[][], mode: 'rebuild' | 'reuse') => {
 +    let value = data.searchValue;
 +
 +    const addRem = (field: string, key: string) => {
 +        const v = data[key];
 +        if (v) {
 +            const nv = v === true
 +                ? `${field}`
 +                : `${field}:${v}`;
 +
 +            if (mode === 'rebuild') {
 +                value = value + ' ' + nv;
 +            } else {
 +                value = nv + ' ' + value;
 +            }
 +        } else if (data.hasOwnProperty(key) && (v === undefined || v === false)) {
 +            const pattern = v === false
 +                ? `${field.replace(':', '\\:\\s*')}\\s*`
 +                : `${field.replace(':', '\\:\\s*')}\\:\\s*[\\w|\\#|\\-|\\/]*`;
 +            value = value.replace(new RegExp(pattern), '');
 +        }
 +    };
 +
 +    keyMap.forEach(km => addRem(km[0], km[1]));
 +
 +    return value;
 +};
 +
 +export const getQueryFromAdvancedData = (data: SearchBarAdvanceFormData, prevData?: SearchBarAdvanceFormData) => {
 +    let value = '';
 +
 +    const flatData = (data: SearchBarAdvanceFormData) => {
 +        const fo = {
 +            searchValue: data.searchValue,
 +            type: data.type,
 +            cluster: data.cluster,
 +            projectUuid: data.projectUuid,
 +            inTrash: data.inTrash,
 +            dateFrom: data.dateFrom,
 +            dateTo: data.dateTo,
 +        };
 +        (data.properties || []).forEach(p => fo[`prop-${p.key}`] = p.value);
 +        return fo;
 +    };
 +
 +    const keyMap = [
 +        ['type', 'type'],
 +        ['cluster', 'cluster'],
 +        ['project', 'projectUuid'],
 +        ['is:trashed', 'inTrash'],
 +        ['from', 'dateFrom'],
 +        ['to', 'dateTo']
 +    ];
 +    _.union(data.properties, prevData ? prevData.properties : [])
 +        .forEach(p => keyMap.push([`has:${p.key}`, `prop-${p.key}`]));
 +
 +    if (prevData) {
 +        const obj = getModifiedKeysValues(flatData(data), flatData(prevData));
 +        console.log(obj);
 +        value = buildQueryFromKeyMap({
 +            searchValue: data.searchValue,
 +            ...obj
 +        } as SearchBarAdvanceFormData, keyMap, "reuse");
 +    } else {
 +        value = buildQueryFromKeyMap(flatData(data), keyMap, "rebuild");
 +    }
 +
 +    value = value.trim();
 +    return value;
 +};
 +
 +export const parseQuery: (query: string) => { hasKeywords: boolean; values: string[]; properties: any } = (searchValue: string) => {
 +    const keywords = [
 +        'type:',
 +        'cluster:',
 +        'project:',
 +        'is:',
 +        'from:',
 +        'to:',
 +        'has:'
 +    ];
 +
 +    const hasKeywords = (search: string) => keywords.reduce((acc, keyword) => acc + search.indexOf(keyword) >= 0 ? 1 : 0, 0);
 +    let keywordsCnt = 0;
 +
 +    const properties = {};
 +
 +    keywords.forEach(k => {
 +        let p = searchValue.indexOf(k);
 +        const key = k.substr(0, k.length - 1);
 +
 +        while (p >= 0) {
 +            const l = searchValue.length;
 +            keywordsCnt += 1;
 +
 +            let v = '';
 +            let i = p + k.length;
 +            while (i < l && searchValue[i] === ' ') {
 +                ++i;
 +            }
 +            const vp = i;
 +            while (i < l && searchValue[i] !== ' ') {
 +                v += searchValue[i];
 +                ++i;
 +            }
 +
 +            if (hasKeywords(v)) {
 +                searchValue = searchValue.substr(0, p) + searchValue.substr(vp);
 +            } else {
 +                if (v !== '') {
 +                    if (!properties[key]) {
 +                        properties[key] = [];
 +                    }
 +                    properties[key].push(v);
 +                }
 +                searchValue = searchValue.substr(0, p) + searchValue.substr(i);
 +            }
 +            p = searchValue.indexOf(k);
 +        }
 +    });
 +
 +    const values = _.uniq(searchValue.split(' ').filter(v => v.length > 0));
 +
 +    return { hasKeywords: keywordsCnt > 0, values, properties };
 +};
 +
 +export const getAdvancedDataFromQuery = (query: string): SearchBarAdvanceFormData => {
 +    const r = parseQuery(query);
 +
 +    const getFirstProp = (name: string) => r.properties[name] && r.properties[name][0];
 +    const getPropValue = (name: string, value: string) => r.properties[name] && r.properties[name].find((v: string) => v === value);
 +    const getProperties = () => {
-         if (r.properties['has']) {
-             return r.properties['has'].map((value: string) => {
++        if (r.properties.has) {
++            return r.properties.has.map((value: string) => {
 +                const v = value.split(':');
 +                return {
 +                    key: v[0],
 +                    value: v[1]
-                 }
-             })
++                };
++            });
 +        }
 +        return [];
 +    };
 +
 +    return {
 +        searchValue: r.values.join(' '),
 +        type: getResourceKind(getFirstProp('type')),
 +        cluster: getClusterObjectType(getFirstProp('cluster')),
 +        projectUuid: getFirstProp('project'),
 +        inTrash: getPropValue('is', 'trashed') !== undefined,
 +        dateFrom: getFirstProp('from'),
 +        dateTo: getFirstProp('to'),
 +        properties: getProperties(),
 +        saveQuery: false,
-         queryName: '',
-     }
++        queryName: ''
++    };
 +};
 +
 +export const getFilters = (filterName: string, searchValue: string): string => {
 +    const filter = new FilterBuilder();
 +
 +    const pq = parseQuery(searchValue);
 +
 +    if (!pq.hasKeywords) {
 +        filter
 +            .addILike(filterName, searchValue, GroupContentsResourcePrefix.COLLECTION)
 +            .addILike(filterName, searchValue, GroupContentsResourcePrefix.PROCESS)
 +            .addILike(filterName, searchValue, GroupContentsResourcePrefix.PROJECT);
 +    } else {
 +
 +        if (pq.properties.type) {
 +            pq.values.forEach(v => {
 +                let prefix = '';
 +                switch (ResourceKind[pq.properties.type]) {
 +                    case ResourceKind.PROJECT:
 +                        prefix = GroupContentsResourcePrefix.PROJECT;
 +                        break;
 +                    case ResourceKind.COLLECTION:
 +                        prefix = GroupContentsResourcePrefix.COLLECTION;
 +                        break;
 +                    case ResourceKind.PROCESS:
 +                        prefix = GroupContentsResourcePrefix.PROCESS;
 +                        break;
 +                }
 +                if (prefix !== '') {
 +                    filter.addILike(filterName, v, prefix);
 +                }
 +            });
 +        } else {
 +            pq.values.forEach(v => {
 +                filter
 +                    .addILike(filterName, v, GroupContentsResourcePrefix.COLLECTION)
 +                    .addILike(filterName, v, GroupContentsResourcePrefix.PROCESS)
 +                    .addILike(filterName, v, GroupContentsResourcePrefix.PROJECT);
 +            });
 +        }
 +
 +        if (pq.properties.is && pq.properties.is === 'trashed') {
 +        }
 +
 +        if (pq.properties.project) {
 +            filter.addEqual('owner_uuid', pq.properties.project, GroupContentsResourcePrefix.PROJECT);
 +        }
 +
 +        if (pq.properties.from) {
 +            filter.addGte('modified_at', buildDateFilter(pq.properties.from));
 +        }
 +
 +        if (pq.properties.to) {
 +            filter.addLte('modified_at', buildDateFilter(pq.properties.to));
 +        }
 +        // filter
 +        //     .addIsA("uuid", buildUuidFilter(resourceKind))
 +        //     .addILike(filterName, searchValue, GroupContentsResourcePrefix.COLLECTION)
 +        //     .addILike(filterName, searchValue, GroupContentsResourcePrefix.PROCESS)
 +        //     .addILike(filterName, searchValue, GroupContentsResourcePrefix.PROJECT)
 +        //     .addLte('modified_at', buildDateFilter(dateTo))
 +        //     .addGte('modified_at', buildDateFilter(dateFrom))
 +        //     .addEqual('groupClass', GroupClass.PROJECT, GroupContentsResourcePrefix.PROJECT)
 +    }
 +
 +    return filter
          .addEqual('groupClass', GroupClass.PROJECT, GroupContentsResourcePrefix.PROJECT)
          .getFilters();
  };

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list