diff --git a/config.js.template b/config.js.template deleted file mode 100644 index 525f6bd..0000000 --- a/config.js.template +++ /dev/null @@ -1,6 +0,0 @@ -btoa = (s) => new Buffer(s).toString('base64'); - -Object.assign(exports, { - "baseUrl": "http://localhost:8080", - "authorization": "Basic " + btoa("admin:district") -}); \ No newline at end of file diff --git a/package.json b/package.json index fba5acb..457614a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "d2-user-extended-app", - "version": "0.3.0", + "version": "0.4.0", "description": "DHIS2 Extended User app", "main": "src/index.html", "license": "GPL-3.0", @@ -55,7 +55,6 @@ "karma-coverage": "0.5.0", "karma-mocha": "0.2.0", "karma-mocha-reporter": "1.1.1", - "karma-phantomjs-launcher": "0.2.1", "karma-sinon": "1.0.4", "karma-sinon-chai": "1.0.0", "karma-sourcemap-loader": "0.3.5", @@ -68,7 +67,6 @@ "mocha": "2.2.5", "moment": "^2.19.1", "node-sass": "^3.7.0", - "phantomjs": "1.9.18", "phantomjs-polyfill": "0.0.1", "precommit-hook": "3.0.0", "prettier": "^1.18.2", diff --git a/src/List/List.component.js b/src/List/List.component.js index c79a310..8d28160 100644 --- a/src/List/List.component.js +++ b/src/List/List.component.js @@ -25,6 +25,7 @@ import replicateUserStore from "./replicateUser.store"; import OrgUnitDialog from "./organisation-unit-dialog/OrgUnitDialog.component"; import UserRolesDialog from "../components/UserRolesDialog.component"; import UserGroupsDialog from "../components/UserGroupsDialog.component"; +import CopyInUserDialog from "../components/CopyInUserDialog.component"; import ReplicateUserFromTemplate from "../components/ReplicateUserFromTemplate.component"; import ReplicateUserFromTable from "../components/ReplicateUserFromTable.component"; import snackActions from "../Snackbar/snack.actions"; @@ -43,6 +44,7 @@ import ModalLoadingMask from "../components/ModalLoadingMask.component"; import SettingsDialog from "../components/SettingsDialog.component"; import Filters from "./Filters.component"; import DetailsBoxWithScroll from "./DetailsBoxWithScroll.component"; +import copyInUserStore from "./copyInUser.store"; const pageSize = 50; @@ -151,6 +153,9 @@ const List = React.createClass({ importUsers: { open: false, }, + copyUsers: { + open: false, + }, }; }, @@ -248,6 +253,10 @@ const List = React.createClass({ const deleteUserStoreDisposable = deleteUserStore.subscribe(users => this.filterList()); + const userCopyUserDialogStoreDisposable = copyInUserStore.subscribe(copyUsers => { + this.setAssignState("copyUsers", copyUsers); + }); + this.registerDisposable(detailsStoreDisposable); this.registerDisposable(orgUnitAssignmentStoreDisposable); this.registerDisposable(userRolesAssignmentDialogStoreDisposable); @@ -255,6 +264,7 @@ const List = React.createClass({ this.registerDisposable(replicateUserDialogStoreDisposable); this.registerDisposable(deleteUserStoreDisposable); this.registerDisposable(enableStoreDisposable); + this.registerDisposable(userCopyUserDialogStoreDisposable); this.filterList(); }, @@ -456,7 +466,13 @@ const List = React.createClass({ }; const rows = this.getDataTableRows(this.state.dataRows); - const { assignUserRoles, assignUserGroups, replicateUser, listFilterOptions } = this.state; + const { + assignUserRoles, + assignUserGroups, + replicateUser, + listFilterOptions, + copyUsers, + } = this.state; const { showAllUsers, filterByGroups, @@ -555,6 +571,13 @@ const List = React.createClass({ /> ) : null} + {copyUsers.open ? ( + copyInUserStore.setState({ open: false })} + /> + ) : null} + {assignUserGroups.open ? ( detailsStore.setState(user), primary: true, }, + { + name: "copyInUser", + multiple: false, + icon: "content_copy", + onClick: user => copyInUserStore.setState({ user, open: true }), + allowed: checkAccess(["update"]), + }, { name: "assignToOrgUnits", multiple: true, diff --git a/src/List/copyInUser.store.js b/src/List/copyInUser.store.js new file mode 100644 index 0000000..2203dce --- /dev/null +++ b/src/List/copyInUser.store.js @@ -0,0 +1,3 @@ +import Store from "d2-ui/lib/store/Store"; + +export default Store.create(); diff --git a/src/components/CopyInUserDialog.component.js b/src/components/CopyInUserDialog.component.js new file mode 100644 index 0000000..bbf3a20 --- /dev/null +++ b/src/components/CopyInUserDialog.component.js @@ -0,0 +1,46 @@ +import React from "react"; +import PropTypes from "prop-types"; +import CopyInUserBatchModelsMultiSelectComponent from "./batch-models-multi-select/CopyInUserBatchModelsMultiSelect.component"; +import CopyInUserBatchModelsMultiSelectModel from "./batch-models-multi-select/CopyInUserBatchModelsMultiSelect.model"; +import _m from "../utils/lodash-mixins"; +import { getPayload } from "../models/userHelpers"; + +function getTitle(getTranslation, users) { + const usernames = users && users.map(user => user.userCredentials.username); + const info = usernames ? _m.joinString(getTranslation, usernames, 3, ", ") : "..."; + return getTranslation("copyInUser") + ": " + info; +} + +function CopyInUserDialog(props, context) { + const { d2 } = context; + const getTranslation = context.d2.i18n.getTranslation.bind(context.d2.i18n); + const modelOptions = { + parentModel: d2.models.users, + parentFields: ":owner,userCredentials[id,username,userRoles[id,name],lastLogin]", + childrenModel: d2.models.users, + getChildren: user => user.userCredentials.userRoles, + getPayload: getPayload, + }; + + return ( + getTitle(getTranslation, users)} + onSuccess={getTranslation("user_configuration_copied")} + onError={getTranslation("user_configuration_copied_error")} + /> + ); +} + +CopyInUserDialog.contextTypes = { + d2: PropTypes.object.isRequired, +}; + +CopyInUserDialog.propTypes = { + user: PropTypes.object.isRequired, + onRequestClose: PropTypes.func.isRequired, +}; + +export default CopyInUserDialog; diff --git a/src/components/batch-models-multi-select/BatchModelsMultiSelect.component.js b/src/components/batch-models-multi-select/BatchModelsMultiSelect.component.js index 8b2aa1d..66be82d 100644 --- a/src/components/batch-models-multi-select/BatchModelsMultiSelect.component.js +++ b/src/components/batch-models-multi-select/BatchModelsMultiSelect.component.js @@ -60,7 +60,6 @@ export default class BatchModelsMultiSelectComponent extends React.Component { componentDidMount() { const { parents, model } = this.props; - return Promise.all([model.getAllChildren(), model.getParents(parents)]) .then(([allChildren, parentsLoaded]) => this.setState({ @@ -111,7 +110,6 @@ export default class BatchModelsMultiSelectComponent extends React.Component { .then(() => this.close(this.props.onSuccess)) .catch(err => this.close(this.props.onError)); } - onChange(selectedIds) { this.setState({ selectedIds }); } diff --git a/src/components/batch-models-multi-select/BatchModelsMultiSelect.model.js b/src/components/batch-models-multi-select/BatchModelsMultiSelect.model.js index 0ac7174..74ac32c 100644 --- a/src/components/batch-models-multi-select/BatchModelsMultiSelect.model.js +++ b/src/components/batch-models-multi-select/BatchModelsMultiSelect.model.js @@ -1,5 +1,4 @@ import _ from "lodash"; - const toArray = obj => (obj.toArray ? obj.toArray() : obj || []); export default class BatchModelsMultiSelectModel { diff --git a/src/components/batch-models-multi-select/CopyInUserBatchModelsMultiSelect.component.js b/src/components/batch-models-multi-select/CopyInUserBatchModelsMultiSelect.component.js new file mode 100644 index 0000000..3ff40ac --- /dev/null +++ b/src/components/batch-models-multi-select/CopyInUserBatchModelsMultiSelect.component.js @@ -0,0 +1,241 @@ +import React from "react"; +import Dialog from "material-ui/Dialog/Dialog"; +import FlatButton from "material-ui/FlatButton/FlatButton"; +import RaisedButton from "material-ui/RaisedButton/RaisedButton"; +import LoadingMask from "d2-ui/lib/loading-mask/LoadingMask.component"; +import TextField from "material-ui/TextField/TextField"; +import MultiSelect from "../MultiSelect.component"; +import snackActions from "../../Snackbar/snack.actions"; +import Toggle from "material-ui/Toggle/Toggle"; +import PropTypes from "prop-types"; + +export default class CopyInUserBatchModelsMultiSelectComponent extends React.Component { + constructor(props, context) { + super(props, context); + this.getTranslation = context.d2.i18n.getTranslation.bind(context.d2.i18n); + this.state = { + state: "loading", + parents: null, + allChildren: null, + selectedIds: null, + filterText: "", + updateStrategy: this.props.parents.length > 1 ? "merge" : "replace", + copyUserGroups: false, + copyUserRoles: false, + }; + } + + styles = { + dialog: { + minWidth: 875, + maxWidth: "100%", + }, + contents: { + padding: 15, + position: "relative", + height: 450, + minHeight: 450, + maxHeight: 450, + minWidth: 800, + }, + loadingMask: { + position: "fixed", + top: 54, + right: 22, + width: 480, + height: 250, + background: "rgba(255,255,255,0.6)", + zIndex: 5, + }, + controls: { + position: "fixed", + top: 156, + right: 24, + width: 475, + zIndex: 1, + background: "white", + }, + cancelButton: { + marginRight: 16, + }, + toggle: { + width: 135, + float: "right", + marginTop: 20, + marginRight: 50, + }, + }; + + componentDidMount() { + const { parents, model } = this.props; + return Promise.all([model.getAllChildren(), model.getParents(parents)]) + .then(([allChildren, parentsLoaded]) => + this.setState({ + state: "ready", + parents: parentsLoaded, + allChildren, + selectedIds: [], + }) + ) + .catch(err => + this.close(this.getTranslation("error_loading_data") + " :" + err.toString()) + ); + } + + close(snackMessage = null) { + if (snackMessage) snackActions.show({ message: snackMessage }); + this.props.onRequestClose(); + } + + renderStrategyToggle() { + if (this.state.parents && this.state.parents.length > 1) { + const label = + this.getTranslation("update_strategy") + + ": " + + this.getTranslation("update_strategy_" + this.state.updateStrategy); + + return ( + + this.setState({ updateStrategy: newValue ? "replace" : "merge" }) + } + /> + ); + } else { + return null; + } + } + + async copyInUserSave() { + const { parents, selectedIds, copyUserGroups, copyUserRoles } = this.state; + this.setState({ state: "loading" }); + await this.props.model + .copyInUserSave(parents, selectedIds, copyUserGroups, copyUserRoles) + .then(() => this.close(this.props.onSuccess)) + .catch(err => this.close(this.props.onError)) + .finally(() => this.setState({ state: "ready" })); + } + + onChange(selectedIds) { + this.setState({ selectedIds }); + } + + render() { + switch (this.state.state) { + case "loading": + return ( +
+ +
+ ); + case "error": + return
{this.state.error}
; + case "ready": + return this.renderForm(); + default: + throw new Error(`Unknown state: ${state}`); + } + } + + onFilterTextChange(event) { + this.setState({ filterText: event.target.value }); + } + + copy() { + const { copyUserGroups, copyUserRoles, selectedIds } = this.state; + + if (!copyUserGroups && !copyUserRoles) { + snackActions.show({ message: this.getTranslation("select_one_toggle") }); + } else if (_.isEmpty(selectedIds)) { + snackActions.show({ message: this.getTranslation("select_at_least_one_user") }); + } else { + this.copyInUserSave(); + } + } + + getDialogButtons() { + const isLoading = this.state.state === "loading"; + + return [ + , + , + ]; + } + + render() { + const isLoading = this.state.state === "loading"; + const { parents, allChildren, filterText, selectedIds } = this.state; + const title = this.props.getTitle(parents, allChildren); + const parentName = this.props.parents[0].name; + const options = _(allChildren || []) + .sortBy("name") + .map(obj => ({ value: obj.id, text: obj.name })) + .filter(obj => obj.text !== parentName) + .value(); + return ( + + + + {this.renderStrategyToggle()} + + this.setState({ copyUserGroups: newValue })} + /> + this.setState({ copyUserRoles: newValue })} + /> +
+ +
+
+ ); + } +} + +CopyInUserBatchModelsMultiSelectComponent.propTypes = { + model: PropTypes.object.isRequired, + parents: PropTypes.arrayOf(PropTypes.object).isRequired, + onRequestClose: PropTypes.func.isRequired, +}; + +CopyInUserBatchModelsMultiSelectComponent.contextTypes = { + d2: PropTypes.object.isRequired, +}; diff --git a/src/components/batch-models-multi-select/CopyInUserBatchModelsMultiSelect.model.js b/src/components/batch-models-multi-select/CopyInUserBatchModelsMultiSelect.model.js new file mode 100644 index 0000000..a716204 --- /dev/null +++ b/src/components/batch-models-multi-select/CopyInUserBatchModelsMultiSelect.model.js @@ -0,0 +1,70 @@ +import _ from "lodash"; +import { getOwnedPropertyJSON } from "d2/lib/model/helpers/json"; +import { getExistingUsers } from "../../models/userHelpers"; +const toArray = obj => (obj.toArray ? obj.toArray() : obj || []); + +export default class CopyInUserBatchModelsMultiSelectModel { + constructor( + d2, + { parentModel, getPayload, parentFields, childrenModel, childrenFields, getChildren } + ) { + Object.assign(this, { + d2, + parentModel: parentModel, + parentFields: parentFields || ":owner", + childrenModel: childrenModel, + getChildren: parent => toArray(getChildren(parent)), + childrenFields: childrenFields || "id,name", + getPayload, + }); + } + + getAllChildren() { + return this.childrenModel + .list({ fields: this.childrenFields, paging: false }) + .then(collection => + _(collection.toArray()) + .sortBy("name") + .value() + ); + } + + getParents(parents) { + const parentIds = _(parents) + .map(obj => obj.id) + .compact() + .value(); + const options = { + paging: false, + filter: "id:in:[" + parentIds.join(",") + "]", + fields: this.parentFields || ":owner", + }; + return this.parentModel.list(options).then(collection => collection.toArray()); + } + + async getUserInfo(ids) { + const users = await getExistingUsers(d2, { + fields: ":owner,userGroups[id]", + filter: "id:in:[" + ids.join(",") + "]", + }); + return users; + } + async copyInUserSave(parents, selectedIds, copyUserGroups, copyUserRoles) { + const parentWithRoles = await this.getUserInfo([getOwnedPropertyJSON(parents[0]).id]); + const childrenUsers = await this.getUserInfo(selectedIds); + const payload = await this.getPayload( + ...parentWithRoles, + childrenUsers, + copyUserGroups, + copyUserRoles + ); + return payload; + } + + getSelectedChildren(parents) { + const commonChildren = _.intersectionBy(...parents.map(this.getChildren), "id"); + return _(commonChildren) + .sortBy(obj => obj.name) + .value(); + } +} diff --git a/src/i18n/i18n_module_ar.properties b/src/i18n/i18n_module_ar.properties index 31bfa5d..42b34ac 100644 --- a/src/i18n/i18n_module_ar.properties +++ b/src/i18n/i18n_module_ar.properties @@ -7,6 +7,7 @@ assignToOrgUnitsOutput=Assign to organisation units output replicateUser=Replicate user cancel=CANCEL close=Close +copyInUser=Copy in User remove=Remove enable=Enable disable=Disable @@ -67,6 +68,8 @@ organisation_unit_assignment_saved=Organisation unit assignment saved organisation_unit_assignment_save_error=Failed to save organisation unit assignment no_changes_to_be_saved=No changes to be saved error_loading_data=Error loading data +user_configuration_copied=User configuration successfully copied +user_configuration_copied_error=Fail to copy user configuration user_roles_assigned=User roles assigned user_roles_assign_error=User roles failed to be assigned user_groups_assigned=User groups assigned @@ -125,3 +128,5 @@ confirm_delete_users=Are you sure you want to remove the selected users? ($$user users_deleted=Users removed successfully: $$users$$ config_import_export=Import/export setting_organisation_units_field=Organisation Units field used for users import/export +select_one_toggle=You must select a toggle option +select_at_least_one_user=Select at least one destination user diff --git a/src/i18n/i18n_module_en.properties b/src/i18n/i18n_module_en.properties index 6d33fb7..1133a7c 100644 --- a/src/i18n/i18n_module_en.properties +++ b/src/i18n/i18n_module_en.properties @@ -7,6 +7,7 @@ assignToOrgUnitsOutput=Assign to organisation units output replicateUser=Replicate user cancel=CANCEL close=Close +copyInUser=Copy in User remove=Remove enable=Enable disable=Disable @@ -67,6 +68,8 @@ organisation_unit_assignment_saved=Organisation unit assignment saved organisation_unit_assignment_save_error=Failed to save organisation unit assignment no_changes_to_be_saved=No changes to be saved error_loading_data=Error loading data +user_configuration_copied=User configuration successfully copied +user_configuration_copied_error=Fail to copy user configuration user_roles_assigned=User roles assigned user_roles_assign_error=User roles failed to be assigned user_groups_assigned=User groups assigned @@ -125,3 +128,5 @@ confirm_delete_users=Are you sure you want to remove the selected users? ($$user users_deleted=Users removed successfully: $$users$$ config_import_export=Import/export setting_organisation_units_field=Organisation Units field used for users import/export +select_one_toggle=You must select a toggle option +select_at_least_one_user=Select at least one destination user diff --git a/src/i18n/i18n_module_es.properties b/src/i18n/i18n_module_es.properties index c0a58bb..ed9b6fc 100644 --- a/src/i18n/i18n_module_es.properties +++ b/src/i18n/i18n_module_es.properties @@ -7,6 +7,7 @@ assignToOrgUnitsOutput=Asignar a unidades organizativas de salida replicateUser=Replicar usuario cancel=CANCELAR close=Cerrar +copyInUser=Copiar en usuario remove=Eliminar enable=Habilitar disable=Deshabilitar @@ -63,10 +64,12 @@ username=Nombre de usuario dismiss=Cerrar ok=OK no_org_units_add_one_to_get_started=No hay unidades organizativas, añada una para empezar -organisation_unit_assignment_saved=Asignació de unidad organizativa guardada +organisation_unit_assignment_saved=Asignación de unidad organizativa guardada organisation_unit_assignment_save_error=Se produjo un error al guardar la asignació de unidad organizativa no_changes_to_be_saved=No hay cambios a guardar error_loading_data=Error cargado datos +user_configuration_copied=Configuración de user copiada +user_configuration_copied_error=Fallo copiando configuración de usuario user_roles_assigned=Los roles de usuario asignados correctamente user_roles_assign_error=Error al asignar los roles de usuario user_groups_assigned=Grupos de usuario asignados @@ -125,3 +128,5 @@ confirm_delete_users=¿Está seguro de que quiere eliminar los usuarios seleccio users_deleted=Usuarios eliminados con éxito: $$users$$ config_import_export=Importación/Exportación setting_organisation_units_field=Campo para unidades organizativas usando en importación/exportación de usuarios +select_one_toggle=Seleccione al menos un modelo a copiar +select_at_least_one_user=Seleccione al menos un usuario destino diff --git a/src/i18n/i18n_module_fr.properties b/src/i18n/i18n_module_fr.properties index 5cb2e5e..d348153 100644 --- a/src/i18n/i18n_module_fr.properties +++ b/src/i18n/i18n_module_fr.properties @@ -7,6 +7,7 @@ assignToOrgUnitsOutput=Assign to organisation units output replicateUser=Replicate user cancel=CANCEL close=Close +copyInUser=Copy in User remove=Remove enable=Enable disable=Disable @@ -67,6 +68,8 @@ organisation_unit_assignment_saved=Organisation unit assignment saved organisation_unit_assignment_save_error=Failed to save organisation unit assignment no_changes_to_be_saved=No changes to be saved error_loading_data=Error loading data +user_configuration_copied=User configuration successfully copied +user_configuration_copied_error=Fail to copy user configuration user_roles_assigned=User roles assigned user_roles_assign_error=User roles failed to be assigned user_groups_assigned=User groups assigned @@ -125,3 +128,5 @@ confirm_delete_users=Are you sure you want to remove the selected users? ($$user users_deleted=Users removed successfully: $$users$$ config_import_export=Import/export setting_organisation_units_field=Organisation Units field used for users import/export +select_one_toggle=You must select a toggle option +select_at_least_one_user=Select at least one destination user diff --git a/src/models/userHelpers.js b/src/models/userHelpers.js index 4a88ebd..7f4aee3 100644 --- a/src/models/userHelpers.js +++ b/src/models/userHelpers.js @@ -1,4 +1,5 @@ import _ from "lodash"; +import _m from "../utils/lodash-mixins"; import moment from "moment"; import Papa from "papaparse"; import { generateUid } from "d2/lib/uid"; @@ -526,6 +527,16 @@ async function saveUsers(d2, users) { return postMetadata(api, payload); } +async function saveCopyInUsers(d2, users, copyUserGroups, copyUserRoles) { + const api = d2.Api.getApi(); + const userGroupsToSave = await getUserGroupsToSave(api, users, []); + const payload = { users: users, userGroups: userGroupsToSave }; + + if (copyUserRoles && !copyUserGroups) { + return postMetadata(api, { users: users }); + } else return postMetadata(api, payload); +} + /* Return an array of users from DHIS2 API. filters: Object with `field` as keys, `[operator, value]` as values. @@ -627,6 +638,29 @@ async function getExistingUsers(d2, options = {}) { return users; } +function getPayload(parentUser, destUsers, copyUserGroups, copyUserRoles) { + const users = destUsers.map(childUser => { + let childUserRoles = childUser.userCredentials.userRoles; + let childUserGroups = childUser.userGroups; + if (copyUserRoles) { + parentUser.userCredentials.userRoles.forEach(role => { + if (childUserRoles.find(element => element.id === role.id) === undefined) { + childUserRoles.push(role); + } + }); + } + if (copyUserGroups) { + parentUser.userGroups.forEach(group => { + if (childUserGroups.find(element => element.id === group.id) === undefined) { + childUserGroups.push(group); + } + }); + } + return childUser; + }); + return saveCopyInUsers(d2, users, copyUserGroups, copyUserRoles); +} + export { getList, exportToCsv, @@ -635,4 +669,5 @@ export { saveUsers, parseResponse, getExistingUsers, + getPayload, }; diff --git a/yarn.lock b/yarn.lock index cf45ad4..5ac6e62 100644 --- a/yarn.lock +++ b/yarn.lock @@ -40,10 +40,6 @@ acorn@^5.2.1, acorn@^5.4.0: version "5.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102" -adm-zip@0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736" - after@0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/after/-/after-0.8.1.tgz#ab5d4fb883f596816d3515f8f791c0af486dd627" @@ -1210,12 +1206,6 @@ bindings@1.2.x, bindings@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" -bl@~0.9.0: - version "0.9.5" - resolved "https://registry.yarnpkg.com/bl/-/bl-0.9.5.tgz#c06b797af085ea00bc527afc8efcf11de2232054" - dependencies: - readable-stream "~1.0.26" - blob@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" @@ -1407,10 +1397,6 @@ caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" -caseless@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.6.0.tgz#8167c1ab8397fb5bb95f96d28e5a81c50f247ac4" - center-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" @@ -1683,13 +1669,6 @@ concat-stream@^1.5.2: readable-stream "^2.2.2" typedarray "^0.0.6" -config-chain@~1.1.8: - version "1.1.11" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - connect-history-api-fallback@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" @@ -3023,15 +3002,6 @@ fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" -fs-extra@~0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.23.1.tgz#6611dba6adf2ab8dc9c69fab37cddf8818157e3d" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - fs-readdir-recursive@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" @@ -3192,7 +3162,7 @@ globule@^1.0.0: lodash "~4.17.4" minimatch "~3.0.2" -graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6: +graceful-fs@^4.1.2, graceful-fs@^4.1.4: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -3550,7 +3520,7 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" -ini@^1.2.0, ini@^1.3.4, ini@~1.3.0: +ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" @@ -3945,12 +3915,6 @@ json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - optionalDependencies: - graceful-fs "^4.1.6" - jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -4012,12 +3976,6 @@ karma-mocha@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-0.2.0.tgz#198937c2c5f710d9586aa5dfd6ab4ce7a4218751" -karma-phantomjs-launcher@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.2.1.tgz#7c15fbb82b7661b17ed19391f019d76554b654df" - dependencies: - lodash "^3.10.1" - karma-sinon-chai@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/karma-sinon-chai/-/karma-sinon-chai-1.0.0.tgz#ab0e653b17d8f914c841812a382f2523bf2b047d" @@ -4072,10 +4030,6 @@ karma@0.13.9, karma@>=0.9: source-map "^0.4.4" useragent "^2.1.6" -kew@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/kew/-/kew-0.4.0.tgz#da97484f1b06502146f3c60cec05ac6012cd993f" - keycode@^2.1.8: version "2.1.9" resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.9.tgz#964a23c54e4889405b4861a5c9f0480d45141dfa" @@ -4276,7 +4230,7 @@ lodash@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e" -lodash@^3.10.0, lodash@^3.10.1, lodash@^3.8.0, lodash@^3.9.3: +lodash@^3.10.0, lodash@^3.8.0, lodash@^3.9.3: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -4687,7 +4641,7 @@ node-uuid@~1.4.0: version "1.4.8" resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" -"nopt@2 || 3", nopt@3.x, nopt@~3.0.1: +"nopt@2 || 3", nopt@3.x: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" dependencies: @@ -4728,20 +4682,6 @@ normalize-url@^1.4.0: query-string "^4.1.0" sort-keys "^1.0.0" -npmconf@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/npmconf/-/npmconf-2.1.1.tgz#a266c7e5c56695eb7f55caf3a5a7328f24510dae" - dependencies: - config-chain "~1.1.8" - inherits "~2.0.0" - ini "^1.2.0" - mkdirp "^0.5.0" - nopt "~3.0.1" - once "~1.3.0" - osenv "^0.1.0" - semver "2 || 3 || 4" - uid-number "0.0.5" - "npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -4770,10 +4710,6 @@ oauth-sign@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.3.0.tgz#cb540f93bb2b22a7d5941691a288d60e8ea9386e" -oauth-sign@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.4.0.tgz#f22956f31ea7151a821e5f2fb32c113cad8b9f69" - oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -4843,12 +4779,6 @@ once@1.x, once@^1.3.0, once@^1.3.3: dependencies: wrappy "1" -once@~1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" - dependencies: - wrappy "1" - onetime@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" @@ -4920,7 +4850,7 @@ os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -osenv@0, osenv@^0.1.0, osenv@^0.1.4: +osenv@0, osenv@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" dependencies: @@ -5043,19 +4973,6 @@ phantomjs-polyfill@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/phantomjs-polyfill/-/phantomjs-polyfill-0.0.1.tgz#5e61a5c5621a2656e5374f23909d871ce61c1dd2" -phantomjs@1.9.18: - version "1.9.18" - resolved "https://registry.yarnpkg.com/phantomjs/-/phantomjs-1.9.18.tgz#e876fce89b143a6c01c24e0332ef3822851cace1" - dependencies: - adm-zip "0.4.4" - fs-extra "~0.23.1" - kew "0.4.0" - npmconf "2.1.1" - progress "1.1.8" - request "2.42.0" - request-progress "0.3.1" - which "~1.0.5" - pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -5376,7 +5293,7 @@ process@^0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -progress@1.1.8, progress@^1.1.8: +progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" @@ -5401,10 +5318,6 @@ prop-types@^15.5.8, prop-types@^15.6.1: loose-envify "^1.3.1" object-assign "^4.1.1" -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - proxy-addr@~2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" @@ -5444,10 +5357,6 @@ qs@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/qs/-/qs-1.0.2.tgz#50a93e2b5af6691c31bcea5dae78ee6ea1903768" -qs@~1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-1.2.2.tgz#19b57ff24dc2a99ce1f8bdf6afcda59f8ef61f88" - qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" @@ -5674,7 +5583,7 @@ readable-stream@^3.1.1: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@~1.0.2, readable-stream@~1.0.26: +readable-stream@~1.0.2: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" dependencies: @@ -5884,12 +5793,6 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request-progress@0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-0.3.1.tgz#0721c105d8a96ac6b2ce8b2c89ae2d5ecfcf6b3a" - dependencies: - throttleit "~0.0.2" - request@2, request@^2.61.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" @@ -5936,27 +5839,6 @@ request@2.40.0: tough-cookie ">=0.12.0" tunnel-agent "~0.4.0" -request@2.42.0: - version "2.42.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.42.0.tgz#572bd0148938564040ac7ab148b96423a063304a" - dependencies: - bl "~0.9.0" - caseless "~0.6.0" - forever-agent "~0.5.0" - json-stringify-safe "~5.0.0" - mime-types "~1.0.1" - node-uuid "~1.4.0" - qs "~1.2.0" - tunnel-agent "~0.4.0" - optionalDependencies: - aws-sign2 "~0.5.0" - form-data "~0.1.0" - hawk "1.1.1" - http-signature "~0.10.0" - oauth-sign "~0.4.0" - stringstream "~0.0.4" - tough-cookie ">=0.12.0" - request@2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" @@ -6103,14 +5985,14 @@ scss-tokenizer@^0.2.3: js-base64 "^2.1.8" source-map "^0.4.2" -"semver@2 || 3 || 4", semver@~4.3.3: - version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" +semver@~4.3.3: + version "4.3.6" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" + send@0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" @@ -6629,10 +6511,6 @@ text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" -throttleit@~0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" - through@^2.3.6, through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -6779,10 +6657,6 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" -uid-number@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.5.tgz#5a3db23ef5dbd55b81fce0ec9a2ac6fccdebb81e" - uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" @@ -7078,7 +6952,7 @@ which@1, which@^1.2.9: dependencies: isexe "^2.0.0" -which@1.0.x, which@~1.0.5: +which@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/which/-/which-1.0.9.tgz#460c1da0f810103d0321a9b633af9e575e64486f"