2017-02-13 14:50:13 -08:00
|
|
|
import Ember from 'ember';
|
|
|
|
|
2017-03-25 22:11:20 -07:00
|
|
|
const {
|
2017-03-26 06:36:23 -07:00
|
|
|
set,
|
|
|
|
get,
|
|
|
|
getWithDefault,
|
|
|
|
computed,
|
2017-03-25 22:11:20 -07:00
|
|
|
Component,
|
2017-03-26 16:03:25 -07:00
|
|
|
inject: { service }
|
2017-03-25 22:11:20 -07:00
|
|
|
} = Ember;
|
|
|
|
|
2017-03-26 13:52:37 -07:00
|
|
|
// Class to toggle readonly mode vs edit mode
|
2017-03-25 22:11:20 -07:00
|
|
|
const userNameEditableClass = 'dataset-author-cell--editing';
|
2017-03-26 13:52:37 -07:00
|
|
|
// Required minimum confirmed owners needed to update the list of owners
|
2017-03-26 06:36:23 -07:00
|
|
|
const minRequiredConfirmed = 2;
|
2017-03-26 13:52:37 -07:00
|
|
|
const _defaultOwnerProps = {
|
|
|
|
userName: 'New Owner',
|
|
|
|
email: null,
|
|
|
|
name: '',
|
|
|
|
isGroup: false,
|
|
|
|
namespace: 'urn:li:griduser',
|
|
|
|
type: 'Producer',
|
|
|
|
subType: null,
|
|
|
|
sortId: 0,
|
|
|
|
source: ''
|
|
|
|
};
|
2017-03-25 22:11:20 -07:00
|
|
|
|
|
|
|
export default Component.extend({
|
2017-03-26 06:36:23 -07:00
|
|
|
// Inject the currentUser service to retrieve logged in userName
|
2017-03-26 13:52:37 -07:00
|
|
|
sessionUser: service('current-user'),
|
|
|
|
|
|
|
|
loggedInUserName() {
|
|
|
|
return get(this, 'sessionUser.userName') ||
|
|
|
|
get(this, 'sessionUser.currentUser.userName');
|
|
|
|
},
|
2017-03-26 06:36:23 -07:00
|
|
|
|
2017-02-13 14:50:13 -08:00
|
|
|
$ownerTable: null,
|
|
|
|
|
2017-03-26 06:36:23 -07:00
|
|
|
// Returns a list of owners with truthy value for their confirmedBy attribute
|
2017-03-26 16:03:25 -07:00
|
|
|
confirmedOwners: computed('owners.@each.confirmedBy', function() {
|
2017-03-26 06:36:23 -07:00
|
|
|
return getWithDefault(this, 'owners', []).filter(
|
2017-03-26 16:03:25 -07:00
|
|
|
({ confirmedBy }) => confirmedBy
|
2017-03-26 06:36:23 -07:00
|
|
|
);
|
|
|
|
}),
|
|
|
|
|
|
|
|
// Checks that the number of confirmedOwners is < minRequiredConfirmed
|
2017-03-26 16:03:25 -07:00
|
|
|
requiredMinNotConfirmed: computed.lt(
|
|
|
|
'confirmedOwners.length',
|
|
|
|
minRequiredConfirmed
|
|
|
|
),
|
2017-03-26 06:36:23 -07:00
|
|
|
|
2017-02-13 14:50:13 -08:00
|
|
|
didInsertElement() {
|
|
|
|
this._super(...arguments);
|
|
|
|
// Cache reference to element on component
|
|
|
|
this.set('$ownerTable', $('[data-attribute=owner-table]'));
|
|
|
|
|
|
|
|
// Apply jQuery sortable plugin to element
|
2017-03-26 16:03:25 -07:00
|
|
|
this.get('$ownerTable').sortable({
|
|
|
|
start: (e, { item }) => set(this, 'startPosition', item.index()),
|
|
|
|
|
|
|
|
update: (e, { item }) => {
|
|
|
|
const from = get(this, 'startPosition');
|
|
|
|
const to = item.index(); // New position where row was dropped
|
|
|
|
const currentOwners = getWithDefault(this, 'owners', []);
|
|
|
|
|
|
|
|
// Updates the owners array to reflect the UI position changes
|
|
|
|
if (currentOwners.length) {
|
|
|
|
const reArrangedOwners = [...currentOwners];
|
|
|
|
const travelingOwner = reArrangedOwners.splice(from, 1).pop();
|
|
|
|
|
|
|
|
reArrangedOwners.splice(to, 0, travelingOwner);
|
|
|
|
currentOwners.setObjects(reArrangedOwners);
|
|
|
|
|
|
|
|
// TODO: refactor in next commit
|
|
|
|
// setOwnerNameAutocomplete(this.controller);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2017-02-13 14:50:13 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
willDestroyElement() {
|
|
|
|
this._super(...arguments);
|
|
|
|
// Removes the sortable functionality from the cached DOM element reference
|
2017-03-26 06:36:23 -07:00
|
|
|
get(this, '$ownerTable').sortable('destroy');
|
2017-02-13 14:50:13 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
actions: {
|
2017-03-25 22:11:20 -07:00
|
|
|
/**
|
|
|
|
* Handles the user intention to update the owner userName, by
|
|
|
|
* adding a class signifying edit to the DOM td classList.
|
|
|
|
* The click event is handled on the TD which is the parent
|
|
|
|
* of the target label.
|
|
|
|
* @param {DOMTokenList} classList passed in from the HTMLBars template
|
|
|
|
* currentTarget.classList
|
|
|
|
*/
|
|
|
|
willEditUserName(classList) {
|
|
|
|
// Add the className so the input element is visible in the DOM
|
|
|
|
classList.add(userNameEditableClass);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mutates the owner.userName property, setting it to the value entered
|
|
|
|
* in the table field
|
|
|
|
* @param {Object} owner the owner object rendered for this table row
|
|
|
|
* @param {String|void} value user entered value from the ui
|
|
|
|
* @param {Node} parentNode DOM node wrapping the target user input field
|
|
|
|
* this is expected to be a TD node
|
|
|
|
*/
|
2017-03-26 16:03:25 -07:00
|
|
|
editUserName(owner, { target: { value, parentNode = {} } }) {
|
|
|
|
const { nodeName, classList } = parentNode;
|
2017-03-25 22:11:20 -07:00
|
|
|
if (value) {
|
|
|
|
set(owner, 'userName', value);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The containing TD should have the className that allows the user
|
|
|
|
// to see the input element, remove this to revert to readonly mode
|
|
|
|
if (String(nodeName).toLowerCase() === 'td') {
|
|
|
|
classList.remove(userNameEditableClass);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2017-03-26 13:52:37 -07:00
|
|
|
/**
|
|
|
|
* Adds a candidate owner to the list of updated owners to be potentially
|
|
|
|
* propagated to the server.
|
|
|
|
* If the owner already exists in the list of currentOwners, this is a no-op.
|
|
|
|
* Also, sets the errorMessage to reflect this occurrence.
|
|
|
|
* @return {Array.<Object>|void}
|
|
|
|
*/
|
2017-03-26 16:03:25 -07:00
|
|
|
addOwner() {
|
2017-03-26 13:52:37 -07:00
|
|
|
// Make a copy of the list of current owners
|
|
|
|
const currentOwners = [...getWithDefault(this, 'owners', [])];
|
|
|
|
// Make a shallow copy for the new user. A shallow copy is fine,
|
|
|
|
// since the properties are scalars.
|
|
|
|
const newOwner = Object.assign({}, _defaultOwnerProps);
|
|
|
|
// Case insensitive regular exp to check that the username is not in
|
|
|
|
// the current list of owners
|
|
|
|
const regex = new RegExp(`.*${newOwner.userName}.*`, 'i');
|
|
|
|
let updatedOwners = [];
|
|
|
|
|
2017-03-26 16:03:25 -07:00
|
|
|
const ownerAlreadyExists = currentOwners
|
|
|
|
.mapBy('userName')
|
|
|
|
.some(userName => regex.test(userName));
|
2017-03-26 13:52:37 -07:00
|
|
|
|
|
|
|
if (!ownerAlreadyExists) {
|
|
|
|
updatedOwners = [newOwner, ...currentOwners];
|
|
|
|
return set(this, 'owners', updatedOwners);
|
2017-02-13 14:50:13 -08:00
|
|
|
}
|
2017-03-26 13:52:37 -07:00
|
|
|
|
|
|
|
set(
|
|
|
|
this,
|
|
|
|
'errorMessage',
|
|
|
|
`Uh oh! There is already a user with the username ${newOwner.userName} in the list of owners.`
|
|
|
|
);
|
|
|
|
|
|
|
|
// TODO: refactor in next commit
|
2017-03-26 16:03:25 -07:00
|
|
|
setTimeout(
|
|
|
|
function() {
|
2017-03-26 13:52:37 -07:00
|
|
|
// setOwnerNameAutocomplete(controller)
|
2017-03-26 16:03:25 -07:00
|
|
|
},
|
|
|
|
500
|
|
|
|
);
|
2017-02-13 14:50:13 -08:00
|
|
|
},
|
2017-03-26 13:52:37 -07:00
|
|
|
|
2017-03-26 16:03:25 -07:00
|
|
|
/**
|
|
|
|
* Removes the provided owner from the current owners array. Pretty simple.
|
|
|
|
* @param {Object} owner
|
|
|
|
* @returns {any|Ember.Array|{}}
|
|
|
|
*/
|
|
|
|
removeOwner(owner) {
|
|
|
|
return getWithDefault(this, 'owners', []).removeObject(owner);
|
2017-02-13 14:50:13 -08:00
|
|
|
},
|
2017-03-26 06:36:23 -07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the checked confirmedBy property on an owner, when the user
|
|
|
|
* indicates this thought the UI, and if their username is
|
|
|
|
* available.
|
|
|
|
* @param {Object} owner the owner object to update
|
|
|
|
* @prop {String|null|void} owner.confirmedBy flag indicating userName
|
|
|
|
* that confirmed ownership, or null or void otherwise
|
|
|
|
* @param {Boolean = false} checked flag for the current ui checked state
|
|
|
|
*/
|
2017-03-26 16:03:25 -07:00
|
|
|
confirmOwner(owner, { target: { checked } = false }) {
|
2017-03-26 06:36:23 -07:00
|
|
|
// Attempt to get the userName from the currentUser service
|
2017-03-26 16:03:25 -07:00
|
|
|
const userName = get(this, 'loggedInUserName').call(this);
|
2017-03-26 06:36:23 -07:00
|
|
|
|
|
|
|
// If checked, assign userName otherwise, null
|
|
|
|
const isConfirmedBy = checked ? userName : null;
|
|
|
|
const currentOwners = get(this, 'owners');
|
|
|
|
|
|
|
|
// Ensure that the provided owner is in the list of currentOwners
|
|
|
|
if (currentOwners.includes(owner)) {
|
|
|
|
const ownerPosition = currentOwners.indexOf(owner);
|
|
|
|
// If we have a non blank userName in confirmedBy
|
|
|
|
// assign to owner, otherwise assign a toggled blank.
|
|
|
|
// A toggled blank is necessary as a state change device, since
|
|
|
|
// Ember does a deep comparison of object properties when deciding
|
|
|
|
// to perform a re-render. We could also use a device such as a hidden
|
|
|
|
// field with a randomized value.
|
|
|
|
// This helps to ensure our UI checkbox is consistent with our world
|
|
|
|
// state.
|
|
|
|
const currentConfirmation = get(owner, 'confirmedBy');
|
|
|
|
let nextBlank = currentConfirmation === null ? void 0 : null;
|
|
|
|
|
|
|
|
set(owner, 'confirmedBy', isConfirmedBy ? isConfirmedBy : nextBlank);
|
|
|
|
|
|
|
|
// Non-mutative array insertion
|
|
|
|
const updatedOwners = [
|
|
|
|
...currentOwners.slice(0, ownerPosition),
|
|
|
|
owner,
|
|
|
|
...currentOwners.slice(ownerPosition + 1)
|
|
|
|
];
|
|
|
|
|
|
|
|
currentOwners.setObjects(updatedOwners);
|
2017-02-13 14:50:13 -08:00
|
|
|
}
|
|
|
|
},
|
2017-03-26 06:36:23 -07:00
|
|
|
|
2017-03-26 16:03:25 -07:00
|
|
|
/**
|
|
|
|
* Invokes the passed in `save` closure action with the current list of owners.
|
|
|
|
* @returns {boolean|Promise.<TResult>|*}
|
|
|
|
*/
|
|
|
|
updateOwners() {
|
|
|
|
const closureAction = get(this, 'attrs.save');
|
|
|
|
|
|
|
|
return typeof closureAction === 'function' &&
|
|
|
|
closureAction(get(this, 'owners'))
|
|
|
|
.then(({
|
|
|
|
status
|
|
|
|
} = {}) => {
|
|
|
|
if (status === 'ok') {
|
|
|
|
set(
|
|
|
|
this,
|
|
|
|
'actionMessage',
|
|
|
|
'Successfully updated ownership for this dataset'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.catch(({ msg }) =>
|
|
|
|
set(
|
|
|
|
this,
|
|
|
|
'errorMessage',
|
|
|
|
`An error occurred while saving. Please let us know of this incident. ${msg}`
|
|
|
|
));
|
2017-02-13 14:50:13 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|