UNPKG

d2-ui

Version:
1,359 lines (1,108 loc) 195 kB
var d2 = (function () {var d2 = /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ((function(modules) { // Check all modules for deduplicated modules for(var i in modules) { if(Object.prototype.hasOwnProperty.call(modules, i)) { switch(typeof modules[i]) { case "function": break; case "object": // Module can be created from a template modules[i] = (function(_m) { var args = _m.slice(1), fn = modules[_m[0]]; return function (a,b,c) { fn.apply(this, [a,b,c].concat(args)); }; }(modules[i])); break; default: // Module is a copy of another module modules[i] = modules[modules[i]]; break; } } } return modules; }([ /* 0 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); exports.getManifest = getManifest; exports.getUserSettings = getUserSettings; exports.init = init; exports.getInstance = getInstance; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } } var _libUtils = __webpack_require__(1); var _loggerLogger = __webpack_require__(2); var _loggerLogger2 = _interopRequireDefault(_loggerLogger); var _modelModels = __webpack_require__(4); var _modelModels2 = _interopRequireDefault(_modelModels); var _apiApi = __webpack_require__(7); var _apiApi2 = _interopRequireDefault(_apiApi); var _systemSystem = __webpack_require__(9); var _systemSystem2 = _interopRequireDefault(_systemSystem); var _i18nI18n = __webpack_require__(30); var _i18nI18n2 = _interopRequireDefault(_i18nI18n); var _config = __webpack_require__(31); var _config2 = _interopRequireDefault(_config); var _currentUserCurrentUser = __webpack_require__(33); var _currentUserCurrentUser2 = _interopRequireDefault(_currentUserCurrentUser); __webpack_require__(12); var firstRun = true; var deferredD2Init = _libUtils.Deferred.create(); var preInitConfig = _config2['default'].create(); function getManifest(url) { var api = new _apiApi2['default'](); api.setBaseUrl(''); var manifestUtilities = { getBaseUrl: function getBaseUrl() { return this.activities.dhis.href; } }; return api.get('' + url).then(function (manifest) { return Object.assign({}, manifest, manifestUtilities); }); } /** * @function getUserSettings * * @returns {Promise} A promise to the current user settings * * @description * The object that is the result of the promise will have the following properties * ```js * { * "uiLocale": "en" // The users locale, that can be used for translations) * } * ``` */ function getUserSettings() { var api = _apiApi2['default'].getApi(); if (preInitConfig.baseUrl && firstRun) { api.setBaseUrl(preInitConfig.baseUrl); } return api.get('userSettings'); } function getModelRequests(api) { var schemaNames = arguments.length <= 1 || arguments[1] === undefined ? [] : arguments[1]; var fieldsForSchemas = ['apiEndpoint,name,authorities,singular,plural,shareable,metadata,klass,identifiableObject,properties[href', 'writable,collection,collectionName,name,propertyType,persisted,required,min,max,ordered,unique,constants', 'owner,itemPropertyType]'].join(','); var modelRequests = []; var loadSchemaForName = function loadSchemaForName(schemaName) { return api.get('schemas/' + schemaName, { fields: fieldsForSchemas }); }; if (schemaNames.length > 0) { var individualSchemaRequests = schemaNames.map(loadSchemaForName); var schemasPromise = Promise.all(individualSchemaRequests).then(function (schemas) { return { schemas: schemas }; }); modelRequests.push(schemasPromise); } else { // Used as a source to generate the models. modelRequests.push(api.get('schemas', { fields: fieldsForSchemas })); } // Used to add the dynamic attributes to the models that should have them. modelRequests.push(api.get('attributes', { fields: ':all,optionSet[:all,options[:all]]', paging: false })); return modelRequests; } /** * @function init * * @param {Object} initConfig Configuration object that will be used to configure to define D2 Setting. * See the description for more information on the available settings. * @returns {Promise} A promise that resolves with the intialized d2 object. Which is an object that exposes `model`, `models` and `Api` * * @description * Init function that used to initialise D2. This will load the schemas from the DHIS2 api and configure your D2 instance. * * The `config` object that can be passed into D2 can have the following properties: * * baseUrl: Set this when the url is something different then `/api`. If you are running your dhis instance in a subdirectory of the actual domain * for example http://localhost/dhis/ you should set the base url to `/dhis/api` * * ```js * import init from 'd2'; * * init({baseUrl: '/dhis/api'}) * .then((d2) => { * console.log(d2.model.dataElement.list()); * }); * ``` */ function init(initConfig) { var api = _apiApi2['default'].getApi(); var logger = _loggerLogger2['default'].getLogger(); var config = _config2['default'].create(preInitConfig, initConfig); var d2 = { models: undefined, model: _modelModels2['default'], Api: _apiApi2['default'], system: _systemSystem2['default'].getSystem(), i18n: _i18nI18n2['default'].getI18n() }; // Process the config in a the config class to keep all config calls together. _config2['default'].processConfigForD2(config, d2); // Because when importing the getInstance method in dependencies the getInstance could run before // init we have to resolve the current promise on first run and for consecutive ones replace the // old one with a fresh promise. if (firstRun) { firstRun = false; } else { deferredD2Init = _libUtils.Deferred.create(); } var modelRequests = getModelRequests(api, config.schemas); var userRequests = [api.get('me', { fields: ':all,organisationUnits[id],userGroups[id],userCredentials[:all,!user,userRoles[id]' }), api.get('me/authorization'), getUserSettings()]; var systemRequests = [api.get('system/info'), api.get('apps')]; return Promise.all([].concat(_toConsumableArray(modelRequests), userRequests, systemRequests, [d2.i18n.load()])).then(function (res) { var responses = { schemas: (0, _libUtils.pick)('schemas')(res[0]), attributes: (0, _libUtils.pick)('attributes')(res[1]), currentUser: res[2], authorities: res[3], userSettings: res[4], systemInfo: res[5], apps: res[6] }; responses.schemas // TODO: Remove this when the schemas endpoint is versioned or shows the correct urls for the requested version // The schemas endpoint is not versioned which will result into the modelDefinitions always using the // "default" endpoint, we therefore modify the endpoint url based on the given baseUrl. .map(function (schema) { schema.apiEndpoint = (0, _libUtils.updateAPIUrlWithBaseUrlVersionNumber)(schema.apiEndpoint, config.baseUrl); // eslint-disable-line no-param-reassign return schema; }).forEach(function (schema) { // Attributes that do not have values do not by default get returned with the data, // therefore we need to grab the attributes that are attached to this particular schema to be able to know about them var schemaAttributes = responses.attributes.filter(function (attributeDescriptor) { var attributeNameFilter = [schema.singular, 'Attribute'].join(''); return attributeDescriptor[attributeNameFilter] === true; }); if (!Object.prototype.hasOwnProperty.call(d2.models, schema.singular)) { d2.models.add(_modelModels2['default'].ModelDefinition.createFromSchema(schema, schemaAttributes)); } }); d2.currentUser = _currentUserCurrentUser2['default'].create(responses.currentUser, responses.authorities, d2.models, responses.userSettings); d2.system.setSystemInfo(responses.systemInfo); d2.system.setInstalledApps(responses.apps); deferredD2Init.resolve(d2); return deferredD2Init.promise; })['catch'](function (error) { logger.error('Unable to get schemas from the api', JSON.stringify(error), error); deferredD2Init.reject('Unable to get schemas from the DHIS2 API'); return deferredD2Init.promise; }); } /** * @function getInstance * * @returns {Promise} A promise to an initialized d2 instance. * * @description * This function can be used to retrieve the `singleton` instance of d2. The instance is being created by calling * the `init` method. * * ```js * import {init, getInstance} from 'd2'; * * init({baseUrl: '/dhis2/api/'}); * getInstance() * .then(d2 => { * d2.models.dataElement.list(); * // and all your other d2 magic. * }); * ``` */ function getInstance() { return deferredD2Init.promise; } // Alias preInitConfig to be able to `import {config} from 'd2';` /** * @property config * * @description * Can be used to set config options before initialisation of d2. * * ```js * import {config, init} from 'd2'; * * config.baseUrl = '/demo/api'; * config.i18n.sources.add('i18n/systemsettingstranslations.properties'); * * init() * .then(d2 => { * d2.system.settings.all() * .then(systemSettings => Object.keys()) * .then(systemSettingsKey => { * d2.i18n.getTranslation(systemSettingsKey); * }); * }); * * ``` */ var config = preInitConfig; exports.config = config; exports['default'] = { init: init, config: config, getInstance: getInstance, getUserSettings: getUserSettings, getManifest: getManifest }; /***/ }, /* 1 */ /***/ function(module, exports) { // TODO: Most of these functions should be moved out to d2-utilizr 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); exports.throwError = throwError; exports.curry = curry; exports.addLockedProperty = addLockedProperty; exports.copyOwnProperties = copyOwnProperties; exports.pick = pick; exports.updateAPIUrlWithBaseUrlVersionNumber = updateAPIUrlWithBaseUrlVersionNumber; exports.customEncodeURIComponent = customEncodeURIComponent; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } function throwError(message) { throw new Error(message); } // TODO: Throw an error when `toCurry` is not a function function curry(toCurry, parameter) { return function curried() { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return toCurry.apply(this, [parameter].concat(args)); }; } function addLockedProperty(object, name, value) { var propertyDescriptor = { enumerable: true, configurable: false, writable: false, value: value }; Object.defineProperty(object, name, propertyDescriptor); } function copyOwnProperties(to, from) { var key = undefined; for (key in from) { if (from.hasOwnProperty(key)) { to[key] = from[key]; // eslint-disable-line no-param-reassign } } return to; } function pick(property) { return function (item) { if (item) { return item[property]; } return undefined; }; } var Deferred = (function () { function Deferred() { var _this = this; _classCallCheck(this, Deferred); this.promise = new Promise(function (resolve, reject) { _this.resolve = resolve; _this.reject = reject; }); } _createClass(Deferred, null, [{ key: 'create', value: function create() { return new Deferred(); } }]); return Deferred; })(); exports.Deferred = Deferred; function updateAPIUrlWithBaseUrlVersionNumber(apiUrl, baseUrl) { if (!baseUrl || !apiUrl) { return apiUrl; } var apiUrlWithVersionRexExp = /api\/(2[3-9])/; var apiVersionMatch = baseUrl.match(apiUrlWithVersionRexExp); var baseUrlHasVersion = apiVersionMatch && apiVersionMatch[1]; var apiUrlHasVersion = apiUrl && !apiUrlWithVersionRexExp.test(apiUrl); if (baseUrlHasVersion && apiUrlHasVersion) { var version = apiVersionMatch[1]; // Inject the current api version number into the endPoint urls return apiUrl.replace(/api/, 'api/' + version); } return apiUrl; } // Define our very own special list of characters that we don't want to encode in the URI var whitelistURI = ',&$=/;:'; var whitelistURICodes = whitelistURI.split('').map(function (c) { return encodeURIComponent(c); }); var whitelistRegExp = new RegExp('(?:' + whitelistURICodes.join('|') + ')', 'g'); /** * Encode all invalid URI characters, except the ones we've decided we don't want to */ function customEncodeURIComponent(uri) { // return uri; return encodeURIComponent(uri).replace(whitelistRegExp, decodeURIComponent); } /***/ }, /* 2 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var _libCheck = __webpack_require__(3); var Logger = (function () { function Logger(logging) { _classCallCheck(this, Logger); (0, _libCheck.checkType)(logging, 'object', 'console'); this.logger = logging; } _createClass(Logger, [{ key: 'canLog', value: function canLog(type) { return !!(type && console && (0, _libCheck.isType)(this.logger[type], 'function')); } }, { key: 'debug', value: function debug() { if (this.canLog('debug')) { for (var _len = arguments.length, rest = Array(_len), _key = 0; _key < _len; _key++) { rest[_key] = arguments[_key]; } this.logger.debug.apply(console, rest); return true; } return false; } }, { key: 'error', value: function error() { if (this.canLog('error')) { for (var _len2 = arguments.length, rest = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { rest[_key2] = arguments[_key2]; } this.logger.error.apply(console, rest); return true; } return false; } }, { key: 'log', value: function log() { if (this.canLog('log')) { for (var _len3 = arguments.length, rest = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { rest[_key3] = arguments[_key3]; } this.logger.log.apply(console, rest); return true; } return false; } }, { key: 'warn', value: function warn() { if (this.canLog('warn')) { for (var _len4 = arguments.length, rest = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { rest[_key4] = arguments[_key4]; } this.logger.warn.apply(console, rest); return true; } return false; } }], [{ key: 'getLogger', value: function getLogger() { var logger = undefined; // TODO: This is not very clean try to figure out a better way to do this. try { // Node version logger = global.console; } catch (e) { // Browser version fallback /* istanbul ignore next */ logger = window.console; } if (this.logger) { return this.logger; } return this.logger = new Logger(logger); } }]); return Logger; })(); exports['default'] = Logger; module.exports = exports['default']; /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }, /* 3 */ /***/ function(module, exports) { 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); exports.checkDefined = checkDefined; exports.checkType = checkType; exports.isType = isType; exports.isString = isString; exports.isArray = isArray; exports.isObject = isObject; exports.isDefined = isDefined; exports.isInteger = isInteger; exports.isNumeric = isNumeric; exports.contains = contains; exports.isValidUid = isValidUid; function checkDefined(value, name) { if (value !== undefined) { return true; } throw new Error([name || 'Value', 'should be provided'].join(' ')); } // TODO: Decide if checkType([], 'object') is a 'false' positive function checkType(value, type, name) { checkDefined(value, name); checkDefined(type, 'Type'); if (typeof type === 'function' && value instanceof type || typeof type === 'string' && typeof value === type) { return true; } throw new Error(['Expected', name || value, 'to have type', type].join(' ')); } // TODO: Log type error? function isType(value, type) { function noop() {} try { checkType(value, type); return true; } catch (e) { noop(); } return false; } function isString(value) { return isType(value, 'string'); } function isArray(value) { return Array.isArray(value); } function isObject(value) { return isType(value, Object); } function isDefined(value) { return value !== undefined; } function isInteger(nVal) { return typeof nVal === 'number' && isFinite(nVal) && nVal > -9007199254740992 && nVal < 9007199254740992 && Math.floor(nVal) === nVal; } // Polyfill for the isInteger function that will be added in ES6 // http://wiki.ecmascript.org/doku.php?id=harmony:number.isinteger /* istanbul ignore if */ if (!Number.isInteger) { Number.isInteger = isInteger; } function isNumeric(nVal) { return typeof nVal === 'number' && isFinite(nVal) && nVal - parseFloat(nVal) + 1 >= 0; } function contains(item, list) { var listToCheck = isArray(list) && list || []; return listToCheck.indexOf(item) >= 0; } function isValidUid(value) { return value && value.length === 11; } exports['default'] = { checkType: checkType, checkDefined: checkDefined, isArray: isArray, isDefined: isDefined, isInteger: isInteger, isNumeric: isNumeric, isString: isString, isType: isType, contains: contains, isValidUid: isValidUid }; /***/ }, /* 4 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } var _ModelBase = __webpack_require__(5); var _ModelBase2 = _interopRequireDefault(_ModelBase); var _Model = __webpack_require__(14); var _Model2 = _interopRequireDefault(_Model); var _ModelDefinition = __webpack_require__(15); var _ModelDefinition2 = _interopRequireDefault(_ModelDefinition); var _ModelDefinitions = __webpack_require__(16); var _ModelDefinitions2 = _interopRequireDefault(_ModelDefinitions); var _ModelValidation = __webpack_require__(6); var _ModelValidation2 = _interopRequireDefault(_ModelValidation); exports['default'] = { ModelBase: _ModelBase2['default'], Model: _Model2['default'], ModelDefinition: _ModelDefinition2['default'], ModelDefinitions: _ModelDefinitions2['default'], ModelValidation: _ModelValidation2['default'] }; module.exports = exports['default']; /***/ }, /* 5 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var _ModelValidation = __webpack_require__(6); var _ModelValidation2 = _interopRequireDefault(_ModelValidation); var _libCheck = __webpack_require__(3); var _helpersJson = __webpack_require__(13); var modelValidator = _ModelValidation2['default'].getModelValidation(); var DIRTY_PROPERTY_LIST = Symbol('List to keep track of dirty properties'); exports.DIRTY_PROPERTY_LIST = DIRTY_PROPERTY_LIST; function hasModelValidationForProperty(model, property) { return Boolean(model.modelDefinition && model.modelDefinition.modelValidations && model.modelDefinition.modelValidations[property] && Object.prototype.hasOwnProperty.call(model.modelDefinition.modelValidations, property)); } function updateModelFromResponseStatus(result) { if (result && result.httpStatus === 'Created' && result && (0, _libCheck.isValidUid)(result.response.uid)) { this.dataValues.id = result.response.uid; this.dataValues.href = [this.modelDefinition.apiEndpoint, this.dataValues.id].join('/'); } this.dirty = false; this.getDirtyChildren().forEach(function (value) { if (value.resetDirtyState) { value.resetDirtyState(); } else { value.dirty = false; // eslint-disable-line no-param-reassign } }); this[DIRTY_PROPERTY_LIST].clear(); return result; } /** * @class ModelBase */ var ModelBase = (function () { function ModelBase() { _classCallCheck(this, ModelBase); } _createClass(ModelBase, [{ key: 'create', /** * @method create * * @returns {Promise} Returns a promise that resolves when the model has been saved or rejected with the result from * the `validate()` call. * * @definition * Will save model as a new object to the server using a POST request. This method would generally be used if * you're creating models with pre-specified IDs. Note that this does not check if the model is marked as dirty. */ value: function create() { var _this = this; return this.validate().then(function (validationState) { if (!validationState.status) { return Promise.reject(validationState); } return _this.modelDefinition.saveNew(_this).then(updateModelFromResponseStatus.bind(_this)); }); } /** * @method save * * @returns {Promise} Returns a promise that resolves when the model has been saved * or rejects with the result from the `validate()` call. * * @description * Checks if the model is dirty. When the model is dirty it will check if the values of the model are valid by calling * `validate`. If this is correct it will attempt to save the [Model](#/model/Model) to the api. * * ```js * myModel.save() * .then((message) => console.log(message)); * ``` */ }, { key: 'save', value: function save(includeChildren) { var _this2 = this; if (!this.isDirty(includeChildren)) { return Promise.reject('No changes to be saved'); } return this.validate().then(function (validationState) { if (!validationState.status) { return Promise.reject(validationState); } return _this2.modelDefinition.save(_this2).then(updateModelFromResponseStatus.bind(_this2)); }); } /** * @method validate * * @returns {Promise} Promise that resolves with an object with a status property that represents if the model * is valid or not the fields array will return the names of the fields that are invalid. * * @description * This will run the validations on the properties which have validations set. Normally these validations are defined * through the DHIS2 schema. It will check min/max for strings/numbers etc. Additionally it will * run model validations against the schema. * * ```js * myModel.validate() * .then(myModelStatus => { * if (myModelStatus.status === false) { * myModelStatus.fields.forEach((fieldName) => console.log(fieldName)); * } * }); * ``` */ }, { key: 'validate', value: function validate() { var _this3 = this; return new Promise(function (resolve, reject) { var validationMessages = []; function unique(current, property) { if (property && current.indexOf(property) === -1) { current.push(property); } return current; } function asyncRemoteValidation(model) { return modelValidator.validateAgainstSchema(model); } // Run async validation against the api asyncRemoteValidation(_this3)['catch'](function (remoteMessages) { // Errors are ok in this case if (Array.isArray(remoteMessages)) { return remoteMessages; } return Promise.reject(remoteMessages); }).then(function (remoteMessages) { validationMessages = validationMessages.concat(remoteMessages); var validationState = { status: remoteMessages.length === 0, fields: validationMessages.map(function (validationMessage) { return validationMessage.property; }).reduce(unique, []), messages: validationMessages }; resolve(validationState); })['catch'](function (message) { return reject(message); }); }); } }, { key: 'clone', value: function clone() { return this.modelDefinition.create((0, _helpersJson.getJSONForProperties)(this, Object.keys(this.modelDefinition.modelValidations))); } }, { key: 'delete', value: function _delete() { return this.modelDefinition['delete'](this); } }, { key: 'isDirty', value: function isDirty() { var includeChildren = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; if (!(this.dirty || includeChildren === true && this.hasDirtyChildren())) { return false; } return true; } }, { key: 'getDirtyPropertyNames', value: function getDirtyPropertyNames() { return Array.from(this[DIRTY_PROPERTY_LIST].values()); } }, { key: 'getCollectionChildren', value: function getCollectionChildren() { var _this4 = this; // TODO: Can't be sure that this has a `modelDefinition` property return Object.keys(this).filter(function (propertyName) { return _this4[propertyName] && hasModelValidationForProperty(_this4, propertyName) && _this4.modelDefinition.modelValidations[propertyName].owner; }).map(function (propertyName) { return _this4[propertyName]; }); } }, { key: 'getCollectionChildrenPropertyNames', value: function getCollectionChildrenPropertyNames() { var _this5 = this; return Object.keys(this).filter(function (propertyName) { return _this5.modelDefinition && _this5.modelDefinition.modelValidations && _this5.modelDefinition.modelValidations[propertyName] && _this5.modelDefinition.modelValidations[propertyName].type === 'COLLECTION'; }); } }, { key: 'getDirtyChildren', value: function getDirtyChildren() { return this.getCollectionChildren().filter(function (property) { return property && property.dirty === true; }); } }, { key: 'hasDirtyChildren', value: function hasDirtyChildren() { return this.getDirtyChildren().length > 0; } }]); return ModelBase; })(); exports['default'] = new ModelBase(); /***/ }, /* 6 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var _libCheck = __webpack_require__(3); var _loggerLogger = __webpack_require__(2); var _loggerLogger2 = _interopRequireDefault(_loggerLogger); var _apiApi = __webpack_require__(7); var _apiApi2 = _interopRequireDefault(_apiApi); var _helpersJson = __webpack_require__(13); /** * @class ModelValidation */ var ModelValidation = (function () { function ModelValidation(providedLogger) { _classCallCheck(this, ModelValidation); (0, _libCheck.checkType)(providedLogger, 'object', 'logger (Logger)'); this.logger = providedLogger; } /** * @deprecated * @method validate * * @returns {{status: boolean, messages: Array}} Returns {status: true, messages: []} */ _createClass(ModelValidation, [{ key: 'validate', value: function validate() { this.logger.warn('Client side model validation is deprecated'); throw new Error('Client side model validation is deprecated'); } /** * @method validateAgainstSchema * * @param {Model} model The model that should be validated. * @returns {Array} Returns an array with validation messages if there are any. * * @description * Sends a POST request against the `api/schemas` endpoint to check if the model is valid. * * @note {warn} Currently only checks */ }, { key: 'validateAgainstSchema', value: function validateAgainstSchema(model) { if (!(model && model.modelDefinition && model.modelDefinition.name)) { return Promise.reject('model.modelDefinition.name can not be found'); } function extractValidationViolations(webmessage) { if (webmessage.response && webmessage.response.errorReports) { return webmessage.response.errorReports; } throw new Error('Response was not a WebMessage with the expected format'); } var url = 'schemas/' + model.modelDefinition.name; // TODO: The function getOwnedPropertyJSON should probably not be exposed, perhaps we could have a getJSONForModel(ownedPropertiesOnly=true) method. return _apiApi2['default'].getApi().post(url, (0, _helpersJson.getOwnedPropertyJSON)(model)).then(function (webMessage) { if (webMessage.status === 'OK') { return []; } return Promise.reject(webMessage); })['catch'](extractValidationViolations); } /** * @method getModelValidation * @static * * @returns {ModelValidation} New or memoized instance of `ModelInstance` * * @description * Returns the `ModelValidation` singleton. Creates a new one if it does not yet exist. * Grabs a logger instance by calling `Logger.getLogger` */ }], [{ key: 'getModelValidation', value: function getModelValidation() { if (this.modelValidation) { return this.modelValidation; } return this.modelValidation = new ModelValidation(_loggerLogger2['default'].getLogger(console)); } }]); return ModelValidation; })(); exports['default'] = ModelValidation; module.exports = exports['default']; /***/ }, /* 7 */ /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global, process) {'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } var _libCheck = __webpack_require__(3); var _libUtils = __webpack_require__(1); var _systemSystem = __webpack_require__(9); var _systemSystem2 = _interopRequireDefault(_systemSystem); __webpack_require__(12); function getMergeStrategyParam() { var mergeType = arguments.length <= 0 || arguments[0] === undefined ? 'REPLACE' : arguments[0]; var system = _systemSystem2['default'].getSystem(); if (system.version && Number(system.version.minor) <= 22) { return 'mergeStrategy=' + mergeType; } return 'mergeMode=' + mergeType; } function getUrl(baseUrl, url) { // If we are dealing with an absolute url use that instead if (new RegExp('^(:?https?:)?//').test(url)) { return url; } var urlParts = []; if (baseUrl) { urlParts.push(baseUrl); } urlParts.push(url); return urlParts.join('/').replace(new RegExp('(.(?:[^:]))\/\/+', 'g'), '$1/').replace(new RegExp('\/$'), ''); } var Api = (function () { function Api(fetchImpl) { _classCallCheck(this, Api); // Optionally provide fetch to the constructor so it can be mocked during testing if (typeof fetchImpl === 'function') { this.fetch = fetchImpl.bind(typeof window !== 'undefined' ? window : global); } else if (typeof fetch !== 'undefined') { this.fetch = fetch.bind(typeof window !== 'undefined' ? window : global); } else { throw new Error('Failed to initialise D2 Api: No fetch implementation is available'); } this.baseUrl = '/api'; this.defaultFetchOptions = { mode: 'cors', // requests to different origins fail credentials: 'include', // include cookies with same-origin requests cache: 'default', // See https://fetch.spec.whatwg.org/#concept-request-cache-mode, headers: new Headers() }; } _createClass(Api, [{ key: 'get', value: function get(url, data, options) { return this.request('GET', getUrl(this.baseUrl, url), data, options); } /* eslint-disable complexity */ }, { key: 'post', value: function post(url, data) { var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; var requestUrl = getUrl(this.baseUrl, url); var payload = data; // Ensure that headers are defined and are treated without case sensitivity options.headers = new Headers(options.headers || {}); // eslint-disable-line // Pass data through JSON.stringify, unless options.contentType is 'text/plain' or false (meaning don't process) // TODO: Deprecated - remove in v26 if (options.contentType) { // Display a deprecation warning, except during test if (!process.env || process.env.npm_lifecycle_event !== 'test') { var e = new Error(); console.warn( // eslint-disable-line 'Deprecation warning: Setting `contentType` for API POST requests is deprecated, and support may ' + 'be removed in the next major release of D2. In stead you may set the `Content-Type` header ' + 'explicitly. If no `Content-Type` header is specified, the browser will try to determine one for ' + 'you.\nRequest:', 'POST', requestUrl, e.stack); } options.headers.set('Content-Type', 'text/plain'); delete options.contentType; // eslint-disable-line } else if (data.constructor.name === 'FormData' && !options.headers.get('Content-Type')) { options.headers.set('Content-Type', 'multipart/form-data'); payload = data; } else { payload = JSON.stringify(data); } return this.request('POST', requestUrl, payload, options); } /* eslint-enable complexity */ }, { key: 'delete', value: function _delete(url, options) { return this.request('DELETE', getUrl(this.baseUrl, url), undefined, options); } }, { key: 'update', value: function update(url, data) { var useMergeStrategy = arguments.length <= 2 || arguments[2] === undefined ? false : arguments[2]; // Since we are currently using PUT to save the full state back, we have to use mergeMode=REPLACE // to clear out existing values var urlForUpdate = useMergeStrategy === true ? url + '?' + getMergeStrategyParam() : url; return this.request('PUT', getUrl(this.baseUrl, urlForUpdate), JSON.stringify(data)); } /* eslint-disable complexity */ }, { key: 'request', value: function request(method, url, data) { var _this = this; var options = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3]; (0, _libCheck.checkType)(method, 'string', 'Request type'); (0, _libCheck.checkType)(url, 'string', 'Url'); var api = this; var requestUrl = url; var query = ''; if (requestUrl.indexOf('?') !== -1) { query = requestUrl.substr(requestUrl.indexOf('?') + 1); requestUrl = requestUrl.substr(0, requestUrl.indexOf('?')); } // Transfer filter properties from the data object to the query string if (data && Array.isArray(data.filter)) { query = '' + query + (query.length ? '&' : '') + 'filter=' + data.filter.join('&filter='); delete data.filter; // eslint-disable-line no-param-reassign } // When using the GET method, transform the data object to query parameters if (data && method === 'GET') { Object.keys(data).forEach(function (key) { query = '' + query + (query.length > 0 ? '&' : '') + key + '=' + data[key]; }); } function getOptions(mergeOptions, requestData) { var resultOptions = Object.assign({}, api.defaultFetchOptions, mergeOptions); var headers = new Headers(mergeOptions.headers || {}); resultOptions.method = method; // Only set content type when there is data to send // GET requests and requests without data do not need a Content-Type header // 0 and false are valid requestData values and therefore should have a content type if (resultOptions.method === 'GET' || !requestData && requestData !== 0 && requestData !== false) { headers['delete']('Content-Type'); } else if (requestData) { // resultOptions.dataType = options.dataType !== undefined ? options.dataType : 'json'; if (!headers.get('Content-Type')) { headers.set('Content-Type', data.constructor.name === 'FormData' ? 'multipart/form-data' : 'application/json'); } resultOptions.body = requestData; } // Handle the dataType option used by jQuery.ajax, but throw a deprecation warning // TODO: Remove in 2.26 if (mergeOptions.dataType) { // Display a deprecation warning, except during test if (!process.env || process.env.npm_lifecycle_event !== 'test') { var e = new Error(); console.warn( // eslint-disable-line 'Deprecation warning: Setting `dataType` for API requests is deprecated, and support may be ' + 'removed in the next major release of D2. In stead you should set the `Accept` header ' + 'directly.\nRequest:', resultOptions.method, requestUrl, e.stack); } if (mergeOptions.dataType === 'text') { headers.set('Accept', 'text/plain'); delete resultOptions.dataType; } } resultOptions.headers = headers; return resultOptions; } if (query.length) { requestUrl = requestUrl + '?' + (0, _libUtils.customEncodeURIComponent)(query); } var requestOptions = getOptions(options, options.method === 'GET' ? undefined : data); // If the provided value is valid JSON, return the parsed JSON object. If not, return the raw value as is. function parseResponseData(value) { try { return JSON.parse(value); } catch (e) { return value; } } return new Promise(function (resolve, reject) { // fetch returns a promise that will resolve with any response received from the server // It will be rejected ONLY if no response is received from the server, i.e. because there's no internet _this.fetch(requestUrl, requestOptions).then(function (response) { // If the request failed, response.ok will be false and response.status will be the status code if (response.ok) { response.text().then(function (text) { return resolve(parseResponseData(text)); }); } else { response.text().then(function (text) { if (!process.env || process.env.npm_lifecycle_event !== 'test') { console.warn( // eslint-disable-line 'API request failed with status ' + response.status + ' ' + response.statusText + '\n', 'Request: ' + requestOptions.method + ' ' + requestUrl); } reject(parseResponseData(text)); }); } })['catch'](function (err) { // It's not usually possible to get much info about the cause of the error programmatically, but // the user can check the browser console for more info if (!process.env || process.env.npm_lifecycle_event !== 'test') { console.error('Server connection error:', err); // eslint-disable-line } reject('Server connection failed for API request: ' + requestOptions.method + ' ' + requestUrl); }); }); } /* eslint-enable complexity */ }, { key: 'setBaseUrl', value: function setBaseUrl(baseUrl) { (0, _libCheck.checkTyp