From 7f076e388d28861f4f50318d9b260b7a5a7bc26d Mon Sep 17 00:00:00 2001 From: Devon Anderson Date: Wed, 18 Dec 2024 16:14:30 -0500 Subject: [PATCH] Update handling of Ember Record Identifiers (#690) * use internal EmberId * Intial feature upgrade for Ember Internal Id * upgrade app to use yarn v4 * remove comments * fixed mdcodes dropdown --- .bowerrc | 4 - .gitignore | 3 + .nvmrc | 1 - .prettierignore | 28 + .prettierrc.js | 15 +- .yarnrc.yml | 1 + README.md | 8 +- app/adapters/application.js | 16 +- app/models/contact.js | 65 +- app/models/dictionary.js | 5 +- app/models/record.js | 5 +- .../components/control/md-modal/component.js | 5 +- .../components/input/md-textarea/component.js | 497 +- .../components/input/md-textarea/template.hbs | 53 +- app/pods/contact/new/id/route.js | 6 +- app/pods/dictionary/new/id/route.js | 6 +- app/pods/import/route.js | 445 +- app/pods/record/new/id/route.js | 28 +- app/services/data-mapper.js | 127 + app/services/schemas.js | 10 +- app/utils/fix-liability-typo.js | 18 + config/deprecation-workflow.js | 29 +- ember-cli-build.js | 40 +- package.json | 137 +- tests/helpers/start-app.js | 1 - yarn.lock | 36118 +++++++++------- 26 files changed, 21963 insertions(+), 15708 deletions(-) delete mode 100644 .bowerrc delete mode 100644 .nvmrc create mode 100644 .prettierignore create mode 100644 .yarnrc.yml create mode 100644 app/services/data-mapper.js create mode 100644 app/utils/fix-liability-typo.js diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index 959e1696e..000000000 --- a/.bowerrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "directory": "bower_components", - "analytics": false -} diff --git a/.gitignore b/.gitignore index 8b490aaa0..72c638a64 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ jsconfig.json /.node_modules.ember-try/ /bower.json.ember-try /package.json.ember-try +/mdeditor-test-fullset-20211206.json .DS_Store .vscode + +.yarn/* diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 93c432517..000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v12.22.12 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..416081d7f --- /dev/null +++ b/.prettierignore @@ -0,0 +1,28 @@ +# unconventional js +/blueprints/*/files/ +/vendor/ + +# compiled output +/dist/ +/tmp/ + +# dependencies +/bower_components/ +/node_modules/ + +# misc +/coverage/ +!.* +.eslintcache +.lint-todo/ + +# ember-try +/.node_modules.ember-try/ +/bower.json.ember-try +/npm-shrinkwrap.json.ember-try +/package.json.ember-try +/package-lock.json.ember-try +/yarn.lock.ember-try + + +.yarn/* diff --git a/.prettierrc.js b/.prettierrc.js index f1459024d..c3a786b0f 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,5 +1,14 @@ -"use strict"; +// prettier.config.js, .prettierrc.js, prettier.config.cjs, or .prettierrc.cjs -module.exports = { +/** + * @see https://prettier.io/docs/en/configuration.html + * @type {import("prettier").Config} + */ +const config = { + trailingComma: 'es5', + tabWidth: 2, + semi: true, singleQuote: true, -}; +} + +module.exports = config \ No newline at end of file diff --git a/.yarnrc.yml b/.yarnrc.yml new file mode 100644 index 000000000..3186f3f07 --- /dev/null +++ b/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/README.md b/README.md index 3665c7eed..cd8b0b838 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,14 @@ You will need the following things properly installed on your computer. - [Git][git] - [Node.js][node] - - Supported versions: `v16`. + - Supported versions: `v18`. - **Apple Silicon Users**: if you experience problems building or running try Node v14. + - We are now using Yarn V4. Here are the steps in setting it up. + - Make sure that you have Node Version 18 doesn't matter the minor semantic changes. + - Enable corepack by using the `corepack enable` command. + - Remove `node_modules` folder + - Run `yarn` to install packages again using Yarn V4. + - All other commands are the same. - [Yarn][yarn] installed globally - [Google Chrome][chrome] - [Firefox][firefox] diff --git a/app/adapters/application.js b/app/adapters/application.js index 4e86c629f..8a59c8745 100644 --- a/app/adapters/application.js +++ b/app/adapters/application.js @@ -1,4 +1,14 @@ -import Adapter -from 'ember-local-storage/adapters/adapter'; +import Adapter from 'ember-local-storage/adapters/adapter'; +import { v4 } from 'uuid'; -export default Adapter.extend({}); +export default Adapter.extend({ + generateIdForRecord(store, type, inputProperties) { + if (!inputProperties.uuid) { + let uuid = v4(); + let shortId = uuid.split('-')[0]; + inputProperties.uuid = uuid; + return shortId; + } + return inputProperties.uuid.split('-')[0]; + }, +}); diff --git a/app/models/contact.js b/app/models/contact.js index 146d24728..0f168e6d4 100644 --- a/app/models/contact.js +++ b/app/models/contact.js @@ -13,8 +13,6 @@ import EmberObject, { import { Copyable } from 'ember-copy' -import uuidV4 from 'uuid/v4'; -import Validator from 'validator'; import Model from 'mdeditor/models/base'; import { validator, @@ -37,7 +35,7 @@ const Validations = buildValidations({ message: "Name should not be only white-space." }), validator('presence', { - disabled: notEmpty('model.json.positionName'), + disabled: notEmpty('model.json.name'), presence: true }) ], @@ -49,7 +47,7 @@ const Validations = buildValidations({ message: "Position Name should not be only white-space." }), validator('presence', { - disabled: notEmpty('model.json.name'), + disabled: notEmpty('model.json.postiionName'), presence: true }) ], @@ -63,10 +61,10 @@ const JsonDefault = EmberObject.extend({ init() { this._super(...arguments); this.setProperties({ - 'contactId': uuidV4(), + 'contactId': null, 'isOrganization': false, 'name': null, - //'positionName': null, + 'positionName': null, 'memberOfOrganization': [], 'logoGraphic': [], 'phone': [], @@ -75,8 +73,6 @@ const JsonDefault = EmberObject.extend({ 'externalIdentifier': [], 'onlineResource': [], 'hoursOfService': [], - //'contactInstructions': null, - //'contactType': null; }); } }); @@ -149,37 +145,6 @@ const Contact = Model.extend(Validations, Copyable, { return json.name || (json.isOrganization ? null : json.positionName); }), - // /** - // * The formatted display string for the contact - // * - // * @property title - // * @type {String} - // * @readOnly - // * @category computed - // * @requires json.name, json.positionName - // */ - // updateMembers: Ember.observer('json.memberOfOrganization.[]', - // function () { - // //const me = this; - // const json = this.get('json'); - // const value = json.memberOfOrganization; - // - // let store = this.get('store'); - // let contacts = store.peekAll('contact'); - // let organizations = this.get('organizations') - // .clear(); - // - // value.forEach(function (id) { - // let rec = contacts.findBy('json.contactId', id); - // - // if(rec) { - // organizations.pushObject(rec); - // } - // //rec.get('contacts').pushObject(me); - // }); - // - // }), - /** * The type of contact * @@ -318,26 +283,6 @@ const Contact = Model.extend(Validations, Copyable, { return combinedName; }), - /** - * The trimmed varsion of the contactId. - * - * @property shortId - * @type {String} - * @readOnly - * @category computed - * @requires json.contactId - */ - shortId: computed('json.contactId', function () { - const contactId = this.get('json.contactId'); - if(contactId && Validator.isUUID(contactId)) { - let index = contactId.indexOf('-'); - - return contactId.substring(0, index); - } - - return contactId; - }), - /** * A list of schema errors return by the validator. * @@ -395,7 +340,7 @@ const Contact = Model.extend(Validations, Copyable, { isOrganization: isOrganization, name: name ? `Copy of ${name}` : null, positionName: name ? positionName : `Copy of ${positionName}`, - contactId: uuidV4() + contactId: null, }); return this.store.createRecord('contact', { diff --git a/app/models/dictionary.js b/app/models/dictionary.js index da7b386d3..38817008c 100644 --- a/app/models/dictionary.js +++ b/app/models/dictionary.js @@ -1,6 +1,5 @@ import { attr } from '@ember-data/model'; import { Copyable } from 'ember-copy' -import uuidV4 from "uuid/v4"; import { alias } from '@ember/object/computed'; import Model from 'mdeditor/models/base'; import { @@ -40,7 +39,7 @@ const JsonDefault = EmberObject.extend({ init() { this._super(...arguments); this.setProperties({ - dictionaryId: uuidV4(), + dictionaryId: null, dataDictionary: { citation: { title: null, @@ -138,7 +137,7 @@ export default Model.extend(Validations, Copyable, { let json = EmberObject.create(current); let name = current.dataDictionary.citation.title; json.set('dataDictionary.citation.title', `Copy of ${name}`); - json.set('dictionaryId', uuidV4()); + json.set('dictionaryId', null); return this.store.createRecord('dictionary', { json: json diff --git a/app/models/record.js b/app/models/record.js index 4e451ddd4..54ce3f8d3 100644 --- a/app/models/record.js +++ b/app/models/record.js @@ -3,7 +3,6 @@ import { alias } from '@ember/object/computed'; import { getOwner } from '@ember/application'; import EmberObject, { computed, getWithDefault } from '@ember/object'; import { Copyable } from 'ember-copy'; -import uuidV4 from "uuid/v4"; import Model from 'mdeditor/models/base'; import { validator, @@ -85,7 +84,7 @@ const Record = Model.extend(Validations, Copyable, { metadata: { metadataInfo: { metadataIdentifier: { - identifier: uuidV4(), + identifier: null, namespace: 'urn:uuid' }, metadataContact: [], @@ -250,7 +249,7 @@ const Record = Model.extend(Validations, Copyable, { json.set('metadata.resourceInfo.resourceType', getWithDefault(json, 'metadata.resourceInfo.resourceType', [{}])); json.set('metadata.metadataInfo.metadataIdentifier', { - identifier: uuidV4(), + identifier: null, namespace: 'urn:uuid' }); diff --git a/app/pods/components/control/md-modal/component.js b/app/pods/components/control/md-modal/component.js index e501641bf..409ec6bd0 100644 --- a/app/pods/components/control/md-modal/component.js +++ b/app/pods/components/control/md-modal/component.js @@ -91,7 +91,6 @@ export default Component.extend({ * @method cancel */ cancel() { - console.log('cancel') this.closeModal(); }, @@ -121,6 +120,6 @@ export default Component.extend({ */ cancel() { this.cancel(); - } - } + }, + }, }); diff --git a/app/pods/components/input/md-textarea/component.js b/app/pods/components/input/md-textarea/component.js index ac00609b1..536f9bdd0 100644 --- a/app/pods/components/input/md-textarea/component.js +++ b/app/pods/components/input/md-textarea/component.js @@ -3,245 +3,258 @@ * @submodule components-input */ - import Component from '@ember/component'; - import { computed, defineProperty } from '@ember/object'; - import { alias, not, notEmpty, and, or } from '@ember/object/computed'; - import { isBlank } from '@ember/utils'; - import { assert, debug } from '@ember/debug'; - - export default Component.extend({ - - /** - * Input, edit, display a multi-line, expandable, text area. - * - * @class md-textarea - * @constructor - */ - - init() { - this._super(...arguments); - - let model = this.model; - let valuePath = this.valuePath; - - if(isBlank(model) !== isBlank(valuePath)) { - assert( - `You must supply both model and valuePath to ${this.toString()} or neither.` - ); - } - - if(!isBlank(model)) { - if(this.get(`model.${valuePath}`) === undefined) { - debug( - `model.${valuePath} is undefined in ${this.toString()}.` - ); - - //Ember.run.once(()=>model.set(valuePath, "")); - } - - defineProperty(this, 'value', alias(`model.${valuePath}`)); - - defineProperty(this, 'validation', alias( - `model.validations.attrs.${valuePath}`) - .readOnly()); - - defineProperty(this, 'required', computed( - 'validation.options.presence{presence,disabled}', - 'disabled', - function () { - return !this.disabled && - this.get('validation.options.presence.presence') && - !this.get('validation.options.presence.disabled'); - }) - .readOnly()); - - defineProperty(this, 'notValidating', not( - 'validation.isValidating') - .readOnly()); - - defineProperty(this, 'hasContent', notEmpty('value') - .readOnly()); - - defineProperty(this, 'hasWarnings', notEmpty( - 'validation.warnings') - .readOnly()); - - defineProperty(this, 'isValid', and('hasContent', - 'validation.isTruelyValid') - .readOnly()); - - defineProperty(this, 'shouldDisplayValidations', or( - 'showValidations', 'didValidate', - 'hasContent') - .readOnly()); - - defineProperty(this, 'showErrorClass', and('notValidating', - 'showErrorMessage', - 'hasContent', 'validation') - .readOnly()); - - defineProperty(this, 'showErrorMessage', and( - 'shouldDisplayValidations', - 'validation.isInvalid') - .readOnly()); - - defineProperty(this, 'showWarningMessage', and( - 'shouldDisplayValidations', - 'hasWarnings', 'isValid') - .readOnly()); - } - }, - - attributeBindings: ['data-spy'], - classNames: ['md-textarea'], - classNameBindings: ['label:form-group', 'required', - 'embedded:md-embedded' - ], - - /** - * Initial value, returned value. - * - * @property value - * @type String - * @return String - * @required - */ - - /** - * Form label for textarea - * - * @property label - * @type String - * @default null - */ - label: null, - - /** - * The string to display when no option is selected. - * - * @property placeholder - * @type String - * @default 'Select one option' - */ - placeholder: "Select one option", - - /** - * Indicates whether the value is required - * - * @property required - * @type Boolean - * @default false - */ - required: false, - - /** - * Maximum number of characters allowed. - * If maxlength is not provided the number of characters will - * not be restricted. - * - * @property maxlength - * @type Number - * @default null - */ - maxlength: null, - - /** - * Enable auto-resizing of the textarea - * - * @property autoresize - * @type Boolean - * @default true - */ - autoresize: true, - - /** - * Toggle expand state - * - * @property isExpanded - * @type Boolean - * @default true - */ - isExpanded: true, - - /** - * Enable collapse of the textarea - * - * @property isCollapsible - * @type Boolean - * @default false - */ - isCollapsible: false, - /** - * Set the maximum width of the resizeable element in pixels. - * If maxwidth is not provided width will not be restricted. - * - * @property maxwidth - * @type Number - * @default null - */ - maxwidth: null, - - /** - * Set the maximum height of the resizable element in pixels. - * If maxheight is not provided height will not be restricted. - * - * @property maxheight - * @type {Number} - * @default null - */ - maxheight: null, - - /** - * Set the minimum number of rows for the element. - * Recommended for textareas. - * - * @property rows - * @type Number - * @default 2 - */ - rows: 2, - - /** - * Set the maximum number of rows for the element. - * Recommended for textareas. - * - * @property maxrows - * @type Number - * @default 10 - */ - maxrows: 10, - - /** - * Class to set on the textarea - * - * @property inputClass - * @type {string} - * @default 'form-control' - */ - inputClass: 'form-control', - - _didInsertArea() { - this.scheduleMeasurement(); - }, - - /** - * Whether to show the infotip - * - * @property infotip - * @type Boolean - * @default false - */ - infotip: false, - - /** - * Determines whether infotip is rendered - * - * @property showInfotip - * @type {Boolean} - * @default "false" - * @readOnly - * @category computed - * @requires placeholder,infotip - */ - showInfotip: and('placeholder', 'infotip') - }); +import Component from '@ember/component'; +import { computed, defineProperty } from '@ember/object'; +import { alias, not, notEmpty, and, or } from '@ember/object/computed'; +import { isBlank } from '@ember/utils'; +import { assert, debug } from '@ember/debug'; + +export default Component.extend({ + /** + * Input, edit, display a multi-line, expandable, text area. + * + * @class md-textarea + * @constructor + */ + + init() { + this._super(...arguments); + + let model = this.model; + let valuePath = this.valuePath; + + if (isBlank(model) !== isBlank(valuePath)) { + assert( + `You must supply both model and valuePath to ${this.toString()} or neither.` + ); + } + + if (!isBlank(model)) { + if (this.get(`model.${valuePath}`) === undefined) { + debug(`model.${valuePath} is undefined in ${this.toString()}.`); + + //Ember.run.once(()=>model.set(valuePath, "")); + } + + defineProperty(this, 'value', alias(`model.${valuePath}`)); + + defineProperty( + this, + 'validation', + alias(`model.validations.attrs.${valuePath}`).readOnly() + ); + + defineProperty( + this, + 'required', + computed( + 'validation.options.presence{presence,disabled}', + 'disabled', + function () { + return ( + !this.disabled && + this.get('validation.options.presence.presence') && + !this.get('validation.options.presence.disabled') + ); + } + ).readOnly() + ); + + defineProperty( + this, + 'notValidating', + not('validation.isValidating').readOnly() + ); + + defineProperty(this, 'hasContent', notEmpty('value').readOnly()); + + defineProperty( + this, + 'hasWarnings', + notEmpty('validation.warnings').readOnly() + ); + + defineProperty( + this, + 'isValid', + and('hasContent', 'validation.isTruelyValid').readOnly() + ); + + defineProperty( + this, + 'shouldDisplayValidations', + or('showValidations', 'didValidate', 'hasContent').readOnly() + ); + + defineProperty( + this, + 'showErrorClass', + and( + 'notValidating', + 'showErrorMessage', + 'hasContent', + 'validation' + ).readOnly() + ); + + defineProperty( + this, + 'showErrorMessage', + and('shouldDisplayValidations', 'validation.isInvalid').readOnly() + ); + + defineProperty( + this, + 'showWarningMessage', + and('shouldDisplayValidations', 'hasWarnings', 'isValid').readOnly() + ); + } + }, + + attributeBindings: ['data-spy'], + classNames: ['md-textarea'], + classNameBindings: ['label:form-group', 'required', 'embedded:md-embedded'], + + /** + * Initial value, returned value. + * + * @property value + * @type String + * @return String + * @required + */ + + /** + * Form label for textarea + * + * @property label + * @type String + * @default null + */ + label: null, + + /** + * The string to display when no option is selected. + * + * @property placeholder + * @type String + * @default 'Select one option' + */ + placeholder: 'Select one option', + + /** + * Indicates whether the value is required + * + * @property required + * @type Boolean + * @default false + */ + required: false, + + /** + * Maximum number of characters allowed. + * If maxlength is not provided the number of characters will + * not be restricted. + * + * @property maxlength + * @type Number + * @default null + */ + maxlength: null, + + /** + * Enable auto-resizing of the textarea + * + * @property autoresize + * @type Boolean + * @default true + */ + autoresize: true, + + /** + * Toggle expand state + * + * @property isExpanded + * @type Boolean + * @default true + */ + isExpanded: true, + + /** + * Enable collapse of the textarea + * + * @property isCollapsible + * @type Boolean + * @default false + */ + isCollapsible: false, + /** + * Set the maximum width of the resizeable element in pixels. + * If maxwidth is not provided width will not be restricted. + * + * @property maxwidth + * @type Number + * @default null + */ + maxwidth: null, + + /** + * Set the maximum height of the resizable element in pixels. + * If maxheight is not provided height will not be restricted. + * + * @property maxheight + * @type {Number} + * @default null + */ + maxheight: null, + + /** + * Set the minimum number of rows for the element. + * Recommended for textareas. + * + * @property rows + * @type Number + * @default 2 + */ + rows: 2, + + /** + * Set the maximum number of rows for the element. + * Recommended for textareas. + * + * @property maxrows + * @type Number + * @default 10 + */ + maxrows: 10, + + /** + * Class to set on the textarea + * + * @property inputClass + * @type {string} + * @default 'form-control' + */ + inputClass: 'form-control', + + /** + * Whether to show the infotip + * + * @property infotip + * @type Boolean + * @default false + */ + infotip: false, + + /** + * Determines whether infotip is rendered + * + * @property showInfotip + * @type {Boolean} + * @default "false" + * @readOnly + * @category computed + * @requires placeholder,infotip + */ + showInfotip: and('placeholder', 'infotip'), +}); diff --git a/app/pods/components/input/md-textarea/template.hbs b/app/pods/components/input/md-textarea/template.hbs index e5d304fed..fe502f77d 100644 --- a/app/pods/components/input/md-textarea/template.hbs +++ b/app/pods/components/input/md-textarea/template.hbs @@ -1,7 +1,7 @@ {{#if label}} {{#if isCollapsible}} -