From 5e3bc7aadd265bf300ab77c98b5dafe54dc58533 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 25 Jun 2020 09:40:26 -0400 Subject: [PATCH 1/7] =?UTF-8?q?chore:=20=F0=9F=A4=96=20use=20displayName?= =?UTF-8?q?=20on=20roles=20index?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/core/app/templates/orgs/org/roles/index.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/core/app/templates/orgs/org/roles/index.hbs b/ui/core/app/templates/orgs/org/roles/index.hbs index 498aecac5..07e3acfaa 100644 --- a/ui/core/app/templates/orgs/org/roles/index.hbs +++ b/ui/core/app/templates/orgs/org/roles/index.hbs @@ -33,7 +33,7 @@ @route="orgs.org.roles.role" @model={{role}} > - {{role.name}} + {{role.displayName}} {{role.description}} From de8d9124108ee5768559d2ea3165af19dead4adf Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 25 Jun 2020 14:13:52 -0400 Subject: [PATCH 2/7] =?UTF-8?q?fix:=20=F0=9F=90=9B=20prenormalize=20findAl?= =?UTF-8?q?l=20responses=20in=20application=20adapter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ember Data fetch-manager will throw an error if an array resposne is an empty object before it reaches the serializer. Thus we need to intercept the response in the adapter and "prenormalize" it to contain an empty items array `{items: []}`. --- addons/api/addon/adapters/application.js | 51 +++++++++++++++++++ addons/api/package.json | 1 + addons/api/tests/dummy/mirage/config.js | 26 ++++++++++ .../tests/dummy/mirage/scenarios/default.js | 9 ++++ .../dummy/mirage/serializers/application.js | 4 ++ .../tests/unit/adapters/application-test.js | 14 +++++ yarn.lock | 15 ++++++ 7 files changed, 120 insertions(+) create mode 100644 addons/api/tests/dummy/mirage/config.js create mode 100644 addons/api/tests/dummy/mirage/scenarios/default.js create mode 100644 addons/api/tests/dummy/mirage/serializers/application.js diff --git a/addons/api/addon/adapters/application.js b/addons/api/addon/adapters/application.js index cef50d39e..06949503e 100644 --- a/addons/api/addon/adapters/application.js +++ b/addons/api/addon/adapters/application.js @@ -6,6 +6,37 @@ import { dasherize } from '@ember/string'; import { pluralize } from 'ember-inflector'; import { isArray } from '@ember/array'; +/** + * Returns false if the payload is an empty object, true otherwise. + * Taken from Ember Data fetch-manager. + * @param {object} adapterPayload + * @return {boolean} + */ +function payloadIsNotBlank(adapterPayload) { + if (Array.isArray(adapterPayload)) { + return true; + } else { + return Object.keys(adapterPayload || {}).length !== 0; + } +} + +/** + * If the resonse is not empty, returns the response. Otherwise, returns + * a new payload containing an empty `items` array, as expected by + * the serializer. + * + * Normally this would be performed 100% inside the serializer. + * However, the fetch manager, which we cannot easily override, glues the + * adapter and serializers together. Before it forwards a response from the + * adapter on to the serializer, it checks for an "empty" response. If the + * response is empty, fetch manager throws and error and never forwards it on. + * @param {object} response + * @return {object} + */ +function prenormalizeArrayResponse(response) { + return payloadIsNotBlank(response) ? response : {items: []}; +} + export default class ApplicationAdapter extends RESTAdapter { // =attributes @@ -36,6 +67,26 @@ export default class ApplicationAdapter extends RESTAdapter { return dasherize(pluralize(type)); } + /** + * Intercepts "empty" responses and adds an empty `items` array. + * @override + * @method findAll + * @return {Promise} promise + */ + findAll() { + return super.findAll(...arguments).then(prenormalizeArrayResponse); + } + + /** + * Intercepts "empty" responses and adds an empty `items` array. + * @override + * @method query + * @return {Promise} promise + */ + query() { + return super.query(...arguments).then(prenormalizeArrayResponse); + } + /** * Overrides default ajax method by rewritting PUT requests as PATCH. * PATCH is the request method used by our API for updates. diff --git a/addons/api/package.json b/addons/api/package.json index 151c4959b..f9a6af815 100644 --- a/addons/api/package.json +++ b/addons/api/package.json @@ -35,6 +35,7 @@ "ember-cli-dependency-checker": "^3.2.0", "ember-cli-eslint": "^5.1.0", "ember-cli-inject-live-reload": "^2.0.2", + "ember-cli-mirage": "^1.1.7", "ember-cli-sri": "^2.1.1", "ember-cli-template-lint": "^1.0.0-beta.3", "ember-cli-uglify": "^3.0.0", diff --git a/addons/api/tests/dummy/mirage/config.js b/addons/api/tests/dummy/mirage/config.js new file mode 100644 index 000000000..c2cd26a9d --- /dev/null +++ b/addons/api/tests/dummy/mirage/config.js @@ -0,0 +1,26 @@ +export default function() { + + // These comments are here to help you get started. Feel free to delete them. + + /* + Config (with defaults). + + Note: these only affect routes defined *after* them! + */ + + // this.urlPrefix = ''; // make this `http://localhost:8080`, for example, if your API is on a different server + // this.namespace = ''; // make this `/api`, for example, if your API is namespaced + // this.timing = 400; // delay for each request, automatically set to 0 during testing + + /* + Shorthand cheatsheet: + + this.get('/posts'); + this.post('/posts'); + this.get('/posts/:id'); + this.put('/posts/:id'); // or this.patch + this.del('/posts/:id'); + + https://www.ember-cli-mirage.com/docs/route-handlers/shorthands + */ +} diff --git a/addons/api/tests/dummy/mirage/scenarios/default.js b/addons/api/tests/dummy/mirage/scenarios/default.js new file mode 100644 index 000000000..adb3af4c0 --- /dev/null +++ b/addons/api/tests/dummy/mirage/scenarios/default.js @@ -0,0 +1,9 @@ +export default function(/* server */) { + + /* + Seed your development database using your factories. + This data will not be loaded in your tests. + */ + + // server.createList('post', 10); +} diff --git a/addons/api/tests/dummy/mirage/serializers/application.js b/addons/api/tests/dummy/mirage/serializers/application.js new file mode 100644 index 000000000..6d47a3669 --- /dev/null +++ b/addons/api/tests/dummy/mirage/serializers/application.js @@ -0,0 +1,4 @@ +import { JSONAPISerializer } from 'ember-cli-mirage'; + +export default JSONAPISerializer.extend({ +}); diff --git a/addons/api/tests/unit/adapters/application-test.js b/addons/api/tests/unit/adapters/application-test.js index 8c58bafec..366c44c4e 100644 --- a/addons/api/tests/unit/adapters/application-test.js +++ b/addons/api/tests/unit/adapters/application-test.js @@ -3,9 +3,12 @@ import { setupTest } from 'ember-qunit'; import config from 'ember-get-config'; import RESTAdapter from '@ember-data/adapter/rest'; import { InvalidError } from '@ember-data/adapter/error'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +import { Response } from 'miragejs'; module('Unit | Adapter | application', function (hooks) { setupTest(hooks); + setupMirage(hooks); test('its namespace is equal to the configured namespace', function (assert) { assert.expect(2); @@ -24,12 +27,23 @@ module('Unit | Adapter | application', function (hooks) { assert.expect(1); const adapter = this.owner.lookup('adapter:application'); // TODO this is icky, should be changed to a spy or stub + const originalAjax = RESTAdapter.prototype.ajax; RESTAdapter.prototype.ajax = (url, type) => { assert.equal(type, 'PATCH'); + RESTAdapter.prototype.ajax = originalAjax; }; adapter.ajax('/', 'PUT'); }); + test('it prenormalizes "empty" responses into a form that the fetch-manager will not reject', async function (assert) { + assert.expect(1); + const adapter = this.owner.lookup('adapter:project'); + const store = this.owner.lookup('service:store'); + this.server.get('/v1/projects', () => new Response({})); + const prenormalized = await adapter.findAll(store, {modelName: 'project'}, null, []); + assert.deepEqual(prenormalized, {items: []}); + }); + test('it correctly identifies 400 responses as invalid', function (assert) { assert.expect(2); const adapter = this.owner.lookup('adapter:application'); diff --git a/yarn.lock b/yarn.lock index 90f435da4..214eb95d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7330,6 +7330,21 @@ ember-cli-mirage@^1.1.6: lodash-es "^4.17.11" miragejs "^0.1.31" +ember-cli-mirage@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/ember-cli-mirage/-/ember-cli-mirage-1.1.7.tgz#846ec8e5199b15fa670da30dfa1708a8ee11e9dc" + integrity sha512-4kVLXXvgHYlv30ChM47U4xYnUtphIoEj+BQwXX0QT7pvD3KQxYnmfZSwlevSEVUy2UhbsBUPw6merENb+dIQ0A== + dependencies: + broccoli-file-creator "^2.1.1" + broccoli-funnel "^3.0.2" + broccoli-merge-trees "^4.2.0" + ember-auto-import "^1.2.19" + ember-cli-babel "^7.5.0" + ember-get-config "^0.2.2" + ember-inflector "^2.0.0 || ^3.0.0" + lodash-es "^4.17.11" + miragejs "^0.1.31" + ember-cli-normalize-entity-name@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" From dbe07cf235ea11e2b1c343215fb837bea5c47b7f Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Thu, 25 Jun 2020 16:17:46 -0400 Subject: [PATCH 3/7] =?UTF-8?q?chore:=20=F0=9F=A4=96=20postivize=20the=20n?= =?UTF-8?q?ame=20of=20payloadIsNotBlank=20to=20...isBlank?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/api/addon/adapters/application.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/addons/api/addon/adapters/application.js b/addons/api/addon/adapters/application.js index 06949503e..182fa3493 100644 --- a/addons/api/addon/adapters/application.js +++ b/addons/api/addon/adapters/application.js @@ -7,23 +7,22 @@ import { pluralize } from 'ember-inflector'; import { isArray } from '@ember/array'; /** - * Returns false if the payload is an empty object, true otherwise. - * Taken from Ember Data fetch-manager. + * Returns true if the payload is an empty object, false otherwise. + * Taken from Ember Data fetch-manager and "positivized" the name. * @param {object} adapterPayload * @return {boolean} */ -function payloadIsNotBlank(adapterPayload) { +function payloadIsBlank(adapterPayload) { if (Array.isArray(adapterPayload)) { - return true; + return false; } else { - return Object.keys(adapterPayload || {}).length !== 0; + return Object.keys(adapterPayload || {}).length === 0; } } /** - * If the resonse is not empty, returns the response. Otherwise, returns - * a new payload containing an empty `items` array, as expected by - * the serializer. + * If the resonse is empty, returns a new payload containing an empty `items` + * array, as expected by the serializer. Otherwise, returns the response. * * Normally this would be performed 100% inside the serializer. * However, the fetch manager, which we cannot easily override, glues the @@ -34,7 +33,7 @@ function payloadIsNotBlank(adapterPayload) { * @return {object} */ function prenormalizeArrayResponse(response) { - return payloadIsNotBlank(response) ? response : {items: []}; + return payloadIsBlank(response) ? {items: []} : response; } export default class ApplicationAdapter extends RESTAdapter { From 22fcdfc49aa6b29f75207b57c1ba677e1df9c419 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Fri, 26 Jun 2020 11:49:38 -0400 Subject: [PATCH 4/7] chore: add containerized build and readme instructions --- README.md | 12 ++++++++++++ docker-compose.yml | 25 +++++++++++++++++++++++++ package.json | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 docker-compose.yml diff --git a/README.md b/README.md index 4c200c5e6..3661b3f98 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ subproject, e.g. running or testing. - [Branching](#branching) - [Building ToC](#building-toc) - [Building Core UI for Production](#building-core-ui-for-production) + - [Building with a Container](#building-with-a-container) - [Committing](#committing) - [License Checking](#license-checking) @@ -116,6 +117,17 @@ yarn build:production:core Assets are saved to `ui/core/dist/`. +#### Building with a Container + +Optionally, you may build the UI within a container. Execute the +following command: + +```bash +docker-compose run build_production +``` + +Assets are saved to `ui/core/dist/`. + ### Committing Instead of the default `git commit`, we prescribe a custom command that ensures diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..7e97b3e0d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3.8' + +services: + node: &node + image: node:12 + volumes: + - './:/src' + - 'icu_node_modules:/src/node_modules' + - 'icu_addon_api_node_modules:/src/addon/api/node_modules' + - 'icu_addon_auth_node_modules:/src/addon/auth/node_modules' + - 'icu_addon_rose_node_modules:/src/addon/rose/node_modules' + - 'icu_ui_core_node_modules:/src/ui/core/node_modules' + working_dir: /src + + build_production: + <<: *node + entrypoint: bash + command: '-c "yarn install && yarn build:production:ui:core"' + +volumes: + icu_node_modules: + icu_addon_api_node_modules: + icu_addon_auth_node_modules: + icu_addon_rose_node_modules: + icu_ui_core_node_modules: diff --git a/package.json b/package.json index 17d23d120..8e18bfe44 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "ui/*" ], "scripts": { - "build:production:core": "cd ui/core && yarn build:production", + "build:production:ui:core": "cd ui/core && yarn build:production", "lint": "yarn lint:addons:api && yarn lint:addons:auth && yarn lint:addons:rose && yarn lint:ui:core", "lint:addons:api": "echo \"\n\nlint: addons/api\n\" && cd addons/api && yarn lint", "lint:addons:auth": "echo \"\n\nlint: addons/auth\n\" && cd addons/auth && yarn lint", From ef8a5d859ba7e61dca6fbd8827f0c0ea8331e9f3 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Fri, 26 Jun 2020 11:52:29 -0400 Subject: [PATCH 5/7] docs: fix error in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3661b3f98..ea2dd6027 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ To quickly produce a production build of Core UI, run from this folder: ```bash yarn install -yarn build:production:core +yarn build:production:ui:core ``` Assets are saved to `ui/core/dist/`. From 70abc17fff36cba6516c29916cca1b49e99a1cb0 Mon Sep 17 00:00:00 2001 From: Randall Morey Date: Fri, 26 Jun 2020 14:15:43 -0400 Subject: [PATCH 6/7] chore: add build script to handle post-build cleanup --- README.md | 2 +- build_production.sh | 4 ++++ docker-compose.yml | 12 ++++++------ 3 files changed, 11 insertions(+), 7 deletions(-) create mode 100755 build_production.sh diff --git a/README.md b/README.md index ea2dd6027..e3951ba65 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Optionally, you may build the UI within a container. Execute the following command: ```bash -docker-compose run build_production +./build_production.sh ``` Assets are saved to `ui/core/dist/`. diff --git a/build_production.sh b/build_production.sh new file mode 100755 index 000000000..b49e79ce4 --- /dev/null +++ b/build_production.sh @@ -0,0 +1,4 @@ +# /#!/bin/sh + +docker-compose run build_production; +chmod -R 777 ./; diff --git a/docker-compose.yml b/docker-compose.yml index 7e97b3e0d..9bd11664b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,9 +6,9 @@ services: volumes: - './:/src' - 'icu_node_modules:/src/node_modules' - - 'icu_addon_api_node_modules:/src/addon/api/node_modules' - - 'icu_addon_auth_node_modules:/src/addon/auth/node_modules' - - 'icu_addon_rose_node_modules:/src/addon/rose/node_modules' + - 'icu_addons_api_node_modules:/src/addons/api/node_modules' + - 'icu_addons_auth_node_modules:/src/addons/auth/node_modules' + - 'icu_addons_rose_node_modules:/src/addons/rose/node_modules' - 'icu_ui_core_node_modules:/src/ui/core/node_modules' working_dir: /src @@ -19,7 +19,7 @@ services: volumes: icu_node_modules: - icu_addon_api_node_modules: - icu_addon_auth_node_modules: - icu_addon_rose_node_modules: + icu_addons_api_node_modules: + icu_addons_auth_node_modules: + icu_addons_rose_node_modules: icu_ui_core_node_modules: From c9cfa63313f742c373afbc4bd0f136d80fb4c0df Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 26 Jun 2020 14:35:51 -0500 Subject: [PATCH 7/7] Fix up perms --- build_production.sh | 4 ---- docker-compose.yml => docker-compose-embedding.yml | 6 +++++- 2 files changed, 5 insertions(+), 5 deletions(-) delete mode 100755 build_production.sh rename docker-compose.yml => docker-compose-embedding.yml (70%) diff --git a/build_production.sh b/build_production.sh deleted file mode 100755 index b49e79ce4..000000000 --- a/build_production.sh +++ /dev/null @@ -1,4 +0,0 @@ -# /#!/bin/sh - -docker-compose run build_production; -chmod -R 777 ./; diff --git a/docker-compose.yml b/docker-compose-embedding.yml similarity index 70% rename from docker-compose.yml rename to docker-compose-embedding.yml index 9bd11664b..1cd3d329b 100644 --- a/docker-compose.yml +++ b/docker-compose-embedding.yml @@ -1,3 +1,7 @@ +# Note: this will change the permissions of the files in this directory after +# running to allow for easy deletion, so this should only be run as part of +# watchtower's build task. + version: '3.8' services: @@ -15,7 +19,7 @@ services: build_production: <<: *node entrypoint: bash - command: '-c "yarn install && yarn build:production:ui:core"' + command: '-c "yarn install && yarn build:production:ui:core && chmod -R 777 ."' volumes: icu_node_modules: