diff --git a/app/workgroup/directives/modals/addPlaceholderUser/addPlaceholderUser.css b/app/workgroup/directives/modals/addPlaceholderUser/addPlaceholderUser.css
new file mode 100644
index 000000000..803fc63fc
--- /dev/null
+++ b/app/workgroup/directives/modals/addPlaceholderUser/addPlaceholderUser.css
@@ -0,0 +1,60 @@
+.add-placeholder-user__input {
+ width: 30%;
+ padding-left: 10px;
+ padding-top: 10px;
+}
+
+.add-placeholder-user__label {
+ padding-left: 20px;
+ font-weight: bold;
+}
+
+.add-placeholder-user__footer {
+ display: flex;
+ justify-content: flex-end;
+ margin-top: 20px;
+ padding: 10px;
+ padding-bottom: 15px;
+ padding-top: 15px;
+ background-color: rgb(248, 248, 248);
+}
+
+.add-placeholder-user__warning {
+ padding: 10px;
+ color: gray;
+}
+
+.add-placeholder-users__input-container {
+ display: flex;
+}
+
+
+.add-placeholder-user .neon-dark-confirm-btn,
+.add-placeholder-user .neon-dark-confirm-btn:focus,
+.add-placeholder-user .neon-dark-confirm-btn:active,
+.add-placeholder-user .neon-dark-confirm-btn {
+ background-color: rgb(48, 54, 65);
+ border-color: rgb(48, 54, 65);
+ color: white;
+}
+
+.add-placeholder-user .neon-dark-confirm-btn:hover {
+ background-color: rgb(18, 24, 35); /* Darker Version for hover */
+ color: white;
+}
+
+.add-placeholder-user .neon-dark-confirm-btn.disabled,
+.add-placeholder-user .neon-dark-confirm-btn.disabled:hover,
+.add-placeholder-user .neon-dark-confirm-btn.disabled:focus,
+.add-placeholder-user .neon-dark-confirm-btn.disabled:active {
+ background-color: rgb(48, 54, 65);
+ color: white;
+}
+
+.add-placeholder-user__cancel-button {
+ margin-right: 5px;
+ margin-left: 5px;
+ color: #303641;
+ background-color: white;
+ border: 1px solid #D6D6D6;
+}
diff --git a/app/workgroup/directives/modals/addPlaceholderUser/addPlaceholderUser.html b/app/workgroup/directives/modals/addPlaceholderUser/addPlaceholderUser.html
new file mode 100644
index 000000000..55596d240
--- /dev/null
+++ b/app/workgroup/directives/modals/addPlaceholderUser/addPlaceholderUser.html
@@ -0,0 +1,44 @@
+
+
+ Please note: This form should only be used to add a user if they do NOT have a kerberos account yet.
+
+ This user will not be able to login to IPA (until you provide the kerberos login id),
+ but you will be able to refer to them in IPA and include them in your scheduling plans.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/workgroup/directives/modals/addPlaceholderUser/addPlaceholderUser.js b/app/workgroup/directives/modals/addPlaceholderUser/addPlaceholderUser.js
new file mode 100644
index 000000000..c684d1141
--- /dev/null
+++ b/app/workgroup/directives/modals/addPlaceholderUser/addPlaceholderUser.js
@@ -0,0 +1,66 @@
+import './addPlaceholderUser.css';
+
+let addPlaceholderUser = function (WorkgroupActionCreators) {
+ return {
+ restrict: 'E',
+ template: require('./addPlaceholderUser.html'),
+ replace: true,
+ scope: {
+ isVisible: '='
+ },
+ link: function (scope) {
+ scope.view = {
+ firstName: "",
+ lastName: "",
+ email: "",
+ validationMessage: ""
+ };
+
+ scope.addPlaceholderUser = function() {
+ var user = {
+ firstName: scope.view.firstName,
+ lastName: scope.view.lastName,
+ email: scope.view.email
+ };
+
+ WorkgroupActionCreators.addPlaceholderUser(user);
+ scope.close();
+ };
+
+ scope.isPlaceholderUserValid = function() {
+ if (
+ !scope.view.firstName &&
+ !scope.view.lastName &&
+ !scope.view.email
+ ) {
+ scope.view.validationMessage = "";
+ return false;
+ }
+
+ if (!scope.view.firstName) {
+ scope.view.validationMessage = "First name is required";
+ return false;
+ }
+
+ if (!scope.view.lastName) {
+ scope.view.validationMessage = "Last name is required";
+ return false;
+ }
+
+ if (!scope.view.email) {
+ scope.view.validationMessage = "Email is required";
+ return false;
+ }
+
+ scope.view.validationMessage = "";
+ return true;
+ };
+
+ scope.close = function () {
+ scope.isVisible = false;
+ };
+ } // end link
+ };
+};
+
+export default addPlaceholderUser;
diff --git a/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.css b/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.css
index 4ba2a39d7..11a2a3bed 100644
--- a/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.css
+++ b/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.css
@@ -73,3 +73,47 @@
padding: 10px;
color: #aaabae;
}
+
+.roles-table__placeholder-update-validation {
+ padding-top: 2px;
+ padding-bottom: 2px;
+ min-height: 1.3em;
+ line-height: 1;
+ color: gray;
+}
+
+.roles-table__placeholder {
+ color: #ffeb3c;
+ border: 1px solid;
+ border-radius: 4px;
+ font-size: 15px;
+ padding-top: 3px;
+ padding-left: 4px;
+ padding-right: 4px;
+ padding-bottom: 3px;
+}
+
+.roles-table__update-placeholder-ui {
+ padding-top: 5px;
+}
+
+.roles-table__update-placeholder-container {
+ display: flex;
+}
+
+.roles-table__update-placeholder-input {
+ margin-left: -5px;
+}
+
+.roles-table__update-placeholder-buttons {
+ padding-right: 2px;
+}
+
+.roles-table__placeholder-person-ui {
+ display: flex;
+ justify-content: flex-end;
+}
+
+.roles-table__match {
+ border-bottom:1px solid #f3f3f3;
+}
diff --git a/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.html b/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.html
index f839fd8bf..b5f7ec19d 100644
--- a/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.html
+++ b/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.html
@@ -7,23 +7,58 @@
ng-change="searchOnChange()" typeahead-loading="view.loadingPeople" typeahead-no-results="view.noResults"
typeahead-wait-ms="400" typeahead-min-length="2" typeahead-on-select="searchUsersResultSelected($item, $model, $label, $event)"
class="form-control typeahead"
- typeahead-template-url="popupTemplate.html">
-
-
+ typeahead-popup-template-url="popupTemplate.html">
+
-
+
+
+
+
+
+
+
- {{ userRole.userDisplayName }}
+
+ {{ userRole.userDisplayName }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Update
+
+
+ Update
+
+
+
+
+
+ Cancel
+
+
+
+
+ {{ view.placeholderUpdate.validationMessage }}
+
+
diff --git a/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.js b/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.js
index 97272c9ca..cda9628cd 100644
--- a/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.js
+++ b/app/workgroup/directives/peopleAndRoles/rolesTable/rolesTable.js
@@ -1,56 +1,120 @@
-import './rolesTable.css';
-
-let rolesTable = function ($rootScope, WorkgroupActionCreators, WorkgroupService) {
- return {
- restrict: 'E',
- template: require('./rolesTable.html'),
- replace: true,
- scope: {
- userRoles: '<',
- activeRoleId: '<',
- users: '<',
- ui: '<'
- },
- link: function(scope) {
- scope.view = {
- loadingPeople: false,
- noResults: false
- };
-
- scope.removeUserRole = function (userRole) {
- WorkgroupActionCreators.removeRoleFromUser(userRole.userId, userRole.roleId, userRole);
- };
-
- scope.clearUserSearch = function () {
- scope.users.newUser = {};
- scope.users.searchQuery = "";
- scope.view.noResults = false;
- };
-
- scope.searchOnChange = function () {
- scope.view.noResults = false;
- scope.users.newUser = {};
- };
-
- scope.searchUsers = function (query) {
- return WorkgroupService.searchUsers(scope.ui.workgroupId, query).then(function (userSearchResults) {
- return userSearchResults;
- }, function () {
- $rootScope.$emit('toast', {message: "Could not search users.", type: "ERROR"});
- });
- };
-
- scope.searchUsersResultSelected = function ($item) {
- scope.users.newUser = $item;
- };
-
- scope.addUserToWorkgroup = function() {
- scope.users.newUser;
- WorkgroupActionCreators.createUser(scope.ui.workgroupId, scope.users.newUser, scope.activeRoleId);
- scope.clearUserSearch();
- };
- }
- };
+import "./rolesTable.css";
+
+let rolesTable = function(
+ $rootScope,
+ WorkgroupActionCreators,
+ WorkgroupService
+) {
+ return {
+ restrict: "E",
+ template: require("./rolesTable.html"),
+ replace: true,
+ scope: {
+ userRoles: "<",
+ activeRoleId: "<",
+ users: "<",
+ ui: "<"
+ },
+ link: function(scope) {
+ scope.view = {
+ loadingPeople: false,
+ noResults: false,
+ placeholderUpdate: {
+ show: false,
+ loginId: "",
+ validationMessage: ""
+ }
+ };
+
+ scope.openPlaceholderModal = function () {
+ WorkgroupActionCreators.openPlaceholderModal();
+ };
+
+ scope.removeUserRole = function(userRole) {
+ WorkgroupActionCreators.removeRoleFromUser(
+ userRole.userId,
+ userRole.roleId,
+ userRole
+ );
+ };
+
+ scope.openPlaceholderUpdateUI = function () {
+ scope.view.placeholderUpdate.show = true;
+ };
+
+ scope.closePlaceholderUpdateUI = function () {
+ scope.view.placeholderUpdate.show = false;
+ scope.view.placeholderUpdate.loginId = "";
+ scope.view.placeholderUpdate.validationMessage = "";
+ scope.view.placeholderUpdate.isValid = false;
+ scope.view.placeholderUpdate.dwUser = null;
+ };
+
+ scope.isPlaceholderUpdateValid = function () {
+ scope.searchUsers(scope.view.placeholderUpdate.loginId).then(function(results) {
+ if (results.length == 1) {
+ scope.view.placeholderUpdate.validationMessage = results[0].name + '(' + results[0].email + ')';
+ scope.view.placeholderUpdate.isValid = true;
+ scope.view.placeholderUpdate.dwUser = results[0];
+ } else {
+ scope.view.placeholderUpdate.validationMessage = "No users with that loginid found";
+ scope.view.placeholderUpdate.isValid = false;
+ }
+ });
+ };
+
+ scope.updatePlaceholderUser = function (userRole) {
+ WorkgroupActionCreators.updatePlaceholderUser(scope.view.placeholderUpdate.dwUser, userRole.userLoginId);
+ };
+
+ scope.clearUserSearch = function() {
+ scope.users.newUser = {};
+ scope.users.searchQuery = "";
+ scope.view.noResults = false;
+ };
+
+ scope.searchOnChange = function() {
+ scope.view.noResults = false;
+ scope.users.newUser = {};
+ };
+
+ scope.searchUsers = function(query) {
+ return WorkgroupService.searchUsers(scope.ui.workgroupId, query).then(
+ function(userSearchResults) {
+ userSearchResults.push({
+ name: "newPlaceholder"
+ });
+ return userSearchResults;
+ },
+ function() {
+ $rootScope.$emit("toast", {
+ message: "Could not search users.",
+ type: "ERROR"
+ });
+ }
+ );
+ };
+
+ scope.searchUsersResultSelected = function($item) {
+ if ($item.name == "newPlaceholder") {
+ scope.openPlaceholderModal();
+ scope.users.searchQuery = "";
+ } else {
+ scope.users.newUser = $item;
+ }
+ };
+
+ scope.addUserToWorkgroup = function() {
+ scope.users.newUser;
+ WorkgroupActionCreators.createUser(
+ scope.ui.workgroupId,
+ scope.users.newUser,
+ scope.activeRoleId
+ );
+ scope.clearUserSearch();
+ };
+ }
+ };
};
export default rolesTable;
diff --git a/app/workgroup/services/workgroupActionCreators.js b/app/workgroup/services/workgroupActionCreators.js
index e4d0ce07c..b6c24feaf 100644
--- a/app/workgroup/services/workgroupActionCreators.js
+++ b/app/workgroup/services/workgroupActionCreators.js
@@ -54,6 +54,49 @@ class WorkgroupActionCreators {
$rootScope.$emit('toast', { message: "Could not update instructor type", type: "ERROR" });
});
},
+ openPlaceholderModal: function () {
+ WorkgroupStateService.reduce({
+ type: ActionTypes.OPEN_PLACEHOLDER_MODAL,
+ payload: {}
+ });
+ },
+ addPlaceholderUser: function (placeholderUser) {
+ var _this = this;
+
+ var roleId = WorkgroupStateService._state.ui.roles.activeRoleId;
+ var workgroupId = parseInt(WorkgroupStateService._state.ui.workgroupId);
+
+ WorkgroupService.addPlaceholderUser(placeholderUser, workgroupId).then(function (newUser) {
+ WorkgroupStateService.reduce({
+ type: ActionTypes.ADD_USER_COMPLETED,
+ payload: {
+ user: newUser
+ }
+ });
+ $rootScope.$emit('toast', { message: "Added user", type: "SUCCESS" });
+
+ var role = new Role({ name: WorkgroupStateService._state.roles.list[roleId].name });
+ _this.addRoleToUser(workgroupId, newUser, new Role({ name: "presence"}));
+ _this.addRoleToUser(workgroupId, newUser, role);
+ }, function () {
+ $rootScope.$emit('toast', { message: "Could not add user.", type: "ERROR" });
+ });
+ },
+ updatePlaceholderUser: function (user, previousLoginId) {
+ var _this = this;
+ var workgroupId = parseInt(WorkgroupStateService._state.ui.workgroupId);
+
+ WorkgroupService.updatePlaceholderUser(user, previousLoginId, workgroupId).then(function (newUser) {
+ WorkgroupStateService.reduce({
+ type: ActionTypes.UPDATE_USER,
+ payload: {
+ user: newUser
+ }
+ });
+ $rootScope.$emit('toast', { message: "Updated user", type: "SUCCESS" });
+ _this._calculateUserRoles();
+ });
+ },
addTag: function (workgroupId, tag) {
WorkgroupService.addTag(workgroupId, tag).then(function (newTag) {
$rootScope.$emit('toast', { message: "Created tag " + newTag.name, type: "SUCCESS" });
@@ -321,6 +364,7 @@ class WorkgroupActionCreators {
workgroupId: userRole.workgroupId,
userDisplayName: user.name,
userId: user.id,
+ userIsPlaceholder: user.placeholder,
userLoginId: user.loginId,
userEmail: user.email,
displayPresence: shouldDisplayPresence,
diff --git a/app/workgroup/services/workgroupService.js b/app/workgroup/services/workgroupService.js
index 824cf00c1..0367ddd9a 100644
--- a/app/workgroup/services/workgroupService.js
+++ b/app/workgroup/services/workgroupService.js
@@ -51,6 +51,12 @@ class WorkgroupService {
updateUserRole: function (userRole) {
return ApiService.put("/api/workgroupView/userRoles/" + userRole.id + "/roles/" + userRole.roleId);
},
+ addPlaceholderUser: function (placeholderUser, workgroupId) {
+ return ApiService.post("/api/workgroups/" + workgroupId + "/users/placeholder/", placeholderUser);
+ },
+ updatePlaceholderUser: function (user, previousLoginId, workgroupId) {
+ return ApiService.put("/api/workgroups/" + workgroupId + "/users/placeholder/" + previousLoginId, user);
+ }
};
}
}
diff --git a/app/workgroup/services/workgroupStateService.js b/app/workgroup/services/workgroupStateService.js
index 0827b164e..a8f9b6503 100644
--- a/app/workgroup/services/workgroupStateService.js
+++ b/app/workgroup/services/workgroupStateService.js
@@ -155,6 +155,9 @@ class WorkgroupStateService {
users.userSearchResults = [];
users.searchQuery = "";
return users;
+ case ActionTypes.UPDATE_USER:
+ users.list[action.payload.user.id] = new User(action.payload.user);
+ return users;
case ActionTypes.REMOVE_USER:
userIndex = users.ids.indexOf(action.payload.user.id);
users.ids.splice(userIndex, 1);
@@ -227,6 +230,7 @@ class WorkgroupStateService {
switch (action.type) {
case ActionTypes.INIT_WORKGROUP:
ui = {
+ isAddPlaceholderModalOpen: false,
addUserPending: false,
workgroupId: action.workgroupId,
roles: {
@@ -255,6 +259,9 @@ class WorkgroupStateService {
ui.instructorTypes.push(instructorType);
});
return ui;
+ case ActionTypes.OPEN_PLACEHOLDER_MODAL:
+ ui.isAddPlaceholderModalOpen = true;
+ return ui;
case ActionTypes.SET_ROLE_TAB:
ui.roles.activeRoleTab = action.payload.activeRoleTab;
ui.roles.activeRoleId = action.payload.activeRoleId;
diff --git a/app/workgroup/templates/WorkgroupCtrl.html b/app/workgroup/templates/WorkgroupCtrl.html
index 885326d1a..51cb1efff 100644
--- a/app/workgroup/templates/WorkgroupCtrl.html
+++ b/app/workgroup/templates/WorkgroupCtrl.html
@@ -12,6 +12,13 @@
+
+
+
+
+
diff --git a/app/workgroup/workgroupApp.js b/app/workgroup/workgroupApp.js
index a66c0024e..3303c1c27 100644
--- a/app/workgroup/workgroupApp.js
+++ b/app/workgroup/workgroupApp.js
@@ -21,6 +21,7 @@ import rolesTable from './directives/peopleAndRoles/rolesTable/rolesTable.js';
import instructorTypeSelector from './directives/peopleAndRoles/rolesTable/instructorTypeSelector/instructorTypeSelector.js';
import studentRoleSelector from './directives/peopleAndRoles/rolesTable/studentRoleSelector/studentRoleSelector.js';
import impersonationModal from './directives/modals/impersonationModal/impersonationModal.js';
+import addPlaceholderUser from './directives/modals/addPlaceholderUser/addPlaceholderUser.js';
// Dependencies
var dependencies = [
@@ -84,6 +85,7 @@ const workgroupApp = angular.module("workgroupApp", dependencies) // eslint-disa
.directive('instructorTypeSelector', instructorTypeSelector)
.directive('studentRoleSelector', studentRoleSelector)
.directive('impersonationModal', impersonationModal)
+.directive('addPlaceholderUser', addPlaceholderUser)
.constant('ActionTypes', {
ADD_TAG: "ADD_TAG",
REMOVE_TAG: "REMOVE_TAG",
@@ -101,7 +103,9 @@ const workgroupApp = angular.module("workgroupApp", dependencies) // eslint-disa
UPDATE_USER_ROLE: "UPDATE_USER_ROLE",
SET_ROLE_TAB: "SET_ROLE_TAB",
CALCULATE_USER_ROLES: "CALCULATE_USER_ROLES",
- CALCULATE_ROLE_TOTALS: "CALCULATE_ROLE_TOTALS"
+ CALCULATE_ROLE_TOTALS: "CALCULATE_ROLE_TOTALS",
+ UPDATE_USER: "UPDATE_USER",
+ OPEN_PLACEHOLDER_MODAL: "OPEN_PLACEHOLDER_MODAL"
});
export default workgroupApp;