// require('../tests/stories/sshKeyCard');
// require('../tests/stories/button');
// require('../tests/stories/sq-input-slider');
- require('../tests/stories/catalogCard');
+ // require('../tests/stories/catalogCard');
+ require('../tests/stories/inputs');
// require as many stories as you need.
}
configure(loadStories, module);
+
+
constants.SOCKET_POOL_LENGTH = 20;
constants.SERVER_PORT = process.env.SERVER_PORT || 8000;
constants.SECURE_SERVER_PORT = process.env.SECURE_SERVER_PORT || 8443;
+constants.REJECT_UNAUTHORIZED = false;
constants.BASE_PACKAGE_UPLOAD_DESTINATION = 'upload/packages/';
constants.PACKAGE_MANAGER_SERVER_PORT = 4567;
var sockjs = require('sockjs');
var websocket_multiplex = require('websocket-multiplex');
var utils = require('./utils.js');
+var configurationAPI = require('../modules/api/configuration.js');
var Subscriptions = function() {
var a = url.resolve(origin, req.baseUrl);
var b = url.resolve(a, URL);
URL = b;
- console.log('DEBUG URL IS', URL);
} else {
protocol = protocol[1]
}
self.isClosed = false;
var requestHeaders = {};
_.extend(requestHeaders, {
- 'Authorization': req.get('Authorization')
+ Cookie: req.get('Cookie')
});
var pollServer = function() {
Request({
- url: url,
+ url: utils.projectContextUrl(req, url),
method: config.method || 'GET',
headers: requestHeaders,
json: config.payload,
return api_server + ':' + CONFD_PORT;
};
+var projectContextUrl = function(req, url) {
+ //NOTE: We need to go into the sessionStore because express-session
+ // does not reliably update the session.
+ // See https://github.com/expressjs/session/issues/450
+ var projectId = (req.session &&
+ req.sessionStore &&
+ req.sessionStore.sessions &&
+ req.sessionStore.sessions[req.session.id] &&
+ JSON.parse(req.sessionStore.sessions[req.session.id])['projectId']) ||
+ (null);
+ if (projectId) {
+ return url.replace(/(\/api\/operational\/|\/api\/config\/)(.*)/, '$1project/' + projectId + '/$2');
+ }
+ return url;
+}
+
+var addProjectContextToRPCPayload = function(req, url, inputPayload) {
+ //NOTE: We need to go into the sessionStore because express-session
+ // does not reliably update the session.
+ // See https://github.com/expressjs/session/issues/450
+ var projectId = (req.session &&
+ req.sessionStore &&
+ req.sessionStore.sessions &&
+ req.sessionStore.sessions[req.session.id] &&
+ JSON.parse(req.sessionStore.sessions[req.session.id])['projectId']) ||
+ (null);
+ if (projectId) {
+ if (url.indexOf('/api/operations/')) {
+ inputPayload['project-name'] = projectId;
+ }
+ }
+ return inputPayload;
+}
+
var validateResponse = function(callerName, error, response, body, resolve, reject) {
var res = {};
};
reject(res);
return false;
- } else if (response.statusCode >= 400) {
+ } else if (response.statusCode >= CONSTANTS.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST) {
console.log('Problem with "', callerName, '": ', response.statusCode, ':', body);
res.statusCode = response.statusCode;
// auth specific
- if (response.statusCode == 401) {
+ if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.ERROR.UNAUTHORIZED) {
res.errorMessage = {
error: 'Authentication needed' + body
};
reject(res);
return false;
- } else if (response.statusCode == 204) {
+ } else if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
resolve({
statusCode: response.statusCode,
data: {}
var checkAuthorizationHeader = function(req) {
return new Promise(function(resolve, reject) {
- if (req.get('Authorization') == null) {
+ if (req.session && req.session.authorization == null) {
reject();
} else {
resolve();
reject(res);
fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error: ' + error);
return false;
- } else if (response.statusCode >= 400) {
+ } else if (response.statusCode >= CONSTANTS.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST) {
console.log('Problem with "', callerName, '": ', response.statusCode, ':', body);
res.statusCode = response.statusCode;
// auth specific
- if (response.statusCode == 401) {
+ if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.ERROR.UNAUTHORIZED) {
res.errorMessage = {
error: 'Authentication needed' + body
};
reject(res);
fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Error Body: ' + body);
return false;
- } else if (response.statusCode == 204) {
+ } else if (response.statusCode == CONSTANTS.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
resolve();
fs.appendFileSync(logFile, 'Request API: ' + response.request.uri.href + ' ; ' + 'Response Body: ' + body);
return false;
}
new Promise(function(resolve, reject) {
request({
- uri: uri,
+ uri: projectContextUrl(req, uri),
method: 'GET',
headers: _.extend({}, CONSTANTS.HTTP_HEADERS.accept[type], {
- 'Authorization': req.get('Authorization'),
+ 'Authorization': req.session && req.session.authorization,
forever: CONSTANTS.FOREVER_ON,
rejectUnauthorized: false,
})
passThroughConstructor: passThroughConstructor,
- getPortForProtocol: getPortForProtocol
+ getPortForProtocol: getPortForProtocol,
+
+ projectContextUrl: projectContextUrl,
+
+ addProjectContextToRPCPayload: addProjectContextToRPCPayload
};
uri: utils.confdPort(api_server) + '/api/schema/nsd-catalog/nsd',
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
uri: utils.confdPort(api_server) + '/api/schema/vnfd-catalog/vnfd',
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// DescriptorModelMeta API (NSD + VNFD)
+
+
+var ProjectManagement = {};
+var Promise = require('bluebird');
+var rp = require('request-promise');
+var Promise = require('promise');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var _ = require('lodash');
+
+ProjectManagement.get = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ rp({
+ uri: utils.confdPort(api_server) + '/api/operational/project',
+ method: 'GET',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session && req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ })
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ response['data']['project'] = JSON.parse(result[0].body)['rw-project:project'];
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with ProjectManagement.get', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to get ProjectManagement' + error
+ };
+ reject(response);
+ });
+ });
+};
+
+ProjectManagement.create = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ var data = req.body;
+ data = {
+ "project":[data]
+ }
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ rp({
+ uri: utils.confdPort(api_server) + '/api/config/project',
+ method: 'POST',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session && req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ json: data,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ })
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ response['data'] = result[0].body;
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with ProjectManagement.create', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to create user' + error
+ };
+ reject(response);
+ });
+ });
+};
+ProjectManagement.update = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ var bodyData = req.body;
+ data = {
+ "project":[bodyData]
+ }
+ var updateTasks = [];
+
+ var updateUser = rp({
+ uri: utils.confdPort(api_server) + '/api/config/project',
+ method: 'PUT',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session && req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ json: data,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ });
+ updateTasks.push(updateUser)
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ updateTasks
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ response['data'] = result[0].body;
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with ProjectManagement.update', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to passwordChange user' + error
+ };
+ reject(response);
+ });
+ });
+};
+
+ProjectManagement.delete = function(req) {
+ var self = this;
+ var projectname = req.params.projectname;
+ var api_server = req.query["api_server"];
+ var requestHeaders = {};
+ var url = `${utils.confdPort(api_server)}/api/config/project/${projectname}`
+ return new Promise(function(resolve, reject) {
+ _.extend(requestHeaders,
+ constants.HTTP_HEADERS.accept.data,
+ constants.HTTP_HEADERS.content_type.data, {
+ 'Authorization': req.session && req.session.authorization
+ });
+ rp({
+ url: url,
+ method: 'DELETE',
+ headers: requestHeaders,
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: false,
+ }, function(error, response, body) {
+ if (utils.validateResponse('ProjectManagement.DELETE', error, response, body, resolve, reject)) {
+ return resolve({
+ statusCode: response.statusCode,
+ data: JSON.stringify(response.body)
+ });
+ };
+ });
+ })
+}
+
+
+ProjectManagement.getPlatform = function(req, userId) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ var user = req.params['userId'] || userId;
+ return new Promise(function(resolve, reject) {
+ var url = utils.confdPort(api_server) + '/api/operational/rbac-platform-config';
+ if(user) {
+ url = url + '/user/' + user;
+ }
+ Promise.all([
+ rp({
+ uri: url,
+ method: 'GET',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session && req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ })
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ if(user) {
+ response['data']['platform'] = JSON.parse(result[0].body)['rw-rbac-platform:user'];
+ } else {
+ response['data']['platform'] = JSON.parse(result[0].body)['rw-rbac-platform:rbac-platform-config'];
+ }
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with ProjectManagement.getPlatform', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to get ProjectManagement.getPlatform' + error
+ };
+ reject(response);
+ });
+ });
+};
+
+ProjectManagement.updatePlatform = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ var bodyData = req.body;
+ data = bodyData;
+ data.user = JSON.parse(data.user)
+ var updateTasks = [];
+
+ var updateUser = rp({
+ uri: utils.confdPort(api_server) + '/api/config/rbac-platform-config',
+ method: 'PUT',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session && req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ json: data,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ });
+ updateTasks.push(updateUser)
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ updateTasks
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ response['data'] = result[0].body;
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with ProjectManagement.updatePlatform', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to passwordChange user' + error
+ };
+ reject(response);
+ });
+ });
+};
+
+
+module.exports = ProjectManagement;
url: uri + url + '?deep',
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * sessions api module. Provides API functions for sessions
+ * @module framework/core/modules/api/sessions
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ */
+
+var Promise = require('bluebird');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var request = utils.request;
+var rp = require('request-promise');
+var sessionsAPI = {};
+var _ = require('lodash');
+var base64 = require('base-64');
+var APIVersion = '/v2';
+var configurationAPI = require('./configuration');
+
+function logAndReject(mesg, reject, errCode) {
+ res.errorMessage = {
+ error: mesg
+ }
+ res.statusCode = errCode || constants.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST;
+ console.log(mesg);
+ reject(res);
+}
+
+function logAndRedirectToLogin(mesg, res, req) {
+ var api_server = req.query['api_server'] || (req.protocol + '://' + configurationAPI.globalConfiguration.get().api_server);
+ var upload_server = req.protocol + '://' + (configurationAPI.globalConfiguration.get().upload_server || req.hostname);
+ console.log(mesg);
+ res.redirect('login.html?api_server=' + api_server + '&upload_server=' + upload_server + '&referer=' + req.headers.referer);
+ res.end();
+}
+
+sessionsAPI.create = function(req, res) {
+ var api_server = req.query["api_server"];
+ var uri = utils.confdPort(api_server);
+ var login_url = uri + APIVersion + '/api/login';
+ var project_url = uri + APIVersion + '/api/operational/project';
+ var authorization_header_string = 'Basic ' + base64.encode(req.body['username'] + ':' + req.body['password']);
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ rp({
+ url: login_url,
+ method: 'POST',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': authorization_header_string
+ }),
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: constants.REJECT_UNAUTHORIZED,
+ resolveWithFullResponse: true
+ }),
+ rp({
+ url: project_url,
+ method: 'GET',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
+ 'Authorization': authorization_header_string
+ }),
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: constants.REJECT_UNAUTHORIZED,
+ resolveWithFullResponse: true
+ })
+
+ ]).then(function(results) {
+ // results[0].statusCode => 200/201
+ // results[1].body.collection['rw-project:project'] => List of projects OR 204 with no content
+ if (results[0].statusCode != constants.HTTP_RESPONSE_CODES.SUCCESS.OK) {
+ var errorMsg = 'Invalid credentials provided!';
+ logAndRedirectToLogin(errorMsg, res, req);
+ return;
+ }
+
+ var username = req.body['username'];
+ var project_list_for_user = [];
+
+ if (results[1].statusCode == constants.HTTP_RESPONSE_CODES.SUCCESS.NO_CONTENT) {
+ console.log('No projects added or user ', username ,' not privileged to view projects.');
+ } else {
+ // go through projects and get list of projects that this user belongs to.
+ // pick first one as default project?
+ var isLCM = false;
+ var projects = JSON.parse(results[1].body).collection['rw-project:project'];
+ projects && projects.map(function(project) {
+ project['project-config'] &&
+ project['project-config']['user'] &&
+ project['project-config']['user'].map(function(user) {
+ if (user['user-name'] == username) {
+ project_list_for_user.push(project);
+ user.role.map(function(role) {
+ if(role.role.indexOf('rw-project-mano:lcm') > -1) {
+ isLCM = true;
+ }
+ })
+ }
+ });
+ });
+ if (project_list_for_user.length > 0) {
+ req.session.projectId = project_list_for_user.sort() && project_list_for_user[0].name;
+ req.session.isLCM = isLCM;
+ }
+ }
+
+ req.session.authorization = authorization_header_string;
+ req.session.loggedIn = true;
+ req.session.userdata = {
+ username: username,
+ // project: req.session.projectId
+ };
+ var successMsg = 'User => ' + username + ' successfully logged in.';
+ successMsg += req.session.projectId ? 'Project => ' + req.session.projectId + ' set as default.' : '';
+
+ console.log(successMsg);
+
+ var response = {
+ statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.CREATED,
+ data: JSON.stringify({
+ status: successMsg
+ })
+ };
+
+ req.session.save(function(err) {
+ if (err) {
+ console.log('Error saving session to store', err);
+ }
+ })
+
+ resolve(response);
+
+ }).catch(function(error) {
+ // Something went wrong - Redirect to /login
+ var errorMsg = 'Error logging in or getting list of projects. Error: ' + error;
+ console.log(errorMsg);
+ logAndRedirectToLogin(errorMsg, res, req);
+ });
+ })
+};
+
+sessionsAPI.addProjectToSession = function(req, res) {
+ return new Promise(function(resolve, reject) {
+ if (req.session && req.session.loggedIn == true) {
+ req.session.projectId = req.params.projectId;
+ req.session.save(function(err) {
+ if (err) {
+ console.log('Error saving session to store', err);
+ }
+ var successMsg = 'Added project ' + req.session.projectId + ' to session ' + req.sessionID;
+ console.log(successMsg);
+
+ return resolve ({
+ statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
+ data: JSON.stringify({
+ status: successMsg
+ })
+ });
+
+ var errorMsg = 'Session does not exist or not logged in';
+ logAndReject(errorMsg, reject, constants.HTTP_RESPONSE_CODES.ERROR.NOT_FOUND);
+ });
+ }
+ });
+}
+
+sessionsAPI.delete = function(req, res) {
+ var api_server = req.query["api_server"];
+ var uri = utils.confdPort(api_server);
+ var url = uri + '/api/logout';
+ req.returnTo = req.headers.referer;
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ rp({
+ url: url,
+ method: 'POST',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: constants.REJECT_UNAUTHORIZED,
+ resolveWithFullResponse: true
+ }),
+ new Promise(function(success, failure) {
+ req.session.destroy(function(err) {
+ if (err) {
+ var errorMsg = 'Error deleting session. Error: ' + err;
+ console.log(errorMsg);
+ success({
+ status: 'error',
+ message: errorMsg
+ });
+ }
+
+ var successMsg = 'Success deleting session';
+ console.log(successMsg);
+
+ success({
+ status: 'success',
+ message: successMsg
+ });
+ });
+ })
+ ]).then(function(result) {
+ // assume the session was deleted!
+ var message = 'Session was deleted.'
+ logAndRedirectToLogin(message, res, req);
+
+ }).catch(function(error) {
+ var message = 'Error deleting session or logging out. Error:' + error;
+ logAndRedirectToLogin(message, res, req);
+ });
+ });
+}
+
+
+module.exports = sessionsAPI;
--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+// DescriptorModelMeta API (NSD + VNFD)
+
+
+var UserManagement = {};
+var Promise = require('bluebird');
+var rp = require('request-promise');
+var Promise = require('promise');
+var constants = require('../../api_utils/constants');
+var utils = require('../../api_utils/utils');
+var _ = require('lodash');
+var ProjectManagementAPI = require('./projectManagementAPI.js');
+
+UserManagement.get = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ rp({
+ uri: utils.confdPort(api_server) + '/api/operational/user-config/user',
+ method: 'GET',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session && req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ })
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ response['data']['user'] = JSON.parse(result[0].body)['rw-user:user'];
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with UserManagement.get', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to get UserManagement' + error
+ };
+ reject(response);
+ });
+ });
+};
+
+
+UserManagement.getProfile = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ return new Promise(function(resolve, reject) {
+ var response = {};
+ var userId = req.session.userdata.username
+ response['data'] = {
+ userId: userId,
+ projectId: req.session.projectId
+ };
+ UserManagement.getUserInfo(req, userId).then(function(result) {
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK;
+ response.data.data =result.data
+ resolve(response);
+ }, function(error) {
+ console.log('Error retrieving getUserInfo');
+ response.statusCode = constants.HTTP_RESPONSE_CODES.ERROR.INTERNAL_SERVER_ERROR;
+ reject(response);
+ })
+
+ });
+};
+UserManagement.getUserInfo = function(req, userId, domain) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ var id = req.params['userId'] || userId;
+ var domain = req.params['domainId'] || domain;
+ var response = {};
+ return new Promise(function(resolve, reject) {
+ if (id) {
+ var getProjects = ProjectManagementAPI.get(req)
+ var getPlatformUser = ProjectManagementAPI.getPlatform(req, id)
+ Promise.all([
+ getProjects,
+ getPlatformUser
+ ]).then(function(result) {
+ var userData = {
+ platform: {
+ role: {
+
+ }
+ },
+ //id/key values for each project
+ projectId:[],
+ project: {
+ /**
+ * [projectId] : {
+ * data: [project object],
+ * role: {
+ * [roleId]: true
+ * }
+ * }
+ */
+ }
+ }
+ //Build project roles
+ var projects = result[0].data.project;
+ var userProjects = [];
+ projects && projects.map(function(p, i) {
+ var users = p['project-config'] && p['project-config'].user;
+ userData.projectId.push(p.name);
+ users && users.map(function(u) {
+ if(u['user-name'] == id) {
+ userData.project[p.name] = {
+ data: p,
+ role: {}
+ }
+ u.role && u.role.map(function(r) {
+ userData.project[p.name].role[r.role] = true
+ });
+ }
+ })
+ });
+ //Build platform roles
+ var platformRoles = result[1].data.platform && result[1].data.platform.role;
+ platformRoles && platformRoles.map(function(r) {
+ userData.platform.role[r.role] = true
+ });
+ response.data = userData;
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+ resolve(response);
+ })
+ } else {
+ var errorMsg = 'userId not specified in UserManagement.getUserInfo';
+ console.error(errorMsg);
+ response.statusCode = constants.HTTP_RESPONSE_CODES.ERROR.BAD_REQUEST;
+ response.error = errorMsg;
+ reject(response)
+ }
+
+ })
+}
+UserManagement.create = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ var data = req.body;
+ data = {
+ "user":[data]
+ }
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ rp({
+ uri: utils.confdPort(api_server) + '/api/config/user-config',
+ method: 'POST',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session && req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ json: data,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ })
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ response['data'] = result[0].body;
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with UserManagement.create', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to create user' + error
+ };
+ reject(response);
+ });
+ });
+};
+UserManagement.update = function(req) {
+ var self = this;
+ var api_server = req.query['api_server'];
+ var bodyData = req.body;
+ data = {
+ "user":[bodyData]
+ }
+ var updateTasks = [];
+ if(bodyData.hasOwnProperty('old-password')) {
+ var changePW = rp({
+ uri: utils.confdPort(api_server) + '/api/operations/change-password',
+ method: 'POST',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session && req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ json: {
+ "input": {
+ 'user-name' : bodyData['user-name'],
+ 'user-domain' : bodyData['user-domain'],
+ 'old-password' : bodyData['old-password'],
+ 'new-password' : bodyData['new-password'],
+ 'confirm-password' : bodyData['confirm-password'],
+ }
+ },
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ });
+ updateTasks.push(changePW);
+ };
+ var updateUser = rp({
+ uri: utils.confdPort(api_server) + '/api/config/user-config',
+ method: 'PUT',
+ headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
+ 'Authorization': req.session && req.session.authorization
+ }),
+ forever: constants.FOREVER_ON,
+ json: data,
+ rejectUnauthorized: false,
+ resolveWithFullResponse: true
+ });
+ updateTasks.push(updateUser)
+ return new Promise(function(resolve, reject) {
+ Promise.all([
+ updateTasks
+ ]).then(function(result) {
+ var response = {};
+ response['data'] = {};
+ if (result[0].body) {
+ response['data'] = result[0].body;
+ }
+ response.statusCode = constants.HTTP_RESPONSE_CODES.SUCCESS.OK
+
+ resolve(response);
+ }).catch(function(error) {
+ var response = {};
+ console.log('Problem with UserManagement.passwordChange', error);
+ response.statusCode = error.statusCode || 500;
+ response.errorMessage = {
+ error: 'Failed to passwordChange user' + error
+ };
+ reject(response);
+ });
+ });
+};
+
+UserManagement.delete = function(req) {
+ var self = this;
+ var username = req.params.username;
+ var domain = req.params.domain;
+ var api_server = req.query["api_server"];
+ var requestHeaders = {};
+ var url = `${utils.confdPort(api_server)}/api/config/user-config/user/${username},${domain}`
+ return new Promise(function(resolve, reject) {
+ _.extend(requestHeaders,
+ constants.HTTP_HEADERS.accept.data,
+ constants.HTTP_HEADERS.content_type.data, {
+ 'Authorization': req.session && req.session.authorization
+ });
+ rp({
+ url: url,
+ method: 'DELETE',
+ headers: requestHeaders,
+ forever: constants.FOREVER_ON,
+ rejectUnauthorized: false,
+ }, function(error, response, body) {
+ if (utils.validateResponse('UserManagement.DELETE', error, response, body, resolve, reject)) {
+ return resolve({
+ statusCode: response.statusCode,
+ data: JSON.stringify(response.body)
+ });
+ };
+ });
+ })
+}
+module.exports = UserManagement;
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
if (!NAVIGATION[plugin_name]) {
NAVIGATION[plugin_name] = {};
}
-
if (!NAVIGATION[plugin_name].routes) {
NAVIGATION[plugin_name].routes = routes;
} else {
NAVIGATION[plugin_name].label = label || 'RW.UI Plugin';
}
+function addAllow(plugin_name, allow) {
+ if (!NAVIGATION[plugin_name]) {
+ NAVIGATION[plugin_name] = {};
+ }
+ NAVIGATION[plugin_name].allow = allow || '*';
+}
+
+function addAdminFlag(plugin_name, admin_link) {
+ if (!NAVIGATION[plugin_name]) {
+ NAVIGATION[plugin_name] = {};
+ }
+ NAVIGATION[plugin_name].admin_link = admin_link || false;
+}
+
function getNavigation() {
return NAVIGATION;
}
addOrder(plugin_name, plugin.order);
addPriority(plugin_name, plugin.priority);
addLabel(plugin_name, plugin.name);
+ addAllow(plugin_name, plugin.allow);
+ addAdminFlag(plugin_name, plugin.admin_link);
}
function init() {
function checkAuth(uri, req){
return new Promise(function(resolve, reject) {
request({
- uri: uri,
+ uri: utils.projectContextUrl(uri),
method: 'GET',
headers: _.extend({}, {
- 'Authorization': req.get('Authorization'),
+ 'Authorization': req.session && req.session.authorization,
forever: CONSTANTS.FOREVER_ON,
rejectUnauthorized: false,
})
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
extended: true
}));
-Router.get('/', cors(), function(req, res, next) {
- res.redirect('/launchpad/?api_server=' + req.protocol + '://' + configurationAPI.globalConfiguration.get().api_server + '&upload_server=' + req.protocol + '://' + (configurationAPI.globalConfiguration.get().upload_server || req.hostname));
+Router.get('/login.html', cors(), function(req, res) {
+ res.render('login.html');
+ res.end();
+});
+
+Router.get('/', cors(), function(req, res) {
+ var api_server = req.query['api_server'] || (req.protocol + '://' + configurationAPI.globalConfiguration.get().api_server);
+ if (req.session && req.session.loggedIn) {
+ console.log('Logged in. Redirect to launchpad');
+ if(req.params.referer) {
+ res.redirect(req.params.referer);
+ } else {
+ if(req.session.isLCM) {
+ res.redirect('/launchpad/?api_server=' + api_server + '&upload_server=' + req.protocol + '://' + (configurationAPI.globalConfiguration.get().upload_server || req.hostname));
+ } else {
+ res.redirect('/user_management/?api_server=' + api_server + '&upload_server=' + req.protocol + '://' + (configurationAPI.globalConfiguration.get().upload_server || req.hostname) + '#/user-profile');
+ }
+ }
+ } else {
+ console.log('Redirect to login.html');
+ res.redirect('login.html?api_server=' + api_server + '&upload_server=' + req.protocol + '://' + (configurationAPI.globalConfiguration.get().upload_server || req.hostname) + '&referer=' + req.headers.referer);
+ }
});
Router.get('/nav', cors(), function(req, res) {
--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * inactivity routes module. Provides a RESTful API for this
+ * skyquake instance's inactivity state.
+ * @module framework/core/modules/routes/inactivity
+ * @author Laurence Maultsby <laurence.maultsby@riftio.com>
+ */
+
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var Router = require('express').Router();
+var utils = require('../../api_utils/utils');
+var ProjectManagementAPI = require('../api/projectManagementAPI.js');
+
+Router.use(bodyParser.json());
+Router.use(cors());
+Router.use(bodyParser.urlencoded({
+ extended: true
+}));
+
+Router.get('/project', cors(), function(req, res) {
+ ProjectManagementAPI.get(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.post('/project', cors(), function(req, res) {
+ ProjectManagementAPI.create(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.put('/project', cors(), function(req, res) {
+ ProjectManagementAPI.update(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.delete('/project/:projectname', cors(), function(req, res) {
+ ProjectManagementAPI.delete(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+
+Router.put('/platform', cors(), function(req, res) {
+ ProjectManagementAPI.updatePlatform(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+
+Router.get('/platform', cors(), function(req, res) {
+ ProjectManagementAPI.getPlatform(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+module.exports = Router;
+
+
+
--- /dev/null
+
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * Node sessions routes module.
+ * Provides a RESTful API to manage sessions.
+ * @module framework/core/modules/routes/sessions
+ * @author Kiran Kashalkar <kiran.kashalkar@riftio.com>
+ */
+
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var sessionsAPI = require('../api/sessions');
+var Router = require('express').Router();
+var utils = require('../../api_utils/utils');
+var CONSTANTS = require('../../api_utils/constants.js');
+var request = require('request');
+var _ = require('lodash');
+
+Router.use(bodyParser.json());
+Router.use(cors());
+Router.use(bodyParser.urlencoded({
+ extended: true
+}));
+
+Router.post('/session', cors(), function(req, res) {
+ sessionsAPI.create(req, res).then(function(data) {
+ utils.sendSuccessResponse(data, res);
+ });
+});
+
+// For project switcher UI
+Router.put('/session/:projectId', cors(), function(req, res) {
+ sessionsAPI.addProjectToSession(req, res).then(function(data) {
+ utils.sendSuccessResponse(data, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+
+Router.delete('/session', cors(), function(req, res) {
+ sessionsAPI.delete(req, res);
+});
+
+
+module.exports = Router;
--- /dev/null
+
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * inactivity routes module. Provides a RESTful API for this
+ * skyquake instance's inactivity state.
+ * @module framework/core/modules/routes/inactivity
+ * @author Laurence Maultsby <laurence.maultsby@riftio.com>
+ */
+
+var cors = require('cors');
+var bodyParser = require('body-parser');
+var Router = require('express').Router();
+var utils = require('../../api_utils/utils');
+var UserManagementAPI = require('../api/userManagementAPI.js');
+
+Router.use(bodyParser.json());
+Router.use(cors());
+Router.use(bodyParser.urlencoded({
+ extended: true
+}));
+
+Router.get('/user', cors(), function(req, res) {
+ UserManagementAPI.get(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.get('/user-profile', cors(), function(req, res) {
+ UserManagementAPI.getProfile(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.get('/user-data/:userId/:domain?', cors(), function(req, res) {
+ UserManagementAPI.getUserInfo(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.post('/user', cors(), function(req, res) {
+ UserManagementAPI.create(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.put('/user', cors(), function(req, res) {
+ UserManagementAPI.update(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+Router.delete('/user/:username/:domain', cors(), function(req, res) {
+ UserManagementAPI.delete(req).then(function(response) {
+ utils.sendSuccessResponse(response, res);
+ }, function(error) {
+ utils.sendErrorResponse(error, res);
+ });
+});
+
+module.exports = Router;
+
+
+
--- /dev/null
+<html>
+<head>
+<style>
+ html, body {
+ background: #f1f1f1;
+ }
+
+ #loginForm {
+ display: flex;
+ flex-direction: column;
+ text-align: center;
+ align-items: center;
+ }
+
+ #loginForm .logo {
+ background: url('/img/svg/osm-logo_color_rgb.svg') no-repeat center;
+ background-size: contain;
+ width: 154px;
+ height: 102px;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 150px;
+ margin-bottom: 20px;
+ }
+
+ #loginForm input {
+ width: 550px;
+ height: 65px;
+ min-width: auto;
+ margin-bottom: 40px;
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, .39), 0 -1px 1px #fff, 0 1px 0 #fff;
+ font-size: 20px;
+ padding-left: 25px;
+ }
+
+ #loginForm #submit {
+ display: inline-block;
+ -webkit-box-shadow: 4px 4px 1px 0 #d9d9d9;
+ -moz-box-shadow: 4px 4px 1px 0 #d9d9d9;
+ box-shadow: 4px 4px 1px 0 #d9d9d9;
+ background-color: #333;
+ color: #fff;
+ text-decoration: none;
+ }
+
+ #loginForm .title {
+ margin-bottom: 40px;
+ font-size: 1.625rem;
+ font-weight: 400;
+ text-decoration: none;
+ text-transform: uppercase;
+ font-family: roboto-thin, Helvetica, Arial, sans-serif;
+ }
+
+</style>
+<title>Login Page</title>
+<script src='/jquery'></script>
+<script>
+
+function getSearchParams(url) {
+ var a = document.createElement('a');
+ a.href = url;
+ var params = {};
+ var items = a.search.replace('?', '').split('&');
+ for (var i = 0; i < items.length; i++) {
+ if (items[i].length > 0) {
+ var key_value = items[i].split('=');
+ params[key_value[0]] = key_value[1];
+ }
+ }
+ return params;
+}
+
+$(document).ready(function() {
+ var username;
+ var pass;
+ var api_server = getSearchParams(window.location).api_server;
+ $('#submit').click(function() {
+ username=$('#username').val();
+ pass=$('#password').val();
+ /*
+ * Perform some validation here.
+ */
+ $.ajax({
+ url: '/session?api_server=' + api_server,
+ type: 'POST',
+ data: {
+ username: username,
+ password: pass
+ },
+ success: function(data) {
+ window.location.href='/?api_server=' + api_server;
+ }
+ });
+ });
+
+ $('#loginForm').on('keyup', function(e) {
+ if (e.keyCode == 13) {
+ $('#submit').click();
+ }
+ });
+});
+
+</script>
+</head>
+<body>
+ <form id='loginForm' autocomplete='on'>
+ <div class='logo'> </div>
+ <h1 class='title'>Launchpad Login</h1>
+ <input type='text' size='40' placeholder='Username' id='username'><br />
+ <input type='password' size='40' placeholder='Password' id='password'><br />
+ <input type='button' value='Submit' id='submit'>
+ </form>
+</body>
+</html>
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
$error-red:#FF5F5F;
-//PC
+/*PC*/
$black: #000;
$gray-lightest: #f1f1f1;
$gray-darker: #666;
$gray-darkest: #333;
$white: #FFF;
-//
-// Brand Colors
-//
+/**/
+/* Brand Colors*/
+/**/
$brand-blue-light: #30baef;
$brand-blue: #00acee;
$brand-blue-dark: #147ca3;
$neutral-light-4: hsl(360, 100%, 50%);
$neutral-light-5: hsl(360, 100%, 50%);
-$neutral-dark-1: hsl(360, 100%, 50%);
-$neutral-dark-2: hsl(360, 100%, 50%);
-$neutral-dark-3: hsl(360, 100%, 50%);
-$neutral-dark-4: hsl(360, 100%, 50%);
-$neutral-dark-5: hsl(360, 100%, 50%);
+$neutral-dark-1: hsl(0, 0%, 63.7%);
+$neutral-dark-2: hsl(0, 0%, 56.7%);
+$neutral-dark-3: hsl(0, 0%, 49.7%);
+$neutral-dark-4: hsl(0, 0%, 42.7%);
+$neutral-dark-5: hsl(0, 0%, 35.7%);
$netral-black: hsl(0, 100%, 0%);
--- /dev/null
+var c = {};
+
+c.PLATFORM = {
+ OPER: "rw-rbac-platform:platform-oper",
+ ADMIN: "rw-rbac-platform:platform-admin",
+ SUPER: "rw-rbac-platform:super-admin"
+}
+
+c.PROJECT = {
+ CATALOG_OPER: "rw-project-mano:catalog-oper",
+ CATALOG_ADMIN: "rw-project-mano:catalog-admin",
+ LCM_OPER: "rw-project-mano:lcm-oper",
+ LCM_ADMIN: "rw-project-mano:lcm-admin",
+ ACCOUNT_OPER: "rw-project-mano:account-oper",
+ ACCOUNT_ADMIN: "rw-project-mano:account-admin",
+ PROJECT_ADMIN: "rw-project:project-admin",
+ PROJECT_OPER: "rw-project:project-oper",
+}
+
+module.exports = c;
var Utils = {};
Utils.DescriptorModelMeta = null;
+// Utils.DescriptorModelMeta = require('./../../plugins/composer/src/src/libraries/model/DescriptorModelMeta.json');
var INACTIVITY_TIMEOUT = 600000;
}
Utils.addAuthorizationStub = function(xhr) {
- var Auth = window.sessionStorage.getItem("auth");
- xhr.setRequestHeader('Authorization', 'Basic ' + Auth);
+ // NO-OP now that we are dealing with it on the server
+ // var Auth = window.sessionStorage.getItem("auth");
+ // xhr.setRequestHeader('Authorization', 'Basic ' + Auth);
};
Utils.getByteDataWithUnitPrefix = function(number, precision) {
window.sessionStorage.removeItem("auth");
AuthActions.notAuthenticated();
window.sessionStorage.setItem("locationRefHash", window.location.hash);
+ $.ajax({
+ url: '//' + window.location.hostname + ':' + window.location.port + '/session?api_server=' + API_SERVER,
+ type: 'DELETE',
+ success: function(data) {
+ console.log('User logged out');
+ },
+ error: function(data) {
+ console.log('Problem logging user out');
+ }
+ });
+
+
if (callback) {
callback();
} else {
- window.location.hash = Utils.loginHash;
+ window.location.replace(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/?api_server=' + API_SERVER);
}
}
Utils.isNotAuthenticated = function(windowLocation, callback) {
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
############################################################################ */
.SqButton {
- align-items: center;
+ -ms-flex-align: center;
+ align-items: center;
border-style: solid;
border-radius: 3px;
border-width: 0px;
cursor: pointer;
+ display: -ms-inline-flexbox;
display: inline-flex;
font-size: 1rem;
height: 50px;
- justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center;
margin: 0 10px;
outline: none;
padding: 0 15px;
/* Focus */
&:focus {
- // box-shadow: $focus-shadow;
- border: 1px solid red;
+ /* box-shadow: $focus-shadow;*/
+ border: 1px solid;
+ border-color: darken($normalHoverBackground, 10%);
}
/* SIZES
fill: $primaryForeground;
}
}
-
-
}
-
+.sqButtonGroup {
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-pack: center;
+ justify-content: center;
+}
Class += " is-disabled";
}
return (
- <div style={{display: 'flex'}}>
+ <div style={{display: 'flex'}} onClick={this.props.onClick}>
<div className={Class} tabIndex="0">
- {svgHTML}
- <div className="SqButton-content">{label}</div>
+ {svgHTML}
+ <div className="SqButton-content">{label}</div>
</div>
+ </div>
+ )
+ }
+}
+
+export class ButtonGroup extends React.Component {
+ render() {
+ let className = "sqButtonGroup";
+ if (this.props.className) {
+ className = `${className} ${this.props.className}`
+ }
+ return (
+ <div className={className} style={this.props.style}>
+ {this.props.children}
</div>
)
}
}
+
SqButton.defaultProps = {
+ onClick: function(e) {
+ console.log('Clicked')
+ },
icon: false,
primary: false,
disabled: false,
Bullet: require('./bullet/bullet.js')
};
-// require('../../assets/js/n3-line-chart.js');
-// var Gauge = require('../../assets/js/gauge-modified.js');
-// var bulletController = function($scope, $element) {
-// this.$element = $element;
-// this.vertical = false;
-// this.value = 0;
-// this.min = 0;
-// this.max = 100;
-// //this.range = this.max - this.min;
-// //this.percent = (this.value - this.min) / this.range;
-// this.displayValue = this.value;
-// this.isPercent = (this.units == '')? true:false;
-// this.bulletColor = "#6BB814";
-// this.fontsize = 28;
-// this.radius = 4;
-// this.containerMarginX = 0;
-// this.containerMarginY = 0;
-// this.textMarginX = 5;
-// this.textMarginY = 42;
-// this.bulletMargin = 0;
-// this.width = 512;
-// this.height = 64;
-// this.markerX = -100; // puts it off screen unless set
-// var self = this;
-// if (this.isPercent) {
-// this.displayValue + "%";
-// }
-// $scope.$watch(
-// function() {
-// return self.value;
-// },
-// function() {
-// self.valueChanged();
-// }
-// );
-
-// }
-
-// bulletController.prototype = {
-
-// valueChanged: function() {
-// var range = this.max - this.min;
-// var normalizedValue = (this.value - this.min) / range;
-// if (this.isPercent) {
-// this.displayValue = String(Math.round(normalizedValue * 100)) + "%";
-// } else {
-// this.displayValue = this.value;
-// }
-// // All versions of IE as of Jan 2015 does not support inline CSS transforms on SVG
-// if (platform.name == 'IE') {
-// this.bulletWidth = Math.round(100 * normalizedValue) + '%';
-// } else {
-// this.bulletWidth = this.width - (2 * this.containerMarginX);
-// var transform = 'scaleX(' + normalizedValue + ')';
-// var bullet = $(this.$element).find('.bullet2');
-// bullet.css('transform', transform);
-// bullet.css('-webkit-transform', transform);
-// }
-// },
-
-// markerChanged: function() {
-// var range = this.max - this.min;
-// var w = this.width - (2 * this.containerMarginX);
-// this.markerX = this.containerMarginX + ((this.marker - this.min) / range ) * w;
-// this.markerY1 = 7;
-// this.markerY2 = this.width - 7;
-// }
-// }
-
-// angular.module('components', ['n3-line-chart'])
-// .directive('rwBullet', function() {
-// return {
-// restrict : 'E',
-// templateUrl: 'modules/views/rw.bullet.tmpl.html',
-// bindToController: true,
-// controllerAs: 'bullet',
-// controller: bulletController,
-// replace: true,
-// scope: {
-// min : '@?',
-// max : '@?',
-// value : '@',
-// marker: '@?',
-// units: '@?',
-// bulletColor: '@?',
-// label: '@?'
-// }
-// };
-// })
-// .directive('rwSlider', function() {
-// var controller = function($scope, $element, $timeout) {
-// // Q: is there a way to force attributes to be ints?
-// $scope.min = $scope.min || "0";
-// $scope.max = $scope.max || "100";
-// $scope.step = $scope.step || "1";
-// $scope.height = $scope.height || "30";
-// $scope.orientation = $scope.orientation || 'horizontal';
-// $scope.tooltipInvert = $scope.tooltipInvert || false;
-// $scope.percent = $scope.percent || false;
-// $scope.kvalue = $scope.kvalue || false;
-// $scope.direction = $scope.direction || "ltr";
-// $($element).noUiSlider({
-// start: parseInt($scope.value),
-// step: parseInt($scope.step),
-// orientation: $scope.orientation,
-// range: {
-// min: parseInt($scope.min),
-// max: parseInt($scope.max)
-// },
-// direction: $scope.direction
-// });
-// //$(".no-Ui-target").Link('upper').to('-inline-<div class="tooltip"></div>')
-// var onSlide = function(e, value) {
-// $timeout(function(){
-// $scope.value = value;
-// })
-
-// };
-// $($element).on({
-// change: onSlide,
-// slide: onSlide,
-// set: $scope.onSet({value: $scope.value})
-// });
-// var val = String(Math.round($scope.value));
-// if ($scope.percent) {
-// val += "%"
-// } else if ($scope.kvalue) {
-// val += "k"
-// }
-// $($element).height($scope.height);
-// if ($scope.tooltipInvert) {
-// $($element).find('.noUi-handle').append("<div class='tooltip' style='position:relative;right:20px'>" + val + "</div>");
-// } else {
-// $($element).find('.noUi-handle').append("<div class='tooltip' style='position:relative;left:-20px'>" + val + "</div>");
-// }
-// $scope.$watch('value', function(value) {
-// var val = String(Math.round($scope.value));
-// if ($scope.percent) {
-// val += "%"
-// } else if($scope.kvalue) {
-// val += "k"
-// }
-// $($element).val(value);
-// $($element).find('.tooltip').html(val);
-// if ($scope.tooltipInvert) {
-// $($element).find('.tooltip').css('right', $($element).find('.tooltip').innerWidth() * -1);
-// } else {
-// $($element).find('.tooltip').css('left', $($element).find('.tooltip').innerWidth() * -1);
-// }
-// });
-// };
-
-// return {
-// restrict : 'E',
-// template: '<div></div>',
-// controller : controller,
-// replace: true,
-// scope: {
-// min : '@',
-// max : '@',
-// width: '@',
-// height: '@',
-// step : '@',
-// orientation : '@',
-// tooltipInvert: '@',
-// percent: '@',
-// kvalue: '@?',
-// onSet:'&?',
-// direction: '@?',
-// value:'=?'
-// }
-// };
-// })
-// .directive('rwGauge', function() {
-// return {
-// restrict: 'AE',
-// template: '<canvas class="rwgauge" style="width:100%;height:100%;max-width:{{width}}px;max-height:240px;"></canvas>',
-// replace: true,
-// scope: {
-// min: '@?',
-// max: '@?',
-// size: '@?',
-// color: '@?',
-// value: '@?',
-// resize: '@?',
-// isAggregate: '@?',
-// units: '@?',
-// valueFormat: '=?',
-// width: '@?'
-// },
-// bindToController: true,
-// controllerAs: 'gauge',
-// controller: function($scope, $element) {
-// var self = this;
-// this.gauge = null;
-// this.min = this.min || 0;
-// this.max = this.max || 100;
-// this.nSteps = 14;
-// this.size = this.size || 300;
-// this.units = this.units || '';
-// $scope.width = this.width || 240;
-// this.color = this.color || 'hsla(212, 57%, 50%, 1)';
-// if (!this.valueFormat) {
-// if (this.max > 1000 || this.value) {
-// self.valueFormat = {
-// "int": 1,
-// "dec": 0
-// };
-// } else {
-// self.valueFormat = {
-// "int": 1,
-// "dec": 2
-// };
-// }
-// }
-// this.isAggregate = this.isAggregate || false;
-// this.resize = this.resize || false;
-// if (this.format == 'percent') {
-// self.valueFormat = {
-// "int": 3,
-// "dec": 0
-// };
-// }
-// $scope.$watch(function() {
-// return self.max;
-// }, function(n, o) {
-// if(n !== o) {
-// renderGauge();
-// }
-// });
-// $scope.$watch(function() {
-// return self.valueFormat;
-// }, function(n, o) {
-// if(n != 0) {
-// renderGauge();
-// }
-// });
-// $scope.$watch(function() {
-// return self.value;
-// }, function() {
-// if (self.gauge) {
-// // w/o rounding gauge will unexplainably thrash round.
-// self.valueFormat = determineValueFormat(self.value);
-// self.gauge.setValue(Math.ceil(self.value * 100) / 100);
-// //self.gauge.setValue(Math.round(self.value));
-// }
-// });
-// angular.element($element).ready(function() {
-// console.log('rendering')
-// renderGauge();
-// })
-// window.testme = renderGauge;
-// function determineValueFormat(value) {
-
-// if (value > 999 || self.units == "%") {
-// return {
-// "int": 1,
-// "dec": 0
-// }
-// }
-
-// return {
-// "int": 1,
-// "dec": 2
-// }
-// }
-// function renderGauge(calcWidth) {
-// if (self.max == self.min) {
-// self.max = 14;
-// }
-// var range = self.max - self.min;
-// var step = Math.round(range / self.nSteps);
-// var majorTicks = [];
-// for (var i = 0; i <= self.nSteps; i++) {
-// majorTicks.push(self.min + (i * step));
-// };
-// var redLine = self.min + (range * 0.9);
-// var config = {
-// isAggregate: self.isAggregate,
-// renderTo: angular.element($element)[0],
-// width: calcWidth || self.size,
-// height: calcWidth || self.size,
-// glow: false,
-// units: self.units,
-// title: false,
-// minValue: self.min,
-// maxValue: self.max,
-// majorTicks: majorTicks,
-// valueFormat: determineValueFormat(self.value),
-// minorTicks: 0,
-// strokeTicks: false,
-// highlights: [],
-// colors: {
-// plate: 'rgba(0,0,0,0)',
-// majorTicks: 'rgba(15, 123, 182, .84)',
-// minorTicks: '#ccc',
-// title: 'rgba(50,50,50,100)',
-// units: 'rgba(50,50,50,100)',
-// numbers: '#fff',
-// needle: {
-// start: 'rgba(255, 255, 255, 1)',
-// end: 'rgba(255, 255, 255, 1)'
-// }
-// }
-// };
-// var min = config.minValue;
-// var max = config.maxValue;
-// var N = 1000;
-// var increment = (max - min) / N;
-// for (i = 0; i < N; i++) {
-// var temp_color = 'rgb(0, 172, 238)';
-// if (i > 0.5714 * N && i <= 0.6428 * N) {
-// temp_color = 'rgb(0,157,217)';
-// } else if (i >= 0.6428 * N && i < 0.7142 * N) {
-// temp_color = 'rgb(0,142,196)';
-// } else if (i >= 0.7142 * N && i < 0.7857 * N) {
-// temp_color = 'rgb(0,126,175)';
-// } else if (i >= 0.7857 * N && i < 0.8571 * N) {
-// temp_color = 'rgb(0,122,154)';
-// } else if (i >= 0.8571 * N && i < 0.9285 * N) {
-// temp_color = 'rgb(0,96,133)';
-// } else if (i >= 0.9285 * N) {
-// temp_color = 'rgb(0,80,112)';
-// }
-// config.highlights.push({
-// from: i * increment,
-// to: increment * (i + 2),
-// color: temp_color
-// })
-// }
-// var updateSize = _.debounce(function() {
-// config.maxValue = self.max;
-// var clientWidth = self.parentNode.parentNode.clientWidth / 2;
-// var calcWidth = (300 > clientWidth) ? clientWidth : 300;
-// self.gauge.config.width = self.gauge.config.height = calcWidth;
-// self.renderGauge(calcWidth);
-// }, 500);
-// if (self.resize) $(window).resize(updateSize)
-// if (self.gauge) {
-// self.gauge.updateConfig(config);
-// } else {
-// self.gauge = new Gauge(config);
-// self.gauge.draw();
-// }
-// };
-// },
-// }
-// });
--- /dev/null
+import './formControls.jsx';
+
+import React from 'react'
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import imgAdd from '../../../node_modules/open-iconic/svg/plus.svg'
+import imgRemove from '../../../node_modules/open-iconic/svg/trash.svg'
+import TextInput from 'widgets/form_controls/textInput.jsx';
+import Input from 'widgets/form_controls/input.jsx';
+
+export class FormSection extends React.Component {
+ render() {
+ let className = 'FormSection ' + this.props.className;
+ let html = (
+ <div
+ style={this.props.style}
+ className={className}
+ >
+ <div className="FormSection-title">
+ {this.props.title}
+ </div>
+ <div className="FormSection-body">
+ {this.props.children}
+ </div>
+ </div>
+ );
+ return html;
+ }
+}
+
+FormSection.defaultProps = {
+ className: ''
+}
+
+/**
+ * AddItemFn:
+ */
+export class InputCollection extends React.Component {
+ constructor(props) {
+ super(props);
+ this.collection = props.collection;
+ }
+ buildTextInput(onChange, v, i) {
+ return (
+ <Input
+ readonly={this.props.readonly}
+ style={{flex: '1 1'}}
+ key={i}
+ value={v}
+ onChange= {onChange.bind(null, i)}
+ />
+ )
+ }
+ buildSelectOption(initial, options, onChange, v, i) {
+ return (
+ <SelectOption
+ readonly={this.props.readonly}
+ key={`${i}-${v.replace(' ', '_')}`}
+ intial={initial}
+ defaultValue={v}
+ options={options}
+ onChange={onChange.bind(null, i)}
+ />
+ );
+ }
+ showInput() {
+
+ }
+ render() {
+ const props = this.props;
+ let inputType;
+ let className = "InputCollection";
+ if (props.className) {
+ className = `${className} ${props.className}`;
+ }
+ if (props.type == 'select') {
+ inputType = this.buildSelectOption.bind(this, props.initial, props.options, props.onChange);
+ } else {
+ inputType = this.buildTextInput.bind(this, props.onChange)
+ }
+ let html = (
+ <div className="InputCollection-wrapper">
+ {props.collection.map((v,i) => {
+ return (
+ <div key={i} className={className} >
+ {inputType(v, i)}
+ {
+ props.readonly ? null : <span onClick={props.RemoveItemFn.bind(null, i)} className="removeInput"><img src={imgRemove} />Remove</span>}
+ </div>
+ )
+ })}
+ { props.readonly ? null : <span onClick={props.AddItemFn} className="addInput"><img src={imgAdd} />Add</span>}
+ </div>
+ );
+ return html;
+ }
+}
+
+InputCollection.defaultProps = {
+ input: Input,
+ collection: [],
+ onChange: function(i, e) {
+ console.log(`
+ Updating with: ${e.target.value}
+ At index of: ${i}
+ `)
+ },
+ AddItemFn: function(e) {
+ console.log(`Adding a new item to collection`)
+ },
+ RemoveItemFn: function(i, e) {
+ console.log(`Removing item from collection at index of: ${i}`)
+ }
+}
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* limitations under the License.
*
*/
-@import 'style/_colors.scss';
+@import '../../style/_colors.scss';
.sqTextInput {
display: -ms-flexbox;
color:$darker-gray;
text-transform:uppercase;
}
- input, .readonly, textarea {
+ input, textarea {
height: 35px;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.39), 0 -1px 1px #ffffff, 0 1px 0 #ffffff;
font-size: 1rem;
.readonly {
line-height: 35px;
box-shadow:none;
+ background:none !important;
}
textarea {
-ms-flex-align: stretch;
border:0px;
height: 100%;
}
+ &.checkbox {
+ -ms-flex-direction:row;
+ flex-direction:row;
+ -ms-flex-align:center;
+ align-items:center;
+ margin-bottom:0;
+ >span {
+ -ms-flex-order: 1;
+ order: 1;
+ padding-left:1rem;
+ }
+ >input {
+ -ms-flex-order: 0;
+ order: 0;
+
+ box-shadow:none;
+ height:25px;
+ }
+ }
+}
+
+.sqCheckBox {
+ display:-ms-flexbox;
+ display:flex;
+ label {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-align: center;
+ align-items: center;
+ input {
+ box-shadow: none;
+ height: auto;
+ margin: 0 0.25rem;
+ }
+ }
+}
+
+.FormSection {
+ &-title {
+ color: #000;
+ background: lightgray;
+ padding: 0.5rem;
+ border-top: 1px solid #f1f1f1;
+ border-bottom: 1px solid #f1f1f1;
+ }
+ &-body {
+ padding: 0.5rem 0.75rem;
+ }
+ label {
+ -ms-flex: 1 0;
+ flex: 1 0;
+ }
+ /* label {*/
+ /* display: -ms-flexbox;*/
+ /* display: flex;*/
+ /* -ms-flex-direction: column;*/
+ /* flex-direction: column;*/
+ /* width: 100%;*/
+ /* margin: 0.5rem 0;*/
+ /* -ms-flex-align: start;*/
+ /* align-items: flex-start;*/
+ /* -ms-flex-pack: start;*/
+ /* justify-content: flex-start;*/
+ /* }*/
+ select {
+ font-size: 1rem;
+ min-width: 75%;
+ height: 35px;
+ }
+}
+
+
+
+
+.InputCollection {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -ms-flex-align: center;
+ align-items: center;
+ button {
+ padding: 0.25rem;
+ height: 1.5rem;
+ font-size: 0.75rem;
+ }
+ select {
+ min-width: 100%;
+ }
+ margin-bottom:0.5rem;
+ &-wrapper {
+
+ }
}
--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+import './formControls.scss';
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import CircleSVG from '../../../node_modules/open-iconic/svg/media-record.svg'
+import React, {Component} from 'react';
+
+export default class Input extends Component {
+ render() {
+ let {label, value, defaultValue, ...props} = this.props;
+ let inputProperties = {
+ value: value
+ }
+ let isRequired;
+ let inputType;
+ let className = `sqTextInput ${props.className}`;
+
+ if(this.props.required) {
+ isRequired = <span className="required">*</span>
+ }
+ if (defaultValue) {
+ inputProperties.defaultValue = defaultValue;
+ }
+ if (props.pattern) {
+ inputProperties.pattern = props.pattern;
+ }
+ if(props.hasOwnProperty('type') && (props.type.toLowerCase() == 'checkbox')) {
+ inputProperties.checked = props.checked;
+ className = `${className} checkbox`;
+ }
+ if (value == undefined) {
+ value = defaultValue;
+ }
+ switch(props.type) {
+ case 'textarea':
+ inputType = <textarea key={props.key} {...inputProperties} value={value} onChange={props.onChange} />
+ break;
+ case 'select':
+ inputType = <SelectOption
+ key={props.key}
+ initial={props.initial}
+ defaultValue={defaultValue}
+ options={props.options}
+ onChange={props.onChange}
+ />
+ break;
+ case 'radiogroup':
+ inputType = buildRadioButtons(this.props);
+ break;
+ default:
+ inputType = <input key={props.key} type={props.type} {...inputProperties} onChange={props.onChange} placeholder={props.placeholder}/>;
+ }
+ let displayedValue;
+ if(value === null) {
+ displayedValue = null;
+ } else {
+ displayedValue = value.toString();
+ }
+ if( props.readonly && props.type == "checkbox" && props.checked ) {
+ displayedValue = <img src={CircleSVG} />
+ }
+ let html = (
+ <label className={className} style={props.style}>
+ <span> { label } {isRequired}</span>
+ {
+ !props.readonly ? inputType : <div className="readonly">{displayedValue}</div>
+ }
+
+ </label>
+ );
+ return html;
+ }
+}
+
+
+function buildRadioButtons(props) {
+ let className = 'sqCheckBox';
+ if (props.className) {
+ className = `${className} ${props.className}`;
+ }
+ return(
+ <div className={className}>
+ {
+ props.options.map((o,i) => {
+ return (
+ <label key={i}>
+ {o.label}
+ <input type="radio" checked={props.value == o.value} value={o.value} onChange={props.onChange} />
+ </label>
+ )
+ })
+ }
+ </div>
+
+ )
+}
+
+Input.defaultProps = {
+ onChange: function(e) {
+ console.log(e.target.value, e);
+ console.dir(e.target);
+ },
+ label: '',
+ defaultValue: null,
+ type: 'text',
+ readonly: false,
+ style:{},
+ className: ''
+
+}
+
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
render() {
let html;
let defaultValue = this.props.defaultValue;
- let options = this.props.options.map(function(op, i) {
- let value = JSON.stringify(op.value);
- return <option key={i} value={JSON.stringify(op.value)}>{op.label}</option>
- });
+ let options = this.props.options && this.props.options.map(function(op, i) {
+ let value;
+ let label;
+ if(typeof(op) == 'object') {
+ value = JSON.stringify(op.value);
+ label = op.label;
+ } else {
+ value = op;
+ label = op;
+ }
+
+ return <option key={i} value={JSON.stringify(value)}>{label}</option>
+ }) || [];
if (this.props.initial) {
options.unshift(<option key='blank' value={JSON.stringify(this.props.defaultValue)}></option>);
}
html = (
- <label>
+ <label key={this.props.key} className={this.props.className}>
{this.props.label}
- <select className={this.props.className} onChange={this.handleOnChange} defaultValue={JSON.stringify(defaultValue)} >
- {
- options
- }
- </select>
+ {
+ this.props.readonly ? defaultValue
+ : (
+ <select
+ className={this.props.className}
+ onChange={this.handleOnChange}
+ value={JSON.stringify(this.props.value)}
+ defaultValue={JSON.stringify(defaultValue)}>
+ {
+ options
+ }
+ </select>
+ )
+ }
</label>
);
return html;
}
}
SelectOption.defaultProps = {
+ /**
+ * [options description]
+ * @type {Array} - Expects items to contain objects with the properties 'label' and 'value' which are both string types. Hint: JSON.stringify()
+ */
options: [],
onChange: function(e) {
+ console.log(e.target.value)
console.dir(e)
},
- defaultValue: false,
+ readonly: false,
+ /**
+ * Selected or default value
+​
+ * @type {[type]}
+ */
+ defaultValue: null,
+ /**
+ * True if first entry in dropdown should be blank
+ * @type {Boolean}
+ */
initial: false,
label: null
}
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
import './formControls.scss';
import React, {Component} from 'react';
-
-export default class TextInput extends Component {
- render() {
- let {label, onChange, value, defaultValue, ...props} = this.props;
- let inputProperties = {
- value: value,
- onChange: onChange
- }
- let isRequired;
- let inputType;
- if(this.props.required) {
- isRequired = <span className="required">*</span>
- }
- if (defaultValue) {
- inputProperties.defaultValue = defaultValue;
- }
- if (props.pattern) {
- inputProperties.pattern = props.pattern;
- }
- if (value == undefined) {
- value = defaultValue;
- }
- switch(props.type) {
- case 'textarea':
- inputType = <textarea {...inputProperties} value={value}/>
-
- break;
- default:
- inputType = <input type={props.type} {...inputProperties} placeholder={props.placeholder}/>;
- }
- let html = (
- <label className={"sqTextInput " + props.className} style={props.style}>
- <span> { label } {isRequired}</span>
- {
- !props.readonly ? inputType : <div className="readonly">{value}</div>
- }
-
- </label>
- );
- return html;
+import Input from './input.jsx';
+class TextInput extends Input {
+ constructor(props) {
+ super(props);
+ console.warn('TextInput is deprecated. Use Input component instead')
}
}
-
-TextInput.defaultProps = {
- onChange: function(e) {
- console.log(e.target.value);
- },
- label: '',
- defaultValue: undefined,
- type: 'text',
- readonly: false,
- style:{}
-
-}
+export default TextInput;
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
*/
header.header-app-component {
- padding: 20px 0px;
+ padding: 10px 0px;
+ display:-ms-flexbox;
display:flex;
- flex-direction:column;
+ -ms-flex-direction:column;
+ flex-direction:column;
.header-app-main {
+ display:-ms-flexbox;
display:flex;
- flex-direction:row;
- justify-content:space-between;
- align-items:center;
+ -ms-flex-direction:row;
+ flex-direction:row;
+ -ms-flex-pack:justify;
+ justify-content:space-between;
+ -ms-flex-align:center;
+ align-items:center;
}
h1 {
/*background: url('../../style/img/header-logo.png') no-repeat;*/
font-size: 1.625rem;
font-weight: 400;
position:relative;
- flex: 1 0 auto;
+ -ms-flex: 1 0 auto;
+ flex: 1 0 auto;
}
ul {
+ display:-ms-flexbox;
display:flex;
}
li {
+ display:-ms-flexbox;
display:flex;
- flex:1 1 auto;
+ -ms-flex:1 1 auto;
+ flex:1 1 auto;
border-right:1px solid #e5e5e5;
padding: 0 1rem;
&:last-child {
}
a {
cursor:pointer;
- // padding: 0.125rem;
- // border-bottom:1px solid black;
+ /* padding: 0.125rem;*/
+ /* border-bottom:1px solid black;*/
text-decoration:underline;
}
}
.header-app-nav {
+ display:-ms-flexbox;
display:flex;
margin-left: 0.25rem;
a,span {
}
}
nav {
+ display:-ms-flexbox;
display:flex;
- flex:0 1 auto;
- align-items:center;
+ -ms-flex:0 1 auto;
+ flex:0 1 auto;
+ -ms-flex-align:center;
+ align-items:center;
}
}
import React, {Component} from 'react';
import 'style/core.css';
import './panel.scss';
+import circleXImage from '../../../node_modules/open-iconic/svg/circle-x.svg';
export class Panel extends Component {
constructor(props) {
super(props)
let classRoot = className ? ' ' + className : ' ';
let hasCorners = this.props['no-corners'];
let titleTag = title ? <header className="skyquakePanel-title">{title}</header> : '';
+ let closeButton = (
+ <a onClick={self.props.hasCloseButton}
+ className={"close-btn"}>
+ <img src={circleXImage} title="Close card" />
+ </a>
+ );
return (
<section className={'skyquakePanel' + classRoot} style={props.style}>
+ { self.props.hasCloseButton ? closeButton : null}
{ !hasCorners ? <i className="corner-accent top left"></i> : null }
{ !hasCorners ? <i className="corner-accent top right"></i> : null }
{titleTag}
export class PanelWrapper extends Component {
render() {
+ let wrapperClass = 'skyquakePanelWrapper';
+ let {className, column, style, ...props} = this.props;
+ if(className) {
+ wrapperClass = `${wrapperClass} ${className}`
+ }
+ if(column) {
+ style.flexDirection = 'column';
+ }
return (
- <div className={'skyquakePanelWrapper ' + this.props.className} style={this.props.style}>
+ <div className={wrapperClass} style={style} {...props}>
{this.props.children}
</div>)
}
}
-
+PanelWrapper.defaultProps = {
+ style: {}
+}
export default Panel;
width:100%;
height:100%;
}
+ .close-btn {
+ cursor:pointer;
+ position: absolute;
+ right: -0.5rem;
+ top: -0.5rem;
+ img {
+ width: 1rem;
+ }
+ }
}
.skyquakePanelWrapper.column {
+ -ms-flex-direction:column;
+ flex-direction:column;
+ display:-ms-flexbox;
+ display:flex;
.skyquakePanel-wrapper {
height:auto;
}
-//import a reset
+/*import a reset*/
@import '../../style/_colors.scss';
html, body {
height:100%;
.skyquakeApp {
+ display: -ms-flexbox;
display: flex;
- flex-direction: column;
+ -ms-flex-direction: column;
+ flex-direction: column;
height: 100%;
background: $gray-lightest;
h1 {
text-transform: uppercase;
}
- .active {
- background-color: $brand-blue!important;
- border-color: $brand-blue!important;
- color: #fff!important
- }
- .skyquakeNav {
- display: flex;
- color:white;
- background:black;
- position:relative;
- z-index: 10;
- font-size:0.75rem;
- .secondaryNav {
- flex: 1 1 auto;
- display: flex;
- justify-content: flex-end;
- }
- .app {
- position:relative;
- h2 {
- font-size:0.75rem;
- border-right: 1px solid black;
- display: flex;
- align-items: center;
- .oi {
- padding-right: 0.5rem;
- }
- }
- .menu {
- position:absolute;
- display:none;
- z-index:2;
- width: 100%;
- }
- &:first-child{
- h2 {
- border-left: 1px solid black;
- }
- }
- &:hover {
- a {
- color:$brand-blue-light;
- cursor:pointer;
- }
- .menu {
- display:block;
- background:black;
- a {
- color:white;
- }
- li:hover {
- a {
- color:$brand-blue-light;
- }
- }
- }
- }
- &.active {
- color:white;
- background:black;
- a {
- color:white;
- }
- }
- }
- a{
- display:block;
- padding:0.5rem 1rem;
- text-decoration:none;
- text-transform:uppercase;
- color:white;
- }
- &:before {
- content: '';
- height:1.85rem;
- width:5.5rem;
- /*margin:0 1rem;*/
- /*padding:0 0.125rem;*/
- /*background: url('../../style/img/svg/riftio_logo_white.svg') no-repeat center center;*/
- background: url('../../style/img/svg/osm-logo_color_rgb_white_text.svg') no-repeat center center;
- background-size: contain;
- }
- }
+
.skyquakeContainerWrapper {
}
.titleBar {
padding: 1rem 0 0;
h1 {
- // background: url('../../style/img/header-logo.png') no-repeat;
+ /* background: url('../../style/img/header-logo.png') no-repeat;*/
background-size:contain;
height: 51px;
line-height: 51px;
margin-left: 20px;
- // padding-left: 100px;
+ /* padding-left: 100px;*/
left: 0;
font-size: 1.625rem;
font-weight: 400;
text-align:left;
position:relative;
- flex: 1 0 auto;
+ -ms-flex: 1 0 auto;
+ flex: 1 0 auto;
}
}
.corner-accent {
this.actions = context.flux.actions.global;
}
render(props) {
- return <Component {...this.props} router={this.router} actions={this.actions} flux={this.context.flux} />
+ return <Component {...this.props} router={this.router} actions={this.actions} flux={this.context.flux}/>
}
}
SkyquakeComponent.contextTypes = {
import React from 'react';
import AltContainer from 'alt-container';
import Alt from './skyquakeAltInstance.js';
-import SkyquakeNav from './skyquakeNav.jsx';
+import SkyquakeNav from '../skyquake_nav/skyquakeNav.jsx';
import EventCenter from './eventCenter.jsx';
import SkyquakeContainerActions from './skyquakeContainerActions.js'
import SkyquakeContainerStore from './skyquakeContainerStore.js';
this.state.eventCenterIsOpen = false;
this.state.currentPlugin = SkyquakeContainerStore.currentPlugin;
}
-
+ getChildContext() {
+ return {
+ userProfile: this.state.user
+ };
+ }
+ getUserProfile() {
+ return this.state.user;
+ }
componentWillMount() {
let self = this;
Utils.bootstrapApplication().then(function() {
SkyquakeContainerStore.listen(self.listener);
SkyquakeContainerStore.getNav();
+ SkyquakeContainerStore.getUserProfile();
SkyquakeContainerStore.getEventStreams();
});
render() {
const {displayNotification, notificationMessage, displayScreenLoader, notificationType, ...state} = this.state;
var html;
-
+ let nav = _.cloneDeep(this.state.nav);
if (this.matchesLoginUrl()) {
html = (
<AltContainer>
timeout= {5000}
/>
<ScreenLoader show={displayScreenLoader}/>
- <SkyquakeNav nav={this.state.nav}
- currentPlugin={this.state.currentPlugin}
- store={SkyquakeContainerStore} />
+ <SkyquakeNav nav={nav}
+ currentPlugin={this.state.user.currentPlugin}
+ currentUser={this.state.user.userId}
+ currentProject={this.state.user.projectId}
+ store={SkyquakeContainerStore}
+ projects={this.state.projects} />
<div className="titleBar">
- <h1>{this.state.currentPlugin + tag}</h1>
+ <h1>{(this.state.nav.name ? this.state.nav.name.replace('_', ' ').replace('-', ' ') : this.state.currentPlugin && this.state.currentPlugin.replace('_', ' ').replace('-', ' ')) + tag}</h1>
</div>
<div className={"application " + routeName}>
{this.props.children}
return html;
}
}
+skyquakeContainer.childContextTypes = {
+ userProfile: React.PropTypes.object
+};
skyquakeContainer.contextTypes = {
router: React.PropTypes.object
};
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
'hideNotification',
//Screen Loader
'showScreenLoader',
- 'hideScreenLoader'
+ 'hideScreenLoader',
+ 'openProjectSocketSuccess',
+ 'getUserProfileSuccess',
+ 'selectActiveProjectSuccess'
);
success: SkyquakeContainerActions.openNotificationsSocketSuccess,
error: SkyquakeContainerActions.openNotificationsSocketError
}
+ },
+ openProjectSocket() {
+ return {
+ remote: function(state) {
+ return new Promise(function(resolve, reject) {
+ //If socket connection already exists, eat the request.
+ if(state.socket) {
+ return resolve(false);
+ }
+ $.ajax({
+ url: '/socket-polling',
+ type: 'POST',
+ beforeSend: Utils.addAuthorizationStub,
+ data: {
+ url: '/project?api_server=' + API_SERVER
+ },
+ success: function(data, textStatus, jqXHR) {
+ Utils.checkAndResolveSocketRequest(data, resolve, reject);
+ }
+ })
+ .fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ });;
+ });
+ },
+ success: SkyquakeContainerActions.openProjectSocketSuccess
+ }
+ },
+
+ getUserProfile() {
+ return {
+ remote: function(state, recordID) {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: '/user-profile?api_server=' + API_SERVER,
+ type: 'GET',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data) {
+ resolve(data);
+ }
+ }).fail(function(xhr) {
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ });;
+ });
+ },
+ loading: Alt.actions.global.showScreenLoader,
+ success: SkyquakeContainerActions.getUserProfileSuccess
+ }
+ },
+
+ selectActiveProject() {
+ return {
+ remote: function(state, event) {
+ let projectId;
+ try {
+ projectId = JSON.parse(JSON.parse(event.currentTarget.value));
+ } catch(e) {
+ console.log('Something went wrong in the selectActiveProject source function', e);
+ }
+
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/session/${projectId}?api_server=${API_SERVER}`,
+ type: 'PUT',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data) {
+ resolve(projectId);
+ }
+ }).fail(function(xhr) {
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ });;
+ });
+ },
+ success: SkyquakeContainerActions.selectActiveProjectSuccess
+ }
}
}
import Alt from './skyquakeAltInstance.js';
import SkyquakeContainerSource from './skyquakeContainerSource.js';
import SkyquakeContainerActions from './skyquakeContainerActions';
+let Utils = require('utils/utils.js');
import _indexOf from 'lodash/indexOf';
+import _isEqual from 'lodash/isEqual';
//Temporary, until api server is on same port as webserver
import rw from 'utils/rw.js';
this.nav = {};
this.notifications = [];
this.socket = null;
+ this.projects = [];
+ this.user = {};
//Notification defaults
this.notificationMessage = '';
this.displayNotification = false;
})
}
+ openProjectSocketSuccess = (connection) => {
+ var self = this;
+ var ws = window.multiplexer.channel(connection);
+ if (!connection) return;
+ self.setState({
+ socket: ws.ws,
+ channelId: connection
+ });
+ ws.onmessage = function(socket) {
+ try {
+ var data = JSON.parse(socket.data);
+ Utils.checkAuthentication(data.statusCode, function() {
+ self.closeSocket();
+ });
+ if (!_isEqual(data.project, self.projects)) {
+ let user = self.user;
+ user.projects = data.project;
+ self.setState({
+ user: user,
+ projects: data.project
+ });
+ }
+ } catch(e) {
+ console.log('HIT an exception in openProjectSocketSuccess', e);
+ }
+ };
+ }
+ getUserProfileSuccess = (user) => {
+ this.alt.actions.global.hideScreenLoader.defer();
+ this.setState({user})
+ }
+ selectActiveProjectSuccess = (projectId) => {
+ let user = this.user;
+ user.projectId = projectId;
+ this.setState({user});
+ window.location.reload(true);
+ }
//Notifications
showNotification = (data) => {
let state = {
if(typeof(data) == 'string') {
} else {
- state.notificationMessage = data.msg;
+ if(!data) data = {};
+ state.notificationMessage = data.msg || 'Something wrong occurred. Check the network tab and console logs for more information.';
if(data.type) {
state.notificationType = data.type;
}
+++ /dev/null
-/*
- *
- * Copyright 2016 RIFT.IO Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import React from 'react';
-import { Link } from 'react-router';
-import Utils from 'utils/utils.js';
-import Crouton from 'react-crouton';
-import 'style/common.scss';
-
-//Temporary, until api server is on same port as webserver
-import rw from 'utils/rw.js';
-
-var API_SERVER = rw.getSearchParams(window.location).api_server;
-var UPLOAD_SERVER = rw.getSearchParams(window.location).upload_server;
-
-//
-// Internal classes/functions
-//
-
-class LogoutAppMenuItem extends React.Component {
- handleLogout() {
- Utils.clearAuthentication();
- }
- render() {
- return (
- <div className="app">
- <h2>
- <a onClick={this.handleLogout}>
- Logout
- </a>
- </h2>
- </div>
- );
- }
-}
-
-
-//
-// Exported classes and functions
-//
-
-//
-/**
- * Skyquake Nav Component. Provides navigation functionality between all plugins
- */
-export default class skyquakeNav extends React.Component {
- constructor(props) {
- super(props);
- this.state = {};
- this.state.validateErrorEvent = 0;
- this.state.validateErrorMsg = '';
- }
- validateError = (msg) => {
- this.setState({
- validateErrorEvent: true,
- validateErrorMsg: msg
- });
- }
- validateReset = () => {
- this.setState({
- validateErrorEvent: false
- });
- }
- returnCrouton = () => {
- return <Crouton
- id={Date.now()}
- message={this.state.validateErrorMsg}
- type={"error"}
- hidden={!(this.state.validateErrorEvent && this.state.validateErrorMsg)}
- onDismiss={this.validateReset}
- />;
- }
- render() {
- let html;
- html = (
- <div>
- {this.returnCrouton()}
- <nav className="skyquakeNav">
- {buildNav.call(this, this.props.nav, this.props.currentPlugin)}
- </nav>
-
- </div>
- )
- return html;
- }
-}
-skyquakeNav.defaultProps = {
- nav: {}
-}
-/**
- * Returns a React Component
- * @param {object} link Information about the nav link
- * @param {string} link.route Hash route that the SPA should resolve
- * @param {string} link.name Link name to be displayed
- * @param {number} index index of current array item
- * @return {object} component A React LI Component
- */
-//This should be extended to also make use of internal/external links and determine if the link should refer to an outside plugin or itself.
-export function buildNavListItem (k, link, index) {
- let html = false;
- if (link.type == 'external') {
- this.hasSubNav[k] = true;
- html = (
- <li key={index}>
- {returnLinkItem(link)}
- </li>
- );
- }
- return html;
-}
-
-/**
- * Builds a link to a React Router route or a new plugin route.
- * @param {object} link Routing information from nav object.
- * @return {object} component returns a react component that links to a new route.
- */
-export function returnLinkItem(link) {
- let ref;
- let route = link.route;
- if(link.isExternal) {
- ref = (
- <a href={route}>{link.label}</a>
- )
- } else {
- if(link.path && link.path.replace(' ', '') != '') {
- route = link.path;
- }
- if(link.query) {
- let query = {};
- query[link.query] = '';
- route = {
- pathname: route,
- query: query
- }
- }
- ref = (
- <Link to={route}>
- {link.label}
- </Link>
- )
- }
- return ref;
-}
-
-/**
- * Constructs nav for each plugin, along with available subnavs
- * @param {array} nav List returned from /nav endpoint.
- * @return {array} List of constructed nav element for each plugin
- */
-export function buildNav(nav, currentPlugin) {
- let navList = [];
- let navListHTML = [];
- let secondaryNav = [];
- let self = this;
- self.hasSubNav = {};
- let secondaryNavHTML = (
- <div className="secondaryNav" key="secondaryNav">
- {secondaryNav}
- <LogoutAppMenuItem />
- </div>
- )
- for (let k in nav) {
- if (nav.hasOwnProperty(k)) {
- self.hasSubNav[k] = false;
- let header = null;
- let navClass = "app";
- let routes = nav[k].routes;
- let navItem = {};
- //Primary plugin title and link to dashboard.
- let route;
- let NavList;
- if (API_SERVER) {
- route = routes[0].isExternal ? '/' + k + '/index.html?api_server=' + API_SERVER + '' + '&upload_server=' + UPLOAD_SERVER + '' : '';
- } else {
- route = routes[0].isExternal ? '/' + k + '/' : '';
- }
- let dashboardLink = returnLinkItem({
- isExternal: routes[0].isExternal,
- pluginName: nav[k].pluginName,
- label: nav[k].label || k,
- route: route
- });
- if (nav[k].pluginName == currentPlugin) {
- navClass += " active";
- }
- NavList = nav[k].routes.map(buildNavListItem.bind(self, k));
- navItem.priority = nav[k].priority;
- navItem.order = nav[k].order;
- navItem.html = (
- <div key={k} className={navClass}>
- <h2>{dashboardLink} {self.hasSubNav[k] ? <span className="oi" data-glyph="caret-bottom"></span> : ''}</h2>
- <ul className="menu">
- {
- NavList
- }
- </ul>
- </div>
- );
- navList.push(navItem)
- }
- }
- //Sorts nav items by order and returns only the markup
- navListHTML = navList.sort((a,b) => a.order - b.order).map(function(n) {
- if((n.priority < 2)){
- return n.html;
- } else {
- secondaryNav.push(n.html);
- }
- });
- navListHTML.push(secondaryNavHTML);
- return navListHTML;
-}
--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import React from 'react';
+import { Link } from 'react-router';
+import Utils from 'utils/utils.js';
+import Crouton from 'react-crouton';
+import 'style/common.scss';
+
+import './skyquakeNav.scss';
+import SelectOption from '../form_controls/selectOption.jsx';
+import {FormSection} from '../form_controls/formControls.jsx';
+import {isRBACValid, SkyquakeRBAC} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+
+//Temporary, until api server is on same port as webserver
+import rw from 'utils/rw.js';
+
+var API_SERVER = rw.getSearchParams(window.location).api_server;
+var UPLOAD_SERVER = rw.getSearchParams(window.location).upload_server;
+
+//
+// Internal classes/functions
+//
+
+class LogoutAppMenuItem extends React.Component {
+ handleLogout() {
+ Utils.clearAuthentication();
+ }
+ render() {
+ return (
+ <div className="app">
+ <h2>
+ <a onClick={this.handleLogout}>
+ Logout
+ </a>
+ </h2>
+ </div>
+ );
+ }
+}
+
+class SelectProject extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+ selectProject(e) {
+ let value = JSON.parse(e.currentTarget.value);
+ console.log('selected project', value)
+ }
+ render() {
+ let props = this.props;
+ let currentValue = JSON.stringify(props.currentProject);
+ let projects = this.props.projects && this.props.projects.map((p,i) => {
+ return {
+ label: p.name,
+ value: p.name
+ }
+ });
+ let hasProjects = (this.props.projects && (this.props.projects.length > 0))
+ return (
+ <div className="userSection app">
+ {
+ hasProjects ? 'Project:' : 'No Projects Assigned'
+ }
+ {
+ hasProjects ?
+ <SelectOption
+ options={projects}
+ value={currentValue}
+ defaultValue={currentValue}
+ onChange={props.onSelectProject}
+ className="projectSelect" />
+ : null
+ }
+ </div>
+ )
+ }
+}
+
+class UserNav extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+ handleLogout() {
+ Utils.clearAuthentication();
+ }
+ selectProject(e) {
+ let value = JSON.parse(e.currentTarget.value)
+ console.log('selected project', value)
+ }
+ render() {
+ let props = this.props;
+ let userProfileLink = '';
+ this.props.nav['user_management'] && this.props.nav['user_management'].routes.map((r) => {
+ if(r.unique) {
+ userProfileLink = returnLinkItem(r, props.currentUser)
+ }
+ })
+ return (
+ <div className="app">
+ <h2>
+ USER: {userProfileLink}
+ <span className="oi" data-glyph="caret-bottom"></span>
+ </h2>
+ <ul className="menu">
+ <li>
+ <a onClick={this.handleLogout}>
+ Logout
+ </a>
+ </li>
+ </ul>
+ </div>
+ )
+ }
+}
+
+UserNav.defaultProps = {
+ projects: [
+
+ ]
+}
+
+//
+// Exported classes and functions
+//
+
+//
+/**
+ * Skyquake Nav Component. Provides navigation functionality between all plugins
+ */
+export default class skyquakeNav extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+ this.state.validateErrorEvent = 0;
+ this.state.validateErrorMsg = '';
+ }
+ componentDidMount() {
+ this.props.store.openProjectSocket();
+ this.props.store.getUserProfile();
+ }
+ validateError = (msg) => {
+ this.setState({
+ validateErrorEvent: true,
+ validateErrorMsg: msg
+ });
+ }
+ validateReset = () => {
+ this.setState({
+ validateErrorEvent: false
+ });
+ }
+ returnCrouton = () => {
+ return <Crouton
+ id={Date.now()}
+ message={this.state.validateErrorMsg}
+ type={"error"}
+ hidden={!(this.state.validateErrorEvent && this.state.validateErrorMsg)}
+ onDismiss={this.validateReset}
+ />;
+ }
+ render() {
+ let html;
+ html = (
+ <div>
+ {this.returnCrouton()}
+ <nav className="skyquakeNav">
+ {buildNav.call(this, this.props.nav, this.props.currentPlugin, this.props)}
+ </nav>
+
+ </div>
+ )
+ return html;
+ }
+}
+skyquakeNav.defaultProps = {
+ nav: {}
+}
+skyquakeNav.contextTypes = {
+ userProfile: React.PropTypes.object
+};
+/**
+ * Returns a React Component
+ * @param {object} link Information about the nav link
+ * @param {string} link.route Hash route that the SPA should resolve
+ * @param {string} link.name Link name to be displayed
+ * @param {number} index index of current array item
+ * @return {object} component A React LI Component
+ */
+//This should be extended to also make use of internal/external links and determine if the link should refer to an outside plugin or itself.
+export function buildNavListItem (k, link, index) {
+ let html = false;
+ if (link.type == 'external') {
+ this.hasSubNav[k] = true;
+ html = (
+ <li key={index}>
+ {returnLinkItem(link)}
+ </li>
+ );
+ }
+ return html;
+}
+
+/**
+ * Builds a link to a React Router route or a new plugin route.
+ * @param {object} link Routing information from nav object.
+ * @return {object} component returns a react component that links to a new route.
+ */
+export function returnLinkItem(link, label) {
+ let ref;
+ let route = link.route;
+ if(link.isExternal) {
+ ref = (
+ <a href={route}>{label || link.label}</a>
+ )
+ } else {
+ if(link.path && link.path.replace(' ', '') != '') {
+ route = link.path;
+ }
+ if(link.query) {
+ let query = {};
+ query[link.query] = '';
+ route = {
+ pathname: route,
+ query: query
+ }
+ }
+ ref = (
+ <Link to={route}>
+ {label || link.label}
+ </Link>
+ )
+ }
+ return ref;
+}
+
+
+
+
+/**
+ * Constructs nav for each plugin, along with available subnavs
+ * @param {array} nav List returned from /nav endpoint.
+ * @return {array} List of constructed nav element for each plugin
+ */
+export function buildNav(nav, currentPlugin, props) {
+ let navList = [];
+ let navListHTML = [];
+ let secondaryNav = [];
+ let adminNav = [];
+ let self = this;
+ const User = this.context.userProfile;
+ self.hasSubNav = {};
+ let secondaryNavHTML = (
+ <div className="secondaryNav" key="secondaryNav">
+ {secondaryNav}
+ <div className="app admin">
+ <h2>
+ <a>
+ ADMIN <span className="oi" data-glyph="caret-bottom"></span>
+ </a>
+ </h2>
+ <ul className="menu">
+ {
+ adminNav
+ }
+ </ul>
+ </div>
+ <SelectProject
+ onSelectProject={props.store.selectActiveProject}
+ projects={props.projects}
+ currentProject={props.currentProject} />
+ <UserNav
+ currentUser={props.currentUser}
+ nav={nav} />
+ </div>
+ )
+ for (let k in nav) {
+ if (nav.hasOwnProperty(k)) {
+ self.hasSubNav[k] = false;
+ let header = null;
+ let navClass = "app";
+ let routes = nav[k].routes;
+ let navItem = {};
+ //Primary plugin title and link to dashboard.
+ let route;
+ let NavList;
+ if (API_SERVER) {
+ route = routes[0].isExternal ? '/' + k + '/index.html?api_server=' + API_SERVER + '' + '&upload_server=' + UPLOAD_SERVER + '' : '';
+ } else {
+ route = routes[0].isExternal ? '/' + k + '/' : '';
+ }
+ let dashboardLink = returnLinkItem({
+ isExternal: routes[0].isExternal,
+ pluginName: nav[k].pluginName,
+ label: nav[k].label || k,
+ route: route
+ });
+ let shouldAllow = nav[k].allow || ['*'];
+ if (nav[k].pluginName == currentPlugin) {
+ navClass += " active";
+ }
+ NavList = nav[k].routes.map(buildNavListItem.bind(self, k));
+ navItem.priority = nav[k].priority;
+ navItem.order = nav[k].order;
+ if(nav[k].admin_link) {
+
+ if (isRBACValid(User, shouldAllow) ){
+ adminNav.push((
+ <li key={nav[k].name}>
+ {dashboardLink}
+ </li>
+ ))
+ }
+ } else {
+ if (isRBACValid(User, shouldAllow) ){
+ navItem.html = (
+ <div key={k} className={navClass}>
+ <h2>{dashboardLink} {self.hasSubNav[k] ? <span className="oi" data-glyph="caret-bottom"></span> : ''}</h2>
+ <ul className="menu">
+ {
+ NavList
+ }
+ </ul>
+ </div>
+ );
+ }
+ navList.push(navItem)
+ }
+
+ }
+ }
+ //Sorts nav items by order and returns only the markup
+ navListHTML = navList.sort((a,b) => a.order - b.order).map(function(n) {
+ if((n.priority < 2)){
+ return n.html;
+ } else {
+ secondaryNav.push(n.html);
+ }
+ });
+ navListHTML.push(secondaryNavHTML);
+ return navListHTML;
+}
--- /dev/null
+@import '../../style/_colors.scss';
+.active {
+ background-color: $brand-blue!important;
+ border-color: $brand-blue!important;
+ color: #fff!important
+ }
+ .skyquakeNav {
+ display: -ms-flexbox;
+ display: flex;
+ color:white;
+ background:black;
+ position:relative;
+ z-index: 10;
+ font-size:0.75rem;
+ padding-right:1rem;
+ .secondaryNav {
+ -ms-flex: 1 1 auto;
+ flex: 1 1 auto;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-pack: end;
+ justify-content: flex-end;
+ }
+ .app {
+ display: -ms-flexbox;
+ display: block;
+ position:relative;
+ margin: auto 0.5rem;
+ min-width: 140px;
+ h2 {
+ font-size:0.75rem;
+ border-right: 1px solid black;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-pack: start;
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ -ms-flex-align: center;
+ align-items: center;
+ .oi {
+ padding-right: 0.5rem;
+ }
+ }
+ .menu {
+ position:absolute;
+ display:none;
+ z-index:2;
+ width: 100%;
+ li {
+ text-align:left;
+ }
+ }
+ &:first-child{
+ h2 {
+ border-left: 1px solid black;
+ }
+ }
+ &:hover {
+ a {
+ color:$brand-blue-light;
+ cursor:pointer;
+ }
+ .menu {
+ display:block;
+ background:black;
+ a {
+ color:white;
+ }
+ li:hover {
+ a {
+ color:$brand-blue-light;
+ }
+ }
+ }
+ }
+ &.active {
+ color:white;
+ background:black;
+ a {
+ color:white;
+ }
+ }
+ }
+ a{
+ display:block;
+ padding:0.5rem 1rem;
+ text-decoration:none;
+ text-transform:uppercase;
+ text-align:left;
+ color:white;
+ }
+ &:before {
+ content: '';
+ min-width: 5.5rem;
+ margin: 0.125rem 1rem;
+ background: url('../../style/img/svg/osm-logo_color_rgb_white_text.svg') no-repeat center center;
+ background-size: contain;
+ }
+ .userSection {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-align:center;
+ align-items:center;
+ padding-left: 1rem;
+ text-transform:uppercase;
+ text-align: left;
+ border-left:1px solid white;
+ .projectSelect {
+ padding: 0 0.5rem;
+ font-size: 1rem;
+ /* min-width: 75%;*/
+ height: 25px;
+ }
+ }
+ }
--- /dev/null
+/*
+ *
+ * Copyright 2016 RIFT.IO Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+import React from 'react';
+import ROLES from 'utils/roleConstants.js';
+const PLATFORM = ROLES.PLATFORM;
+
+export function isRBACValid(User, allow){
+ const UserData = User.data;
+ if(UserData) {
+ const PlatformRole = UserData.platform.role;
+ const isPlatformSuper = PlatformRole[PLATFORM.SUPER];
+ const isPlatformAdmin = PlatformRole[PLATFORM.ADMIN];
+ const isPlatformOper = PlatformRole[PLATFORM.OPER];
+ const hasRoleAccess = checkForRoleAccess(UserData.project[User.projectId], PlatformRole, allow)//false//(this.props.roles.indexOf(userProfile.projectRole) > -1)
+ if (isPlatformSuper) {
+ return true;
+ } else {
+ if (hasRoleAccess) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+export default class SkyquakeRBAC extends React.Component {
+ constructor(props, context) {
+ super(props);
+ }
+ render() {
+ const User = this.context.userProfile;
+ const UserData = User.data;
+ let HTML = null;
+ // If user object has platform property then it has been populated by the back end.
+ if(isRBACValid(User, this.props.allow)) {
+ HTML = this.props.children;
+ }
+ return (<div className={this.props.className} style={this.props.style}>{HTML}</div>)
+ }
+}
+SkyquakeRBAC.defaultProps = {
+ allow: []
+}
+SkyquakeRBAC.contextTypes = {
+ userProfile: React.PropTypes.object
+}
+
+function checkForRoleAccess(project, PlatformRole, allow) {
+ if (allow.indexOf('*') > -1) return true;
+ for (let i = 0; i<allow.length; i++) {
+ if((project && project.role[allow[i]] )|| PlatformRole[allow[i]]) {
+ return true
+ }
+ }
+ return false;
+ }
+
+
+
+// export default function(Component) {
+// class SkyquakeRBAC extends React.Component {
+// constructor(props, context) {
+// super(props);
+// }
+// render(props) {
+// console.log(this.context.userProfile)
+// const User = this.context.userProfile.data;
+// // If user object has platform property then it has been populated by the back end.
+// if(User) {
+// const PlatformRole = User.platform.role;
+// const HTML = <Component {...this.props} router={this.router} actions={this.actions} flux={this.context.flux}/>;
+// const isPlatformSuper = PlatformRole[PLATFORM.SUPER];
+// const isPlatformAdmin = PlatformRole[PLATFORM.ADMIN];
+// const isPlatformOper = PlatformRole[PLATFORM.OPER];
+// const hasRoleAccess = false//(this.props.roles.indexOf(userProfile.projectRole) > -1)
+// if (isPlatformSuper || isPlatformOper || isPlatformAdmin) {
+// return HTML
+// } else {
+// if (hasRoleAccess) {
+// return HTML
+// } else {
+// return null;
+// }
+// }
+// }
+// else {
+// return null;
+
+// }
+// }
+// }
+// SkyquakeRBAC.defaultProps = {
+
+// }
+// SkyquakeRBAC.contextTypes = {
+// userProfile: React.PropTypes.object,
+// allowedRoles: []
+// };
+// return SkyquakeRBAC;
+// }
"dependencies": {
"alt": "^0.18.3",
"alt-container": "^1.0.2",
+ "base-64": "^0.1.0",
"bluebird": "^3.4.1",
"body-parser": "^1.14.2",
"cors": "^2.7.1",
-#
+#
# Copyright 2016 RIFT.IO Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
#
# Author(s): Kiran Kashalkar
# Creation Date: 08/18/2015
-#
+#
##
# DEPENDENCY ALERT
composer
config
debug
+ project_management
+ user_management
# goodbyworld
# helloworld
launchpad
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
url: utils.confdPort(api_server) + APIVersion + '/api/operational/vcs/info?deep',
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
url: utils.confdPort(api_server) + APIVersion + '/api/operational/version?deep',
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
url: utils.confdPort(api_server) + APIVersion + '/api/operational/uptime/uptime',
"dashboard": "./about.jsx",
"order": 99,
"priority":2,
+ "admin_link": true,
"routes" : [{
"label": "Dashboard",
"route": "/",
_.extend(
requestHeaders,
id ? constants.HTTP_HEADERS.accept.data : constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
request({
- url: url + '?deep',
+ url: utils.projectContextUrl(req, url + '?deep'),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: url,
+ url: utils.projectContextUrl(req, url),
method: method,
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: url,
+ url: utils.projectContextUrl(req, url),
method: 'DELETE',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var headers = _.extend({},
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/' + rpcInfo[Type].rpc);
+
+ jsonData['input'] = utils.addProjectContextToRPCPayload(req, uri, jsonData['input']);
+
return new Promise(function(resolve, reject) {
request({
- uri: utils.confdPort(api_server) + '/api/operations/' + rpcInfo[Type].rpc,
+ uri: uri,
method: 'POST',
headers: headers,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/operational/cloud/account',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/cloud/account'),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/operational/cloud/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/cloud/account/' + id),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/config/cloud',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/cloud'),
method: 'POST',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/config/cloud/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/cloud/account/' + id),
method: 'PUT',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/config/cloud/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/cloud/account/' + id),
method: 'DELETE',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/operational/cloud/account/' + cloudAccount + '/resources?deep',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/cloud/account/' + cloudAccount + '/resources?deep'),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/operational/cloud/account/' + cloudAccount + '/pools',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/cloud/account/' + cloudAccount + '/pools'),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/operational/config-agent/account',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operational/config-agent/account'),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/operational/config-agent/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operational/config-agent/account/' + id),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/config/config-agent',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/config/config-agent'),
method: 'POST',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/config/config-agent/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/config/config-agent/account/' + id),
method: 'PUT',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/config/config-agent/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/config/config-agent/account/' + id),
method: 'DELETE',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/operational/sdn/account?deep',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operational/sdn/account?deep'),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/operational/sdn/account/' + id + '?deep',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operational/sdn/account/' + id + '?deep'),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/config/sdn/account',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/config/sdn/account'),
method: 'POST',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/config/sdn/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/config/sdn/account/' + id),
method: 'PUT',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + '/api/config/sdn/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/config/sdn/account/' + id),
method: 'DELETE',
headers: requestHeaders,
forever: constants.FOREVER_ON,
"root": "public",
"name": "Accounts",
"dashboard": "./account/accountsDashboard.jsx",
- "order": 1,
+ "order": 3,
"priority":1,
+ "allow": ["rw-rbac-platform:super-admin", "rw-project-mano:account-oper", "rw-project-mano:account-admin"],
"routes": [
{
"label": "Accounts Dashboard",
import Crouton from 'react-crouton';
import TextInput from 'widgets/form_controls/textInput.jsx';
import {AccountConnectivityStatus} from '../account_sidebar/accountSidebar.jsx';
+
import 'style/common.scss';
import './account.scss';
class Account extends React.Component {
value = Account.params[node.ref];
}
paramsStack.push(
- <TextInput key={node.label} className="accountForm-input" label={node.label} required={!node.optional} onChange={this.props.store.handleParamChange(node)} value={value} />
+ <TextInput
+ key={node.label}
+ className="accountForm-input"
+ label={node.label}
+ required={!node.optional}
+ onChange={this.props.store.handleParamChange(node)}
+ value={value}
+ readonly={self.props.readonly}
+
+ />
);
}
// </label>
// );
nestedParamsStack.push(
- <TextInput key={node.label} label={node.label} required={!node.optional} className="create-fleet-pool-input" type="text" onChange={this.props.store.handleNestedParamChange(Account.nestedParams['container-name'], node)} value={value}/>
+ <TextInput
+ key={node.label}
+ label={node.label}
+ required={!node.optional}
+ className="create-fleet-pool-input"
+ type="text"
+ onChange={this.props.store.handleNestedParamChange(Account.nestedParams['container-name'], node)}
+ value={value}
+ readonly={self.props.readonly}
+ />
);
}
}
<AccountConnectivityStatus status={Account['connection-status'].status} />
{Account['connection-status'] && Account['connection-status'].status && Account['connection-status'].status.toUpperCase()}
</div>
- <Button className="refreshList light" onClick={this.props.store.refreshAccount.bind(this, Account.name, AccountType)} label="REFRESH STATUS"></Button>
+ <Button is-disabled={self.props.readonly} className="refreshList light" onClick={this.props.store.refreshAccount.bind(this, Account.name, AccountType)} label="REFRESH STATUS"></Button>
</div>
{
(Account['connection-status'] && Account['connection-status'].status && Account['connection-status'].status.toUpperCase()) === 'FAILURE' ?
{params}
</ol>
<div className="form-actions">
- {buttons}
+ {!self.props.readonly ? buttons : null}
</div>
</form>
)
}
}
+Account.contextTypes = {
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
+}
+
function displayFailureMessage(msg) {
return (
<div className="accountForm-content" style={{maxWidth: '600px'}}>
var Utils = require('utils/utils.js');
var rw = require('utils/rw.js');
var altImage = rw.getSearchParams(window.location).alt_image;
+var _ = require('lodash');
let Params = {
//Config Agent
if(self.currentAccount) {
let Account = self.getAccountFromStream(data[self.currentAccount.type].data, self.currentAccount.name);
newState.account = self.account;
- newState.account['connection-status'] = Account['connection-status']
+ newState.account['connection-status'] = Account && Account['connection-status']
}
self.setState(newState)
} catch(error) {
}
getAccountFromStream(data, name) {
let result = null;
- data.map(function(a) {
+ data && _.isArray(data) && data.map(function(a) {
if(a.name == name) {
result = a;
}
viewAccount = ({type, name}) => {
var data = null;
var accounts = null;
- if(this && this[type].length) {
+ if(this && this[type] && this[type].length) {
accounts = this[type];
data = this.getAccountFromStream(accounts, name);
if(data) {
}
generateOptionsByName(data) {
let results = [];
- if (data && data.constructor.name == "Array") {
+ if (data && _.isArray(data)) {
data.map(function(d) {
results.push({
label: d.name,
import AccountStore from './accountStore.js';
import AccountSidebar from '../account_sidebar/accountSidebar.jsx';
import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
+import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+import ROLES from 'utils/roleConstants.js';
+
+const PROJECT_ROLES = ROLES.PROJECT;
+const PLATFORM = ROLES.PLATFORM;
+
+//Delete this line after testing is done
+// PROJECT_ROLES.ACCOUNT_ADMIN = '';
import 'style/layout.scss';
class AccountsDashboard extends React.Component {
render() {
let self = this;
let html;
+ let READONLY = !isRBACValid(this.context.userProfile, [PROJECT_ROLES.ACCOUNT_ADMIN]);
html = (<div className="launchpad-account-dashboard content-wrapper">
<div className="flex">
- <AccountSidebar {...this.state} store={this.Store}/>
+ <AccountSidebar {...this.state} readonly={READONLY} store={this.Store}/>
<div>
- { this.props.children ? React.cloneElement(this.props.children, {store: self.Store, ...self.state}) : 'Edit or Create New Accounts'
+ { this.props.children ? React.cloneElement(this.props.children, {readonly: READONLY, store: self.Store, ...self.state}) : 'Edit or Create New Accounts'
}
</div>
</div>
}
}
AccountsDashboard.contextTypes = {
- router: React.PropTypes.object
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
};
export default SkyquakeComponent(AccountsDashboard);
}
render() {
let html;
+ let self = this;
let {store, ...props} = this.props;
//[this.props.cloud,this.props.sdn,this.props['config-agent']]
let AccountData = [
<div>
<h1>VIM Accounts</h1>
{cloudAccounts}
- <DashboardCard className="accountSidebarCard">
- <Link
- to={{pathname: '/accounts/cloud/create'}}
- title="Create Cloud Account"
- className={'accountSidebarCard_create'}
- >
- Add VIM Account
- <img src={require("style/img/launchpad-add-fleet-icon.png")}/>
- </Link>
- </DashboardCard>
+ {
+ !self.props.readonly ?
+ <DashboardCard className="accountSidebarCard">
+ <Link
+ to={{pathname: '/accounts/cloud/create'}}
+ title="Create Cloud Account"
+ className={'accountSidebarCard_create'} >
+ Add VIM Account
+ <img src={require("style/img/launchpad-add-fleet-icon.png")}/>
+ </Link>
+ </DashboardCard>
+ : <div style={{margin:'1rem'}}></div>
+ }
</div>)
: null}
<h1>SDN Accounts</h1>
{sdnAccounts}
- <DashboardCard className="accountSidebarCard">
- <Link
- to={{pathname: '/accounts/sdn/create'}}
- title="Create Sdn Account"
- className={'accountSidebarCard_create'}
- >
- Add SDN Account
- <img src={require("style/img/launchpad-add-fleet-icon.png")}/>
- </Link>
- </DashboardCard>
+ {
+ !self.props.readonly ?
+ <DashboardCard className="accountSidebarCard">
+ <Link
+ to={{pathname: '/accounts/sdn/create'}}
+ title="Create Sdn Account"
+ className={'accountSidebarCard_create'}>
+ Add SDN Account
+ <img src={require("style/img/launchpad-add-fleet-icon.png")}/>
+ </Link>
+
+ </DashboardCard>
+ : <div style={{margin:'1rem'}}></div>
+ }
<h1>Config Agent Accounts</h1>
{configAgentAccounts}
- <DashboardCard className="accountSidebarCard">
- <Link
- to={{pathname: '/accounts/config-agent/create'}}
- title="Create Config Agent Account"
- className={'accountSidebarCard_create'}
- >
- Add Config Agent Account
- <img src={require("style/img/launchpad-add-fleet-icon.png")}/>
- </Link>
- </DashboardCard>
+ {
+ !self.props.readonly ?
+ <DashboardCard className="accountSidebarCard">
+ <Link
+ to={{pathname: '/accounts/config-agent/create'}}
+ title="Create Config Agent Account"
+ className={'accountSidebarCard_create'}
+ >
+ Add Config Agent Account
+ <img src={require("style/img/launchpad-add-fleet-icon.png")}/>
+ </Link>
+ </DashboardCard>
+ : <div style={{margin:'1rem'}}></div>
+ }
</div>
);
return html;
Composer.get = function(req) {
var api_server = req.query['api_server'];
var results = {}
+ var projectPrefix = req.session.projectId ? "project-" : "";
return new Promise(function(resolve, reject) {
Promise.all([
rp({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/nsd-catalog/nsd?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/nsd-catalog/nsd?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
resolveWithFullResponse: true
}),
rp({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/vnfd-catalog/vnfd?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/vnfd-catalog/vnfd?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
resolveWithFullResponse: true
}),
rp({
- uri: utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-opdata?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-opdata?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
// headers: _.extend({},
// constants.HTTP_HEADERS.accept.collection,
// {
- // 'Authorization': req.get('Authorization')
+ // 'Authorization': req.session && req.session.authorization
// }),
// forever: constants.FOREVER_ON,
// rejectUnauthorized: false,
"descriptors": []
}];
if (result[0].body) {
- response[0].descriptors = JSON.parse(result[0].body).collection['nsd:nsd'];
+ response[0].descriptors = JSON.parse(result[0].body).collection[projectPrefix + 'nsd:nsd'];
if (result[2].body) {
var data = JSON.parse(result[2].body);
if (data && data["nsr:ns-instance-opdata"] && data["nsr:ns-instance-opdata"]["rw-nsr:nsd-ref-count"]) {
}
};
if (result[1].body) {
- response[1].descriptors = JSON.parse(result[1].body).collection['vnfd:vnfd'];
+ response[1].descriptors = JSON.parse(result[1].body).collection[projectPrefix + 'vnfd:vnfd'];
};
// if (result[2].body) {
- // response[2].descriptors = JSON.parse(result[2].body).collection['pnfd:pnfd'];
+ // response[2].descriptors = JSON.parse(result[2].body).collection[projectPrefix + 'pnfd:pnfd'];
// };
resolve({
statusCode: response.statusCode || 200,
console.log('Deleting', catalogType, id, 'from', api_server);
return new Promise(function(resolve, reject) {
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog/' + catalogType + '/' + id,
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog/' + catalogType + '/' + id),
method: 'DELETE',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
Composer.getVNFD = function(req) {
var api_server = req.query['api_server'];
var vnfdID = req.body.data;
- var authorization = req.get('Authorization');
+ var authorization = req.session && req.session.authorization;
var VNFDs = [];
if (typeof(vnfdID) == "object" && vnfdID.constructor.name == "Array") {
vnfdID.map(function(id) {
return new Promise(function(resolve, reject) {
var url = utils.confdPort(api_server) + APIVersion + '/api/config/vnfd-catalog/vnfd' + (id ? '/' + id : '') + '?deep';
request({
- uri: url,
+ uri: utils.projectContextUrl(req, url),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
'Authorization': authorization
return new Promise(function(resolve, reject) {
var requestHeaders = {};
_.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- uri: utils.confdPort(api_server) + '/api/config/' + catalogType + '-catalog',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/config/' + catalogType + '-catalog'),
method: 'POST',
headers: requestHeaders,
forever: constants.FOREVER_ON,
return new Promise(function(resolve, reject) {
var requestHeaders = {};
_.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog' + '/' + catalogType + '/' + id,
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog' + '/' + catalogType + '/' + id),
method: 'PUT',
headers: requestHeaders,
forever: constants.FOREVER_ON,
download_host = req.protocol + '://' + req.get('host');//req.api_server + ':' + utils.getPortForProtocol(req.protocol);
}
+ var input = {
+ 'external-url': download_host + '/composer/upload/' + req.file.filename,
+ 'package-type': 'VNFD',
+ 'package-id': uuid()
+ }
+
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-create');
+
+ input = utils.addProjectContextToRPCPayload(req, uri, input);
+
return new Promise(function(resolve, reject) {
Promise.all([
rp({
- uri: utils.confdPort(api_server) + '/api/operations/package-create',
+ uri: uri,
method: 'POST',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
resolveWithFullResponse: true,
json: true,
body: {
- input: {
- 'external-url': download_host + '/composer/upload/' + req.file.filename,
- 'package-type': 'VNFD',
- 'package-id': uuid()
- }
+ input: input
}
})
]).then(function(result) {
data['transaction_id'] = result[0].body['output']['transaction-id'];
// Add a status checker on the transaction and then to delete the file later
- PackageFileHandler.checkCreatePackageStatusAndHandleFile(req, data['transaction_id']);
+ PackageFileHandler.checkCreatePackageStatusAndHandleFile(req, data['transaction_id'], true);
// Return status to composer UI to update the status.
resolve({
'external-url': download_host + '/composer/update/' + req.file.filename,
'package-type': 'VNFD',
'package-id': uuid()
- }
+ };
+
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-update');
+
+ input = utils.addProjectContextToRPCPayload(req, uri, input);
+
return new Promise(function(resolve, reject) {
Promise.all([
rp({
- uri: utils.confdPort(api_server) + '/api/operations/package-update',
+ uri: uri,
method: 'POST',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
PackageManager.export = function(req) {
// /api/operations/package-export
var api_server = req.query['api_server'];
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-export');
+ var input = req.body;
+ input = utils.addProjectContextToRPCPayload(req, uri, input);
return new Promise(function(resolve, reject) {
Promise.all([
rp({
uri: utils.confdPort(api_server) + '/api/operations/package-export',
method: 'POST',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
resolveWithFullResponse: true,
json: true,
- body: { "input": req.body}
+ body: { "input": input }
})
]).then(function(result) {
var data = {};
PackageManager.copy = function(req) {
// /api/operations/package-copy
var api_server = req.query['api_server'];
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-copy');
+ var input = req.body;
+ input = utils.addProjectContextToRPCPayload(req, uri, input);
+
return new Promise(function(resolve, reject) {
Promise.all([
rp({
- uri: utils.confdPort(api_server) + '/api/operations/package-copy',
+ uri: uri,
method: 'POST',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
'Authorization': req.get('Authorization')
rejectUnauthorized: false,
resolveWithFullResponse: true,
json: true,
- body: { "input": req.body}
+ body: { "input": input}
})
]).then(function(result) {
var data = {};
var api_server = req.query["api_server"];
var uri = utils.confdPort(api_server);
var id = req.params['id'];
- var url = uri + '/api/operational/copy-jobs' + (id ? '/job/' + id : '');
+ var url = utils.projectContextUrl(req, uri + '/api/operational/copy-jobs' + (id ? '/job/' + id : ''));
return new Promise(function(resolve, reject) {
request({
url: url,
'package-type': package_type,
'package-id': package_id,
'package-path': package_path + '/' + req.file.filename
- }
+ };
+
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-file-add');
+
+ input = utils.addProjectContextToRPCPayload(req, uri, input);
+
+
return new Promise(function(resolve, reject) {
Promise.all([
rp({
- uri: utils.confdPort(api_server) + '/api/operations/package-file-add',
+ uri: uri,
method: 'POST',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
'Authorization': req.get('Authorization')
}
function deleteFile(payload) {
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/rw-pkg-mgmt:package-file-delete');
+ payload.input = utils.addProjectContextToRPCPayload(req, uri, payload.input);
return new Promise(function(resolve, reject) {
rp({
- uri: utils.confdPort(api_server) + '/api/operations/rw-pkg-mgmt:package-file-delete',
+ uri: uri,
method: 'POST',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
json: payload,
forever: constants.FOREVER_ON,
})
}
function download(payload) {
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/rw-pkg-mgmt:package-file-add');
+ payload.input = utils.addProjectContextToRPCPayload(req, uri, payload.input);
return new Promise(function(resolve, reject) {
rp({
- uri: utils.confdPort(api_server) + '/api/operations/rw-pkg-mgmt:package-file-add',
+ uri: uri,
method: 'POST',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
json: payload,
forever: constants.FOREVER_ON,
})
}
function list(payload) {
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/get-package-endpoint');
+ payload.input = utils.addProjectContextToRPCPayload(req, uri, payload.input);
return new Promise(function(resolve, reject) {
rp({
- uri: utils.confdPort(api_server) + '/api/operations/get-package-endpoint',
+ uri: uri,
method: 'POST',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
json: payload,
forever: constants.FOREVER_ON,
}
parsedEndpoint = URL.parse(endpoint);
rp({
- uri: api_server + ':' + parsedEndpoint.port + parsedEndpoint.path,
+ uri: utils.projectContextUrl(req, api_server + ':' + parsedEndpoint.port + parsedEndpoint.path),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
var id = req.params['id'];
return new Promise(function(resolve, reject) {
request({
- url: uri + url + '?deep',
+ url: utils.projectContextUrl(req, uri + url + '?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
var fs = require('fs');
var _ = require('lodash');
-PackageFileHandler = {};
+var PackageFileHandler = {};
function deleteFile(filename) {
setTimeout(function() {
var upload_server = req.query['upload_server'];
var headers = _.extend({},
{
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
var type = isUpdate ? 'update' : 'upload';
"name": "Catalog",
"dashboard" : "./src/components/ComposerApp.js",
"order": 2,
+ "allow": [
+ "rw-rbac-platform:super-admin",
+ "rw-project-mano:catalog-oper",
+ "rw-project-mano:catalog-admin"],
"routes" : [{
"label": "Catalog",
"route": "/",
label: null,
title: null,
src: null,
+ disabled: false,
onClick: () => {}
};
},
const title = this.props.title;
const draggable = this.props.draggable;
const className = ClassNames(this.props.className, 'Button');
+ let style = {
+ }
+ if(this.props.disabled) {
+ style.pointerEvents = 'none';
+ style.cursor = 'not-allowed';
+ style.opacity = 0.25;
+ }
return (
- <div className={className} onClick={this.props.onClick} title={title} draggable={draggable} onDragStart={this.props.onDragStart}>
+ <div className={className} onClick={this.props.onClick} title={title} draggable={draggable} onDragStart={this.props.onDragStart} style={style}>
{ src ? <img src={src} /> : null }
{label}
</div>
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
import React from 'react'
import PureRenderMixin from 'react-addons-pure-render-mixin'
import EditDescriptorModelProperties from './EditDescriptorModelProperties'
+import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+import ROLES from 'utils/roleConstants.js';
+const PROJECT_ROLES = ROLES.PROJECT;
+const PLATFORM = ROLES.PLATFORM;
const CatalogItemDetailsEditor = React.createClass({
mixins: [PureRenderMixin],
width: 0
};
},
+ contextTypes: {
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
+ },
componentWillMount() {
},
componentDidMount() {
componentWillUnmount() {
},
render() {
+ const User = this.context.userProfile;
const container = this.props.container || {model: {}, uiState: {}};
if (!(container && container.model && container.uiState)) {
<div className="CatalogItemDetailsEditor">
<form name="details-descriptor-editor-form">
<div className="properties-group">
- <EditDescriptorModelProperties container={this.props.container} width={this.props.width} />
+ {
+ isRBACValid(User, [PROJECT_ROLES.CAT_ADMIN]) ?
+ <EditDescriptorModelProperties container={this.props.container} width={this.props.width} />
+ : <EditDescriptorModelProperties container={this.props.container} width={this.props.width} readonly={true} />
+ }
</div>
</form>
</div>
}
});
-
export default CatalogItemDetailsEditor;
const isLoading = this.props.isLoading;
return (
<div className={className} data-resizable="right" data-resizable-handle-offset="0 6" style={{width: this.props.layout.left}}>
- <CatalogPanelToolbar />
+ <CatalogPanelToolbar rbacDisabled={this.props.rbacDisabled} />
<div className="CatalogPanelBody">
{(() => {
if (isLoading) {
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
import imgUpdate from '../../../node_modules/open-iconic/svg/rain.svg'
import imgDownload from '../../../node_modules/open-iconic/svg/cloud-download.svg'
import imgDelete from '../../../node_modules/open-iconic/svg/trash.svg'
+import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+import ROLES from 'utils/roleConstants.js';
+const PROJECT_ROLES = ROLES.PROJECT;
+const PLATFORM = ROLES.PLATFORM;
const CatalogHeader = React.createClass({
mixins: [PureRenderMixin],
},
componentWillUnmount() {
},
+ contextTypes: {
+ userProfile: React.PropTypes.object
+ },
render() {
+ const disabled = !isRBACValid(this.context.userProfile, [PROJECT_ROLES.CAT_ADMIN]);
return (
<div className="CatalogPanelToolbar">
<h1>Descriptor Catalogs</h1>
<div className="btn-bar">
<div className="btn-group">
- <Button type="image" title="OnBoard a catalog package" className="action-onboard-catalog-package" onClick={this.onClickOnBoardCatalog} src={imgOnboard} />
- <Button type="image" title="Update a catalog package" className="action-update-catalog-package" onClick={this.onClickUpdateCatalog} src={imgUpdate} />
- <Button type="image" title="Export selected catalog item(s)" className="action-export-catalog-items" onClick={this.onClickExportCatalogItems} src={imgDownload} />
+ <Button type="image" title="OnBoard a catalog package" className="action-onboard-catalog-package" onClick={this.onClickOnBoardCatalog} src={imgOnboard} disabled={disabled}/>
+ <Button type="image" title="Update a catalog package" className="action-update-catalog-package" onClick={this.onClickUpdateCatalog} src={imgUpdate} disabled={disabled}/>
+ <Button type="image" title="Export selected catalog item(s)" className="action-export-catalog-items" onClick={this.onClickExportCatalogItems} src={imgDownload} disabled={disabled}/>
</div>
<div className="btn-group">
<div className="menu">
- <Button type="image" title="Create a new catalog item" className="action-create-catalog-item" onClick={this.onClickCreateCatalogItem.bind(null, 'nsd')} src={imgAdd} />
+ <Button type="image" title="Create a new catalog item" className="action-create-catalog-item" onClick={this.onClickCreateCatalogItem.bind(null, 'nsd')} src={imgAdd} disabled={disabled}/>
<div className="sub-menu">
- <Button type="image" title="Create a new catalog item" className="action-create-catalog-item" onClick={this.onClickCreateCatalogItem.bind(null, 'nsd')} src={imgAdd} label="Add NSD" />
- <Button type="image" title="Create a new catalog item" className="action-create-catalog-item" onClick={this.onClickCreateCatalogItem.bind(null, 'vnfd')} src={imgAdd} label="Add VNFD" />
+ <Button type="image" title="Create a new catalog item" className="action-create-catalog-item" onClick={this.onClickCreateCatalogItem.bind(null, 'nsd')} src={imgAdd} label="Add NSD" disabled={disabled}/>
+ <Button type="image" title="Create a new catalog item" className="action-create-catalog-item" onClick={this.onClickCreateCatalogItem.bind(null, 'vnfd')} src={imgAdd} label="Add VNFD" disabled={disabled}/>
</div>
</div>
- <Button type="image" title="Copy catalog item" className="action-copy-catalog-item" onClick={this.onClickDuplicateCatalogItem} src={imgCopy} />
+ <Button type="image" title="Copy catalog item" className="action-copy-catalog-item" onClick={this.onClickDuplicateCatalogItem} src={imgCopy} disabled={disabled}/>
</div>
<div className="btn-group">
- <Button type="image" title="Delete catalog item" className="action-delete-catalog-item" onClick = {this.onClickDeleteCatalogItem} src={imgDelete} />
+ <Button type="image" title="Delete catalog item" className="action-delete-catalog-item" onClick = {this.onClickDeleteCatalogItem} src={imgDelete} disabled={disabled}/>
</div>
</div>
</div>
import CatalogItemsActions from '../actions/CatalogItemsActions'
import CommonUtils from 'utils/utils.js'
import FileManagerActions from './filemanager/FileManagerActions';
+import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+import ROLES from 'utils/roleConstants.js';
+
import 'normalize.css'
import '../styles/AppRoot.scss'
import 'style/layout.scss'
const preventDefault = e => e.preventDefault();
const clearDragState = () => ComposerAppActions.setDragState(null);
+const PROJECT_ROLES = ROLES.PROJECT;
+const PLATFORM = ROLES.PLATFORM;
const ComposerApp = React.createClass({
mixins: [PureRenderMixin],
getDefaultProps() {
return {};
},
+ contextTypes: {
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
+ },
componentWillMount() {
if (clearLocalStorage) {
window.localStorage.clear();
render() {
let html = null;
let self = this;
+ const User = this.context.userProfile || {};
+ const rbacDisabled = !isRBACValid(User, [PROJECT_ROLES.CAT_ADMIN]);
if(this.state.hasModel) {
function onClickUpdateSelection(event) {
<CatalogPanel layout={self.state.layout}
isLoading={isLoading}
hasNoCatalogs={hasNoCatalogs}
- filterByType={self.state.filterCatalogByTypeValue} />
+ filterByType={self.state.filterCatalogByTypeValue}
+ rbacDisabled={rbacDisabled} />
<CanvasPanel layout={self.state.layout}
hasNoCatalogs={hasNoCatalogs}
showMore={self.state.showMore}
newPathName={self.state.newPathName}
item={self.state.item}
type={self.state.filterCatalogByTypeValue}
+ rbacDisabled={rbacDisabled}
/>
{
(self.state.panelTabShown == 'descriptor') ?
isEditingVNFD={isEditingVNFD}
isModified={isModified}
isNew={isNew}
- disabled={!hasItem}
+ disabled={!hasItem || rbacDisabled}
onClick={event => event.stopPropagation()}
panelTabShown={self.state.panelTabShown}/>
</div>
});
+
export default ComposerApp;
const style = {left: this.props.layout.left};
const saveClasses = ClassNames('ComposerAppSave', {'primary-action': this.props.isModified || this.props.isNew});
const cancelClasses = ClassNames('ComposerAppCancel', {'secondary-action': this.props.isModified});
- if (this.props.disabled) {
- return (
- <div className="ComposerAppToolbar" style={style}></div>
- );
- }
+ let isDisabled = this.props.disabled;
+ console.log('rbacDisabled', isDisabled )
const hasSelection = SelectionManager.getSelections().length > 0;
if(this.props.panelTabShown != 'descriptor') {
style.pointerEvents = 'none';
if (this.props.isEditingNSD || this.props.isEditingVNFD) {
return (
<div className="FileActions">
- <Button className={saveClasses} onClick={this.onClickSave} label={messages.getSaveActionLabel(this.props.isNew)} src={imgSave} />
- <Button className={cancelClasses} onClick={this.onClickCancel} label="Cancel" src={imgCancel} />
- <Button className="ComposerAppToggleJSONViewerAction" onClick={this.toggleJSONViewer} label="YAML Viewer" src={imgJSONViewer} />
+ <Button className={saveClasses} onClick={this.onClickSave} label={messages.getSaveActionLabel(this.props.isNew)} src={imgSave} disabled={isDisabled} />
+ <Button className={cancelClasses} onClick={this.onClickCancel} label="Cancel" src={imgCancel} disabled={isDisabled} />
+ <Button className="ComposerAppToggleJSONViewerAction" onClick={this.toggleJSONViewer} label="YAML Viewer" src={imgJSONViewer} disabled={isDisabled} />
</div>
);
}
})()}
<div className="LayoutActions">
- <Button className="action-auto-layout" onClick={this.onClickAutoLayout} label="Auto Layout" src={imgLayout} />
+ <Button className="action-auto-layout" onClick={this.onClickAutoLayout} label="Auto Layout" src={imgLayout} disabled={isDisabled} />
{this.props.isEditingNSD ||
this.props.isEditingVNFD ? <Button className="action-add-vld"
+ disabled={isDisabled}
draggable="true"
label={this.props.isEditingNSD ? 'Add VLD' : 'Add IVLD'}
src={imgVLD}
onDragStart={this.onDragStartAddVld}
onClick={this.onClickAddVld} /> : null}
{this.props.isEditingNSD ? <Button className="action-add-vnffg"
+ disabled={isDisabled}
draggable="true"
label="Add VNFFG"
src={imgFG}
onDragStart={this.onDragStartAddVnffg}
onClick={this.onClickAddVnffg} /> : null}
{this.props.isEditingVNFD ? <Button className="action-add-vdu"
+ disabled={isDisabled}
draggable="true"
label="Add VDU"
src={imgVDU}
onDragStart={this.onDragStartAddVdu}
onClick={this.onClickAddVdu} /> : null}
- <Button type="image" title="Delete selected items" className="action-delete-selected-items" disabled={!hasSelection} onClick = {this.onClickDeleteSelected} src={imgDelete} label="Delete" />
+ <Button type="image" title="Delete selected items" className="action-delete-selected-items" disabled={!hasSelection || isDisabled} onClick = {this.onClickDeleteSelected} src={imgDelete} label="Delete" />
</div>
</div>
);
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
},
componentWillUnmount() {
},
+ contextTypes: {
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
+ },
render() {
let json = '{}';
let bodyComponent = messages.detailsWelcome();
export default function EditDescriptorModelProperties(props) {
const container = props.container;
+ const readonly = props.readonly;
+ const isEditable = !readonly; //true
if (!(DescriptorModelFactory.isContainer(container))) {
return
}
CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot());
}
+ if(readonly) {
+ return null;
+ }
return (
<Button className="inline-hint" onClick={onClickAddProperty.bind(container, property, path)} label="Add" src={imgAdd} />
);
}
CatalogItemsActions.catalogItemDescriptorChanged(this.getRoot());
}
+ if(readonly) {
+ return null;
+ }
return (
<Button className="remove-property-action inline-hint" title="Remove" onClick={onClickRemoveProperty.bind(container, property, path)} label="Remove" src={imgRemove}/>
);
onBlur={endEditing}
onMouseDown={startEditing}
onMouseOver={startEditing}
- readOnly={!isEditable}>
+ disabled={!isEditable}>
{options}
</select>
);
onBlur={endEditing}
onMouseDown={startEditing}
onMouseOver={startEditing}
- readOnly={!isEditable}>
+ disabled={!isEditable}>
{options}
</select>
);
onBlur={endEditing}
onMouseDown={startEditing}
onMouseOver={startEditing}
- readOnly={!isEditable}>
+ disabled={!isEditable}>
{options}
</select>
);
onBlur={endEditing}
onMouseDown={startEditing}
onMouseOver={startEditing}
- readOnly={!isEditable}>
+ disabled={!isEditable}>
{options}
</select>
);
onMouseOver={startEditing}
onMouseOut={endEditing}
onMouseLeave={endEditing}
- readOnly={!isEditable} />
+ disabled={!isEditable} />
);
}
onMouseOver={startEditing}
onMouseOut={endEditing}
onMouseLeave={endEditing}
- readOnly={!isEditable}
+ disabled={!isEditable}
/>
);
// write the current choice value into the state
let choiceObject = utils.resolvePath(this.model, [name, selected].join('.'));
let isTopCase = false;
- if (!choiceObject) {
+ if (choiceObject) {
isTopCase = true;
choiceObject = utils.resolvePath(this.model, [selected].join('.'));
}
onMouseOver={startEditing}
onMouseOut={endEditing}
onMouseLeave={endEditing}
+ disabled={!isEditable}
>
{options}
</select>
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
import onCutDelegateToRemove from './onCutDelegateToRemove'
import onClickSelectAndShowInDetailsPanel from './onClickSelectAndShowInDetailsPanel'
+import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+import ROLES from 'utils/roleConstants.js';
+const PROJECT_ROLES = ROLES.PROJECT;
+const PLATFORM = ROLES.PLATFORM;
+
import '../../styles/EditForwardingGraphPaths.scss'
import imgNSD from '../../images/default-catalog-icon.svg'
<div key={i} className={fg.className} data-uid={fg.uid} data-offset-width="true" onClick={onClickSelectAndShowInDetailsPanel.bind(null, fg)} onCut={onCutDelegateToRemove.bind(null, fg)}>
<div key="outline-indicator" data-outline-indicator="true"></div>
<div className="header-actions">
- <Button className="remove-forwarding-graph" title="Remove" onClick={onClickRemoveForwardingGraph.bind(null, fg)} src={imgRemove}/>
+ {
+ this.isRBACValid ?
+ <Button className="remove-forwarding-graph" title="Remove" onClick={onClickRemoveForwardingGraph.bind(null, fg)} src={imgRemove}/>
+ : null
+ }
</div>
<LayoutRow primaryActionColumn={toggleSelectAllPaths} secondaryActionColumn={<img className="fg-icon" src={imgFG} width="20px" />}>
<small>{fg.title}</small>
{fg.classifier.map(mapClassifier.bind(null, context))}
<div className="footer-actions">
<div className="row-action-column">
- <Button className="create-new-classifier" src={imgAdd} width="20px" onClick={onClickAddClassifier.bind(null, context, fg)} label="Add Classifier" />
+ {
+ this.isRBACValid ?
+ <Button className="create-new-classifier" src={imgAdd} width="20px" onClick={onClickAddClassifier.bind(null, context, fg)} label="Add Classifier" />
+ : null
+ }
</div>
</div>
</div>
{forwardingGraphs}
<div className="footer-actions">
<div className="row-action-column">
- <Button className="create-new-forwarding-graph" src={imgAdd} width="20px" onClick={onClickAddForwardingGraph.bind(null, nsd)} label="Add new Forwarding Graph" />
+ {
+ this.isRBACValid ?
+ <Button className="create-new-forwarding-graph" src={imgAdd} width="20px" onClick={onClickAddForwardingGraph.bind(null, nsd)} label="Add new Forwarding Graph" />
+ : null
+ }
</div>
</div>
</div>
},
componentWillUnmount: function () {
},
+ contextTypes: {
+ userProfile: React.PropTypes.object
+ },
render() {
-
const containers = this.props.containers;
const context = {
component: this,
- containers: containers
+ containers: containers,
+ isRBACValid: isRBACValid(this.context.userProfile, [PROJECT_ROLES.CAT_ADMIN])
};
-
const networkService = containers.filter(d => d.type === 'nsd');
if (networkService.length === 0) {
return <p className="welcome-message">No <img src={imgNSD} width="20px" /> NSD open in the canvas. Try opening an NSD.</p>;
+++ /dev/null
-/*
- *
- * Copyright 2016 RIFT.IO Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-import guid from '../libraries/guid'
-import DropZone from 'dropzone'
-import Utils from '../libraries/utils'
-import CatalogPackageManagerActions from '../actions/CatalogPackageManagerActions'
-import ReactDOM from 'react-dom'
-import $ from 'jquery'
-
-const API_SERVER = Utils.getSearchParams(window.location).api_server;
-
-
-
-
-export default class PackageManager {
- constructor(element, button, action) {
- this.stagingArea = {
- packages: {
- ids: []
- }
- }
- this.stagingAreaMonitor = null;
- }
- createStagingArea(type, name) {
- return $.ajax({
- url: Utils.getSearchParams(window.location).api_server + ':8008/api/operations/create-staging-area',
- type: 'POST',
- data: {
- "input" : {
- // Package type not important for package upload.
- "package-type": type || "NSD",
- "name": name || "Package Staging Area"
- }
- },
- error: function() {
- console.log('Something went wrong creating the staging area: ', arguments)
- }
- }).then(function(data) {
- /*
- {
- "output": {
- "endpoint": "api/upload/85f8e2dc-638b-46e7-89cb-ee8de322066f",
- "port": "4568"
- }
- }
- */
- const id = data.output.endpoint.split('/')[2];
- const port = data.output.port;
- this.stagingArea.packages.ids.push(id);
- this.stagingArea.packages[id] = {
- port: port
- };
- return data
- })
- }
- monitoringStagingAreaSocket() {
- let self = this;
- if(self.stagingAreaMonitor) {
- return self.stagingAreaMonitor;
- }
- new Promise(function(resolve, reject) {
- $.ajax({
- url: '/socket-polling',
- type: 'POST',
- beforeSend: Utils.addAuthorizationStub,
- data: {
- url: 'launchpad/api/nsr?api_server=' + API_SERVER
- },
- success: function(data, textStatus, jqXHR) {
- Utils.checkAndResolveSocketRequest(data, resolve, reject, self.monitoringStagingAreaSocketHandler);
- }
- })
- })
-
- return undefined;
- }
- monitoringStagingAreaSocketHandler(connection) {
- let self = this;
- let ws = window.multiplexer.channel(connection);
- if (!connection) return;
- self.stagingAreaMonitor = connection;
- ws.onmessage = function(socket) {
- try {
- Utils.checkAuthentication(data.statusCode, function() {
- ws.close();
- });
-
- } catch(e) {
- console.log('An exception occurred in monitoringStagingAreaSocketHandler', e)
- }
- }
- }
-
-}
-
-
-
console.log('Something went wrong while resolving a leafref. Reached a leaf with predicate.');
} else {
// contains no predicate
+ if (!objectCopy) {
+ break;
+ }
results.push(objectCopy[fragment]);
}
}
}
} else {
// contains no predicate
+ if (!objectCopy) {
+ break;
+ }
objectCopy = objectCopy[fragment];
if (!objectCopy) {
// contains no value
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
font-size: 11px;
}
}
-}
\ No newline at end of file
+}
_.extend(
requestHeaders,
id ? constants.HTTP_HEADERS.accept.data : constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
request({
- url: url + '?deep',
+ url: utils.projectContextUrl(req, url + '?deep'),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: url,
+ url: utils.projectContextUrl(req, url),
method: method,
headers: requestHeaders,
forever: constants.FOREVER_ON,
"dashboard": "./dashboard/dashboard.jsx",
"order": 1,
"priority":1,
+ "admin_link": true,
"routes": [
{
"label": "Configuration Dashboard",
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
url: utils.confdPort(api_server) + APIVersion +'/api/operational/crash?deep',
"dashboard": "./crash.jsx",
"order": 100,
"priority":2,
+ "admin_link": true,
"routes" : [{
"label": "Debug",
"route": "/",
RPC.executeNSServicePrimitive = function(req) {
var api_server = req.query['api_server'];
return new Promise(function(resolve, reject) {
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operations/exec-ns-service-primitive');
var jsonData = {
- "input": req.body
+ "input": utils.addProjectContextToRPCPayload(req, uri, req.body)
};
var headers = _.extend({},
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/operations/exec-ns-service-primitive',
+ url: uri,
method: 'POST',
headers: headers,
forever: constants.FOREVER_ON,
// var nsr_id = req.body['nsr_id_ref'];
// var nsConfigPrimitiveName = req.body['name'];
return new Promise(function(resolve, reject) {
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operations/get-ns-service-primitive-values');
+
var jsonData = {
- "input": req.body
+ "input": utils.addProjectContextToRPCPayload(req, uri, req.body)
};
var headers = _.extend({},
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/operations/get-ns-service-primitive-values',
+ uri: uri,
method: 'POST',
headers: headers,
forever: constants.FOREVER_ON,
}
}
jsonData.input[rpcInfo[Type].label] = Name;
+
+ var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operations/' + rpcInfo[Type].rpc);
+
+ jsonData.input = utils.addProjectContextToRPCPayload(req, uri, jsonData.input);
+
var headers = _.extend({},
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
return new Promise(function(resolve, reject) {
-
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/operations/' + rpcInfo[Type].rpc,
+ uri: uri,
method: 'POST',
headers: headers,
forever: constants.FOREVER_ON,
Catalog.get = function(req) {
var api_server = req.query['api_server'];
var results = {}
+ var projectPrefix = req.session.projectId ? "project-" : "";
return new Promise(function(resolve, reject) {
Promise.all([
rp({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/nsd-catalog/nsd?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/nsd-catalog/nsd?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
resolveWithFullResponse: true
}),
rp({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/vnfd-catalog/vnfd?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/vnfd-catalog/vnfd?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
resolveWithFullResponse: true
}),
rp({
- uri: utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-opdata?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-opdata?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
// headers: _.extend({},
// constants.HTTP_HEADERS.accept.collection,
// {
- // 'Authorization': req.get('Authorization')
+ // 'Authorization': req.session && req.session.authorization
// }),
// forever: constants.FOREVER_ON,
// rejectUnauthorized: false,
var vnfdCatalog = null;
var vnfdDict = {};
if (result[1].body) {
- vnfdCatalog = JSON.parse(result[1].body).collection['vnfd:vnfd'].map(function(v, i) {
+ vnfdCatalog = JSON.parse(result[1].body).collection[projectPrefix + 'vnfd:vnfd'].map(function(v, i) {
vnfdDict[v.id] = v['short-name'] || v.name;
})
}
if (result[0].body) {
- response[0].descriptors = JSON.parse(result[0].body).collection['nsd:nsd'];
+ response[0].descriptors = JSON.parse(result[0].body).collection[projectPrefix + 'nsd:nsd'];
if (result[2].body) {
var data = JSON.parse(result[2].body);
if (data && data["nsr:ns-instance-opdata"] && data["nsr:ns-instance-opdata"]["rw-nsr:nsd-ref-count"]) {
}
};
if (result[1].body) {
- response[1].descriptors = JSON.parse(result[1].body).collection['vnfd:vnfd'];
+ response[1].descriptors = JSON.parse(result[1].body).collection[projectPrefix + 'vnfd:vnfd'];
};
// if (result[2].body) {
- // response[2].descriptors = JSON.parse(result[2].body).collection['pnfd:pnfd'];
+ // response[2].descriptors = JSON.parse(result[2].body).collection[projectPrefix + 'pnfd:pnfd'];
// };
resolve({
statusCode: response.statusCode || 200,
console.log('Deleting', catalogType, id, 'from', api_server);
return new Promise(function(resolve, reject) {
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog/' + catalogType + '/' + id,
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog/' + catalogType + '/' + id),
method: 'DELETE',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
Catalog.getVNFD = function(req) {
var api_server = req.query['api_server'];
var vnfdID = req.body.data;
- var authorization = req.get('Authorization');
+ var authorization = req.session && req.session.authorization;
var VNFDs = [];
if (typeof(vnfdID) == "object" && vnfdID.constructor.name == "Array") {
vnfdID.map(function(id) {
return new Promise(function(resolve, reject) {
var url = utils.confdPort(api_server) + APIVersion + '/api/config/vnfd-catalog/vnfd' + (id ? '/' + id : '') + '?deep';
request({
- uri: url,
+ uri: utils.projectContextUrl(req, url),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
'Authorization': authorization
return new Promise(function(resolve, reject) {
var requestHeaders = {};
_.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog'),
method: 'POST',
headers: requestHeaders,
forever: constants.FOREVER_ON,
return new Promise(function(resolve, reject) {
var requestHeaders = {};
_.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog' + '/' + catalogType + '/' + id,
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog' + '/' + catalogType + '/' + id),
method: 'PUT',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var nsrPromises = [];
var api_server = req.query["api_server"];
var id = req.params.id;
+ var projectPrefix = req.session.projectId ? "project-" : "";
var nsdInfo = new Promise(function(resolve, reject) {
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/nsd-catalog/nsd?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/nsd-catalog/nsd?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
var isString = typeof(response.body) == "string";
if (isString && response.body == '') return resolve('empty');
data = isString ? JSON.parse(response.body) : response.body;
- var nsdData = data.collection["nsd:nsd"];
+ var nsdData = data.collection[projectPrefix + "nsd:nsd"];
if (nsdData.constructor.name == "Object") {
nsdData = [nsdData];
}
})
var config = new Promise(function(resolve, reject) {
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-config/nsr' + (id ? '/' + id : '') + '?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-config/nsr' + (id ? '/' + id : '') + '?deep'),
method: 'GET',
headers: _.extend({}, id ? constants.HTTP_HEADERS.accept.data : constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
});
var opData = new Promise(function(resolve, reject) {
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-opdata/nsr' + (id ? '/' + id : '') + '?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-opdata/nsr' + (id ? '/' + id : '') + '?deep'),
method: 'GET',
headers: _.extend({}, id ? constants.HTTP_HEADERS.accept.data : constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
return new Promise(function(resolve, reject) {
var requestHeaders = {};
_.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config'),
method: 'POST',
headers: requestHeaders,
forever: constants.FOREVER_ON,
return new Promise(function(resolve, reject) {
var requestHeaders = {};
_.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + id,
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + id),
method: 'DELETE',
headers: requestHeaders,
forever: constants.FOREVER_ON,
}
var requestHeaders = {};
_.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + id + '/admin-status/',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + id + '/admin-status/'),
method: 'PUT',
headers: requestHeaders,
json: {
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data,
{
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + id + '/scaling-group/' + scaling_group_id + '/instance',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + id + '/scaling-group/' + scaling_group_id + '/instance'),
method: 'POST',
headers: requestHeaders,
json: jsonData,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data,
{
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + id + '/scaling-group/' + scaling_group_id + '/instance/' + scaling_instance_id,
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + id + '/scaling-group/' + scaling_group_id + '/instance/' + scaling_instance_id),
method: 'DELETE',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
vld_id ? constants.HTTP_HEADERS.accept.data : constants.HTTP_HEADERS.accept.collection,
{
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + nsr_id + '/nsd/vld' + (vld_id ? '/' + vld_id : '') +'?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + nsr_id + '/nsd/vld' + (vld_id ? '/' + vld_id : '') +'?deep'),
method: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
return new Promise(function(resolve, reject) {
var requestHeaders = {};
_.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- uri: utils.confdPort(api_server) + '/api/config/ns-instance-config/nsr/' + nsr_id + '/nsd/vld' + (vld_id ? '/' + vld_id : ''),
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/config/ns-instance-config/nsr/' + nsr_id + '/nsd/vld' + (vld_id ? '/' + vld_id : '')),
method: vld_id ? 'PUT' : 'POST',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
{
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}
);
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + nsr_id + '/nsd/vld/' + vld_id,
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/ns-instance-config/nsr/' + nsr_id + '/nsd/vld/' + vld_id),
method: 'DELETE',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var uri = utils.confdPort(api_server);
uri += APIVersion + '/api/operational/vnfr-catalog/vnfr' + (id ? '/' + id : '') + '?deep';
var headers = _.extend({}, id ? constants.HTTP_HEADERS.accept.data : constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
return new Promise(function(resolve, reject) {
request({
- url: uri,
+ url: utils.projectContextUrl(req, uri),
method: 'GET',
headers: headers,
forever: constants.FOREVER_ON,
}, function(error, response, body) {
if (utils.validateResponse('VNFR.get', error, response, body, resolve, reject)) {
var data = JSON.parse(response.body);
- var returnData = id ? [data["vnfr:vnfr"]] : data.collection["vnfr:vnfr"];
+ var returnData = id ? (data["vnfr:vnfr"] ? [data["vnfr:vnfr"]] : []) : data.collection["vnfr:vnfr"];
returnData.forEach(function(vnfr) {
- vnfr['nfvi-metrics'] = buildNfviGraphs(vnfr.vdur);
- vnfr['epa-params'] = epa_aggregator(vnfr.vdur);
+ vnfr['nfvi-metrics'] = vnfr.vdur ? buildNfviGraphs(vnfr.vdur) : [];
+ vnfr['epa-params'] = vnfr.vdur ? epa_aggregator(vnfr.vdur) : [];
vnfr['service-primitives-present'] = (vnfr['vnf-configuration'] && vnfr['vnf-configuration']['service-primitive'] && vnfr['vnf-configuration']['service-primitive'].length > 0) ? true : false;
vnfr['vdur'] && vnfr['vdur'].map(function(vdur, vdurIndex) {
// This console-url is what front-end will hit to generate a real console-url
delete reqClone.params.id;
uri += APIVersion + '/api/operational/ns-instance-opdata/nsr/' + id + '?deep';
var headers = _.extend({}, id ? constants.HTTP_HEADERS.accept.data : constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
return new Promise(function(resolve, reject) {
if (VNFR.cachedNSR[id]) {
});
} else {
request({
- url: uri,
+ url: utils.projectContextUrl(req, uri),
method: 'GET',
headers: headers,
forever: constants.FOREVER_ON,
var uri = utils.confdPort(api_server);
uri += APIVersion + '/api/operational/vlr-catalog/vlr' + (id ? '/' + id : '') + '?deep';
var headers = _.extend({}, id ? constants.HTTP_HEADERS.accept.data : constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
return new Promise(function(resolve, reject) {
request({
- url: uri,
+ url: utils.projectContextUrl(req, uri),
method: 'GET',
headers: headers,
forever: constants.FOREVER_ON,
var url = req.path;
return new Promise(function(resolve, reject) {
request({
- url: uri + url + '?deep',
+ url: utils.projectContextUrl(req, uri + url + '?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
return new Promise(function(resolve, reject) {
var nsrPromise = new Promise(function(success, failure) {
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-opdata/nsr/' + nsr_id + '?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-opdata/nsr/' + nsr_id + '?deep'),
method: 'GET',
headers: _.extend({},
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
vnfrPromises.push(
new Promise(function(success, failure) {
rp({
- uri: utils.confdPort(api_server) + APIVersion + '/api/operational/vnfr-catalog/vnfr/' + vnfrId + '?deep',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/vnfr-catalog/vnfr/' + vnfrId + '?deep'),
method: 'GET',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
var uri = utils.confdPort(api_server);
uri += APIVersion + '/api/operational/network?deep';
var headers = _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
return new Promise(function(resolve, reject) {
request({
- url: uri,
+ url: utils.projectContextUrl(req, uri),
method: 'GET',
headers: headers,
forever: constants.FOREVER_ON,
var uri = utils.confdPort(api_server);
uri += APIVersion + '/api/operational/vnfr-catalog/vnfr/' + vnfrID + '/vdur/' + vdurID + '?deep';
var headers = _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
return new Promise(function(resolve, reject) {
request({
- url: uri,
+ url: utils.projectContextUrl(req, uri),
method: 'GET',
headers: headers,
forever: constants.FOREVER_ON,
var uri = utils.confdPort(api_server);
uri += APIVersion + '/api/operational/vnfr-console/vnfr/' + vnfrID + '/vdur/' + vdurID + '/console-url' + '?deep';
var headers = _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
return new Promise(function(resolve, reject) {
request({
- url: uri,
+ url: utils.projectContextUrl(req, uri),
method: 'GET',
headers: headers,
forever: constants.FOREVER_ON,
var uri = utils.confdPort(api_server);
uri += APIVersion + '/api/operational/cloud/account?deep';
var headers = _.extend({}, constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
return new Promise(function(resolve, reject) {
request({
- url: uri,
+ url: utils.projectContextUrl(req, uri),
method: 'GET',
headers: headers,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.collection, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/operational/config-agent/account',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/config-agent/account'),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/operational/config-agent/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/config-agent/account/' + id),
type: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/config/config-agent',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/config-agent'),
method: 'POST',
headers: requestHeaders,
forever: constants.FOREVER_ON,
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/config/config-agent/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/config-agent/account/' + id),
method: 'PUT',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/config/config-agent/account/' + id,
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/config-agent/account/' + id),
method: 'DELETE',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/operational/datacenters?deep',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/datacenters?deep'),
method: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
var requestHeaders = {};
_.extend(requestHeaders,
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
request({
- url: utils.confdPort(api_server) + APIVersion + '/api/config/key-pair?deep',
+ url: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/key-pair?deep'),
method: 'GET',
headers: requestHeaders,
forever: constants.FOREVER_ON,
console.log('Deleting ssk-key', id);
return new Promise(function(resolve, reject) {
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/key-pair/' + id,
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/key-pair/' + id),
method: 'DELETE',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: constants.FOREVER_ON,
rejectUnauthorized: false,
var data = req.body;
return new Promise(function(resolve, reject) {
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/key-pair/',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/key-pair/'),
method: 'POST',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
json: data,
forever: constants.FOREVER_ON,
var data = req.body;
return new Promise(function(resolve, reject) {
request({
- uri: utils.confdPort(api_server) + APIVersion + '/api/config/key-pair/',
+ uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/key-pair/'),
method: 'PUT',
headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
json: data,
forever: constants.FOREVER_ON,
"dashboard": "./launchpad.jsx",
"order": 1,
"priority":1,
+ "allow": ["rw-rbac-platform:super-admin", "rw-project-mano:lcm-oper", "rw-project-mano:lcm-admin"],
"routes": [
{
"label": "Dashboard",
"normalizr": "^2.1.0",
"open-iconic": "^1.1.1",
"prismjs": "^1.4.1",
- "react": "^0.14.8",
"react-awesome-modal": "^0.3.3",
"react-breadcrumbs": "^1.3.9",
"react-crouton": "^0.2.7",
- "react-dom": "^0.14.6",
"react-router": "^2.0.1",
"react-slick": "^0.11.1",
"react-tabs": "^0.8.0",
"react-treeview": "^0.4.2",
+ "react": "^0.14.8",
+ "react-dom": "^0.14.6",
"request-promise": "^3.0.0",
"underscore": "^1.8.3"
},
import CatalogDescriptorRaw from './catalogDescriptorRaw.jsx'
import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
import {Panel, PanelWrapper} from 'widgets/panel/panel';
-import Button from 'widgets/button/rw.button.js'
+import Button from 'widgets/button/rw.button.js';
+import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+import ROLES from 'utils/roleConstants.js';
import 'style/layout.scss';
import './instantiateDashboard.scss';
+const PROJECT_ROLES = ROLES.PROJECT;
+const PLATFORM = ROLES.PLATFORM;
+
class InstantiateDashboard extends React.Component {
constructor(props) {
super(props);
let html;
let selectedNSDid = self.state.selectedNSDid;
let isPreviewing = self.state.isPreviewing;
+ const hasAccess = isRBACValid(this.context.userProfile, [PROJECT_ROLES.LCM_ADMIN]);
let descriptorPreview = (
<Panel title={(self.state.selectedNSD['short-name'] || self.state.selectedNSD.name ) + ' Descriptor Preview'} className="CatalogDescriptorPreview">
<span className="oi CatalogDescriptorPreview-button" data-glyph={"circle-x"} onClick={self.Store.deselectDescriptor}></span>
<Button label="Cancel" onClick={this.handleCancel}/>
{this.isSelectPage() ?
- <Button label="Next" isLoading={this.state.isSaving} onClick={this.state.selectedNSD && self.openDescriptor} className="dark" type="submit"/>
+ <Button label="Next" isLoading={this.state.isSaving} onClick={this.state.selectedNSD && self.openDescriptor} className="dark" type="submit"/>
: <div>
<Button label="Back" onClick={this.handleBack}/>
- <Button label="Launch" isLoading={this.state.isSaving} onClick={self.handleSave.bind(self, true)} className="dark" type="submit"/>
+ { hasAccess ? <Button label="Launch" isLoading={this.state.isSaving} onClick={self.handleSave.bind(self, true)} className="dark" type="submit"
+ /> : null}
</div>
}
</div>
}
}
InstantiateDashboard.contextTypes = {
- router: React.PropTypes.object
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
};
export default SkyquakeComponent(InstantiateDashboard);
+++ /dev/null
-
-/*
- *
- * Copyright 2016 RIFT.IO Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-require('../components/form-controls.js');
-require('./launchpad-launch-fleet.html');
-var createStore = require('./createStore.js');
-var createActions = require('./createActions.js');
-
-
-angular.module('launchpad')
- .controller('launchpadCreateCtrl', function($timeout, $stateParams, $state) {
- var self = this;
- self.createStore =
- // var createChannel = $rw.radio.channel('createFleet');
- var apiServer = self.isOnline = require('utils/rw.js').getSearchParams(window.location).api_server;
- // var federationChannel = $rw.radio.channel('federationChannel');
- self.fleet = {
- template_id: null,
- pool_id: null,
- description: '',
- epa_attributes: {},
- status: "active",
- name: 'NEW FLEET'
- };
- self.slaParams = [];
- self.federation = $stateParams.id;
- createStore.getNetworkServices();
- createStore.getSlaParams();
- createStore.getPools();
- createStore.listen(function(state) {
- $timeout(function() {
- self.networkServices = state.networkServices;
- self.slaParams = state.slaParams;
- self.fleet.pool = state.pools[0];
- self.pools = state.pools;
- angular.forEach(self.slaParams, function(v) {
- if (!v.hasOwnProperty('value')) {
- v.value = v.options.second;
- };
- return v;
- });
- })
- })
- // federationChannel.request("federation:services").then(function(data) {
- // $timeout(function() {
- // // self.fleet.service = 'cag';
- // self.networkServices = data;
- // createChannel.request('vnfParams', 'cag').then(function(data) {
- // $timeout(function() {
- // self.vnfParams = data;
- // });
- // });
- // });
- // });
- // federationChannel.request('federation:pools', apiServer).then(function(data) {
- // $timeout(function() {
- // console.log('pools:', data)
- // self.fleet.pool = data[0];
- // self.pools = data;
- // })
- // });
-
- // federationChannel.request('federation:sla-params').then(function(data) {
- // $timeout(function() {
- // self.slaParams = data;
- // angular.forEach(self.slaParams, function(v) {
- // if (!v.hasOwnProperty('value')) {
- // v.value = v.options.second;
- // };
- // return v;
- // });
- // }
- // );
- // });
-
- // federationChannel.on("launchpadCreate", function() {
- // $state.go('launchpad', null, {reload: false});
-
- // });
-
- self.generateServiceImage = function(service) {
- return ('assets/img/svg/' + service.src + (self.isSelectedService(service.id) ? '-active' : '-inactive') + '.svg');
- };
- self.generatePoolImage = function(pool) {
- return ('assets/img/svg/' + self.refsDB.resources.openstackCloud.pools[pool.ref].src + (self.isSelectedPool(pool) ? '-active' : '-inactive') + '.svg');
- };
- self.isSelectedPool = function(id) {
- return id == self.fleet.pool_id;
- };
- self.isSelectedService = function(id) {
- return id == self.fleet.template_id;
- };
- self.launch = function(launch) {
- if (self.fleet.name == "") {
- createActions.validateError('Plase Name the Service')
- }
- createActions.validateReset();
- self.slaParams.forEach(function(v) {
- if (v.value.indexOf("RRC") > -1) {
- v.value = "RRC";
- }
- self.fleet.epa_attributes[v.ref] = v.value;
- });
- delete self.fleet.pool;
- self.fleet.status = launch ? 'active' : 'inactive';
- createStore.createEnvironment(self.fleet)
- };
- self.selectPool = function(id) {
- self.fleet.pool_id = id;
- // createChannel.command("pool:select", id);
- };
- self.selectService = function(id) {
-
- self.fleet.template_id = id;
- // createChannel.command("service:select", id);
- };
- });
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
import Crouton from 'react-crouton'
import AppHeader from 'widgets/header/header.jsx';
import './launchpad.scss';
+
+import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+import ROLES from 'utils/roleConstants.js';
+
+const PROJECT_ROLES = ROLES.PROJECT;
+
let ReactCSSTransitionGroup = require('react-addons-css-transition-group');
var LaunchpadFleetActions = require('./launchpadFleetActions.js');
var LaunchpadFleetStore = require('./launchpadFleetStore.js');
render () {
var self = this;
+ const hasAccess = isRBACValid(this.context.userProfile, [PROJECT_ROLES.LCM_ADMIN]);
let mgmtDomainName = window.location.hash.split('/')[2];
let navItems = [];
if(!mgmtDomainName) {
isVisible={self.state.isNsListPanelVisible}
/>
<NsCardPanel nsrs={self.state.nsrs}
- openedNsrIDs={self.state.openedNsrIDs} />
+ openedNsrIDs={self.state.openedNsrIDs}
+ hasAccess={hasAccess} />
</div>
</div>
);
}
}
LaunchpadApp.contextTypes = {
- router: React.PropTypes.object
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
};
LaunchpadApp.defaultProps = {
// name: 'Loading...',
+++ /dev/null
-
-/*
- *
- * Copyright 2016 RIFT.IO Inc
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-require('./launchpad-fleet-card-params.html');
-var React = require('react');
-var LaunchpadCard = require('./launchpadCard.jsx');
-// var LaunchpadCard = require('../../components/dashboard_card/dashboard_card.jsx');
-angular.module('launchpad')
- .directive('fleetCard', function($state, $stateParams) {
- return {
- restrict: 'AE',
- replace: true,
- template: '<div></div>',
- scope: {
- fleet: '=data',
- $index: '=',
- metric: '=?',
- slaParam: '=?',
- nfviMetric: '=?'
- },
-
- bindToController: true,
- controllerAs: 'card',
- link: function(scope, element, attributes) {
-
- },
- controller: function($timeout, $interval, $scope, $rootScope, $element) {
- var self = this;
-
- console.log(self.fleet)
- $scope.$watch(function() {
- return self.fleet}, reactRender)
- function reactRender() {
- console.log('rendering', self.fleet)
- React.render(
- React.createElement(LaunchpadCard, {className:'launchpadCard'}
- ),
- $element[0]
- );
- }
- //FOR WAG ONLY
- // self.isOn = false;
-
- // //END WAG ONLY
- // //Remove for testing only
- // $scope.$watch(function() {
- // return self.fleet;
- // }, function() {});
-
- // // var fleetChannel = $rw.radio.channel('fleetChannel');
- // var FleetStore = require('../launchpadFleetStore.js');
- // self.valueFormat = {
- // "int": 1,
- // "dec": 0
- // };
- // self.federationID = $stateParams.id;
- // //if this is true, set gauges to start
- // if (require('utils/rw.js').getSearchParams(window.location).api_server) {
- // self.fleet.started = true;
- // }
- // self.apiServer = require('utils/rw.js').getSearchParams(window.location).api_server;
- // self.isNoisy = false;
- // var rateChanged = function(rate) {
- // self.rate = rate;
- // fleetChannel.command('fleet:change:rate', rate)
- // }
- // var packetSizeChanged = function(packetSize) {
- // self.packetSize = packetSize
- // fleetChannel.command('fleet:change:packetSize', packetSize)
- // };
- // self.openFleet = function(index) {
- // var params = require('utils/rw.js').getSearchParams(window.location);
- // if (params.api_server) {
- // if (params.api_server == "http://10.0.201.25:5000") {
- // var newLoc = window.location.origin + window.location.pathname + '?config=' + params.config + '&api_server=' + 'http://10.0.201.25:5050' + '#/wag';
- // window.open(newLoc);
- // return;
- // }
- // if (self.fleet.api == "10.0.117.22") self.fleet.api = "10.0.117.17";
- // var newLoc = window.location.origin + window.location.pathname + '?config=' + params.config + '&api_server=' + 'http://' + self.fleet.api + ':5050' + '&name=' + self.fleet.name + '&env_id=' + self.fleet.id + '#/dashboard/' + $stateParams.id + '/' + index;;
- // console.log('Opening new window at: %s', newLoc)
- // window.open(newLoc);
- // } else {
- // if (self.fleet.id == 'wag-fleet') {
- // var newLoc = window.location.origin + window.location.pathname + '?config=' + params.config + '#/wag';
- // window.open(newLoc);
- // }
- // window.open('#/dashboard/' + $stateParams.id + '/' + index);
- // }
- // };
- // self.openConsole = function(index) {
- // console.log(self);
- // var params = require('utils/rw.js').getSearchParams(window.location);
- // if (params.api_server) {
- // if (self.fleet.api == "10.0.117.22") self.fleet.api = "10.0.117.17";
- // var newLoc = self.apiServer + '/api/environments/' + self.fleet.id + '/console';
- // window.open(newLoc);
- // } else {
- // window.open('#/dashboard/' + $stateParams.id + '/' + index);
- // }
- // };
-
-
- // self.noisyToggle = function() {
- // var action;
- // if (self.isNoisy) {
- // action = 'stop';
- // self.isNoisy = false;
- // } else {
- // action = 'start';
- // self.isNoisy = true;
- // }
- // $.ajax({
- // url: "http://" + self.fleet.api + ':5050/api/operations/' + action + '-stream',
- // type: "POST",
- // headers: {
- // "Content-Type": "application/vnd.yang.operation+json"
- // },
- // dataType: "json",
- // data: JSON.stringify({
- // "input": {
- // "now": ""
- // }
- // })
- // });
- // };
-
- // self.toggleStatus = function() {
- // var state;
- // var status = self.fleet.status;
- // console.log(self.fleet)
- // if (status == "starting" || status == "stopping") {
- // return;
- // }
- // if (status == "active") {
- // state = "inactive";
- // } else {
- // state = "active";
- // }
- // self.fleet.status = state;
- // FleetStore.setFleetState(self.fleet.id, state);
- // };
- // //CAT + NOISY NEIGHBOR ONLY
-
- // self.catStarted = false;
- // self.catToggle = function() {
- // var action;
- // if (self.catStarted) {
- // action = 'stop';
- // self.catStarted = false;
- // } else {
- // action = 'start';
- // self.catStarted = true;
- // }
- // $.ajax({
- // url: "http://" + self.fleet.api + ':5050/api/operations/' + action + '-cat',
- // type: "POST",
- // headers: {
- // "Content-Type": "application/vnd.yang.operation+json"
- // },
- // dataType: "json",
- // data: JSON.stringify({
- // "input": {
- // "now": ""
- // }
- // })
- // });
- // };
-
- // self.deleteFleet = function() {
- // if (confirm("Do you really want to delete this fleet?")) {
- // // if (confirm("Seriously, you REALLY want to delete this?")) {
- // // fleetChannel.request('fleet:delete', self.fleet);
- // FleetStore.deleteFleet(self.fleet.id)
- // // }
- // }
- // };
-
-
- // /**
- // * WAG Code Start
- // **/
- // // var wagChannel = $rw.radio.channel('wag');
-
- // //If Wag page Offline
- // if (!self.apiServer && self.fleet.id == 'wag-fleet') {
- // self.offline = setInterval(function() {
- // if (self.fleet.started) {
- // self.fleet.wagpage.clientsim['traffic-gen']['rx-pps'] = 100 * (Math.random() - .5) + 200;
- // self.fleet.wagpage.clientsim['traffic-gen']['tx-pps'] = 100 * (Math.random() - .5) + 200;
- // }
- // }, 2000);
- // }
-
- // // If Wag page Online
- // if (self.fleet.template_name == 'Wireless Access Gateway') {
- // wagChannel.command('wag-poll');
- // wagChannel.on('wag-update', function(data) {
- // $timeout(function() {
- // self.fleet.wagpage = {};
- // self.fleet.wagpage.clientsim = data.clientsim
- // // self.data.clientsim['traffic-sink']['rx-pps'] / 1000000;
- // self.isOn = data.clientsim['traffic-gen-status'].running;
- // });
- // });
- // }
-
- // $rootScope.$on('$stateChangeStart', function() {
- // wagChannel.command('wag-poll:kill');
- // });
-
- // /**
- // * WAG Code End
- // **/
-
-
- }
- };
- })
-
-.directive('launchpadFleetCardParams', function() {
- return {
- restrict: 'AE',
- replace: true,
- templateUrl: '/modules/launchpad/launchpad_card/launchpad-fleet-card-params.html',
- controllerAs: 'params',
- scope: {
- $index: "=",
- cardData: '=',
- slaParam: '=?',
- nfviMetric: '=?'
- },
- bindToController: true,
- controller: function($scope, $stateParams, $timeout, $interval, $rootScope) {
- //remove watch
- $scope.$watch(function() {
- return self.cardData;
- }, function() {})
- var self = this;
- var apiServer = require('utils/rw.js').getSearchParams(window.location).api_server;
- self.apiServer = apiServer;
- // self.refs = refsDB;
-
-
- // var LaunchpadFleetActions = require('../launchpadFleetActions.js');
- // var LaunchpadFleetStore = require('../launchpadFleetStore.js');
- //var LaunchpadFleetActions = require('./launchpadFleetActions.js');
-
- self.rate = 40;
- self.packetSize = 256;
- self.refParam = $rw.refParams;
- var currentNFVIRef;
-
- this.visible = 'default';
- if (self.cardData.id == "wag-fleet") {
- self.cardData.started = self.cardData.wagpage.clientsim['traffic-gen-status'].running;
- }
-
-
- self.selectedNFVI = 0;
- self.selectedSLAParam = {};
- self.refPools = $rw.refPools;
-
- // Event Listeners
- // View Actions
- self.load = function(panel) {
- self.visible = panel;
- };
- self.filterSLA = function(ref) {
- // fleetChannel.command('filter:SLAParams', ref);
- FleetActions.filterSLAParams(ref);
- };
- self.filterNFVI = function(ref) {
- FleetActions.filterNfviMetrics(ref)
- // fleetChannel.command('filter:NFVIMetrics', ref);
- };
- self.serviceToggle = function(fleet, control) {
- if (apiServer) {
- var vnfrChannel = $rw.radio.channel('vnfr');
- switch (control.ref) {
- case "trafgen":
- var action = (control.started) ? 'stop' : 'start';
- vnfrChannel.command("vnf:command", action, control.data.api, "http://" + fleet.api + ':5050');
- break;
- case "iot_army":
- var action = (control.started) ? 'stop' : 'start';
- vnfrChannel.command("vnf:command", action, control.data.api, "http://" + fleet.api + ':5050');
- break;
- }
- } else {
- fleetChannel.command('fleet:start', $stateParams.id, self.$index);
- if ($stateParams.id == 'wag-federation') {
- if (!self.cardData.wagpage.clientsim['traffic-gen-status']) {
- self.cardData.wagpage.clientsim['traffic-gen-status'] = {};
- }
- self.cardData.wagpage.clientsim['traffic-gen-status'].running = !self.cardData.wagpage.clientsim['traffic-gen-status'].running;
- }
- }
-
- };
- // Init Params
-
-
- //WAG ONLY
- if (self.apiServer == "http://10.0.201.25:5000") {
- self.isWag = true;
- }
- self.toggleOn = function(e) {
- // self.setPacket(e, self.packetSize);
- // self.setRate(e, self.rate);
- // self.setSubscribers(e, self.subscribers);
- // self.setAP(e, self.ap);
- var wagServer = ""
- if (self.apiServer) {
- if (self.isOn) {
- $.ajax({
- type: "POST",
- url: "http://10.0.201.25:5050/api/running/stop-device-group/",
- success: (function() {
- console.log('stahp post sent')
- })
- });
- $.ajax({
- type: "POST",
- url: "http://10.0.201.25:5050/api/running/stop-sink-server/",
- success: (function() {
- console.log('stahp post sent')
- })
- });
- } else {
- $.ajax({
- type: "POST",
- url: "http://10.0.201.25:5050/api/running/start-sink-server/",
- success: (function() {
- console.log('start post sent')
- })
- });
- $.ajax({
- type: "POST",
- url: "http://10.0.201.25:5050/api/running/start-device-group/",
- success: (function() {
- console.log('start post sent')
- })
- });
- }
- }
- self.isOn = !self.isOn;
- }
-
- //END WAG ONLY
-
- },
- link: function(s, e, a) {}
- }
-});
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
<img src={circleXImage} title="Close card" />
</a>
);
-
+ if (this.props.hasAccess) {
+ closeButton = null;
+ }
html = (
<DashboardCard className={'launchpadCard'} closeCard={closeButton}>
<LaunchpadHeader nsr={this.props.nsr} name={this.props.name} isActive={this.props.isActive} id={this.props.id}/>
(<li key="nsr"><h3>NSR: {this.props.nsr['cloud-account']}</h3></li>)
)
}
- this.props.nsr['vnfrs'].map(function(v,i) {
+ this.props.nsr && this.props.nsr['vnfrs'] && this.props.nsr['vnfrs'].map(function(v,i) {
if(v.hasOwnProperty('cloud-account')) {
status.push(
(<li key={i}><h3>VNFR {v['short-name']}: {v['cloud-account']}</h3></li>)
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
}
constructConfigPrimitiveTabs = (tabList, tabPanels) => {
+ const hasAccess = this.props.hasAccess;
let mandatoryFieldValue = 'true';
this.state.vnfrs && this.state.vnfrs.map((vnfr, vnfrIndex) => {
if (vnfr['vnf-configuration'] && vnfr['vnf-configuration']['service-primitive'] && vnfr['vnf-configuration']['service-primitive'].length > 0) {
{params}
</ul>
</div>
- <button className="dark" role="button" onClick={this.handleExecuteClick.bind(this, configPrimitiveIndex, vnfrIndex)}>{configPrimitive.name}</button>
+ {hasAccess ? <button className="dark" role="button" onClick={this.handleExecuteClick.bind(this, configPrimitiveIndex, vnfrIndex)}>{configPrimitive.name}</button> : null}
</TabPanel>
)
});
}
render() {
-
let tabList = [];
let tabPanels = [];
let isConfiguring = (this.props.data['config-status'] && this.props.data['config-status'] != 'configured') || false;
data={nsr.data}
nsr={nsr}
isActive={nsr["admin-status"] == "ENABLED"}
- closeButtonAction={this.onCloseCard(nsr.id)}/>
+ closeButtonAction={this.onCloseCard(nsr.id)}
+ hasAccess={this.props.hasAccess}/>
);
}
}
import Prism from 'prismjs';
import 'prismjs/themes/prism.css';
+import {SkyquakeRBAC, isRBACValid} from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+import ROLES from 'utils/roleConstants.js';
+
+const PROJECT_ROLES = ROLES.PROJECT;
export default class RecordCard extends React.Component {
constructor(props) {
let notice = null;
+ let hasAccess = isRBACValid(this.context.userProfile, [PROJECT_ROLES.LCM_ADMIN]);
+
switch(this.props.type) {
case 'vnfr' :
cardData = this.props.data[0];
if (displayConfigPrimitives) {
configPrimitiveComponent = (
<div className="flex vnfrConfigPrimitiveContainer">
- <VnfrConfigPrimitives data={configPrimitivesProps} />
+ <VnfrConfigPrimitives data={configPrimitivesProps} hasAccess={hasAccess} />
{/* <NsrPrimitiveJobList jobs={cardData['config-agent-job']}/> */}
<div style={{display:'flex', flexDirection: 'column', flex: '1 1 40%'}}>
<div className="launchpadCard_title">
isLoading: true,
jobData: []
}
+RecordCard.contextTypes = {
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
+};
/*
- *
+ *
* Copyright 2016 RIFT.IO Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
let nav = <AppHeader nav={navItems} />
if (this.state.showRecordDetails) {
- recordDetails = <RecordDetails isLoading={this.state.detailLoading} data={this.state.rawData} />
+ recordDetails = <RecordDetails isLoading={this.state.detailLoading} data={this.state.rawData} />
}
html = (
<div className="app-body recordView">
function buildGetRequestOptions(req, endpoint) {
var headers = _.extend({},
constants.HTTP_HEADERS.accept.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
var api_server = req.query["api_server"];
var requestOptions = {
var headers = _.extend({},
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
var api_server = req.query["api_server"];
var requestOptions = {
var headers = _.extend({},
constants.HTTP_HEADERS.accept.data,
constants.HTTP_HEADERS.content_type.data, {
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
});
var api_server = req.query["api_server"];
var requestOptions = {
headers: _.extend({},
constants.HTTP_HEADERS.accept.data,
{
- 'Authorization': req.get('Authorization')
+ 'Authorization': req.session && req.session.authorization
}),
forever: foreverOn,
rejectUnauthorized: false
* Class to convert RESTConf data to logging plugin
*/
-
+var LoggingConfigDecoder = {};
+var LoggingConfigEncoder = {};
LoggingConfigDecoder = function(debugMode) {
this.debugMode = debugMode || false
"root": "public",
"name": "Logging",
"dashboard": "./loggingGeneral.jsx",
- "order": 101,
+ "order": 1,
"priority":2,
+ "admin_link": true,
"routes": [
{
"label": "Logging",
--- /dev/null
+# RIFT_IO_STANDARD_CMAKE_COPYRIGHT_HEADER(BEGIN)
+# Author(s): Kiran Kashalkar
+# Creation Date: 08/18/2015
+# RIFT_IO_STANDARD_CMAKE_COPYRIGHT_HEADER(END)
+
+##
+# DEPENDENCY ALERT
+# The submodule dependencies must be specified in the
+# .gitmodules.dep file at the top level (supermodule) directory
+# If this submodule depends other submodules remember to update
+# the .gitmodules.dep
+##
+
+cmake_minimum_required(VERSION 2.8)
+
+##
+# Submodule specific includes will go here,
+# These are specified here, since these variables are accessed
+# from multiple sub directories. If the variable is subdirectory
+# specific it must be declared in the subdirectory.
+##
+
+rift_externalproject_add(
+ project_management
+ DEPENDS skyquake
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
+ CONFIGURE_COMMAND echo
+ BUILD_COMMAND
+ ${CMAKE_CURRENT_BINARY_DIR}/project_management/project_management-build/scripts/build.sh
+ INSTALL_COMMAND
+ ${CMAKE_CURRENT_SOURCE_DIR}/scripts/install.sh
+ ${CMAKE_CURRENT_BINARY_DIR}/project_management/project_management-build
+ ${CMAKE_INSTALL_PREFIX}/usr/share/rw.ui/skyquake
+ ${RIFT_SUBMODULE_INSTALL_PREFIX}/skyquake/${CMAKE_INSTALL_PREFIX}/usr/share/rw.ui/skyquake
+
+ BCACHE_COMMAND echo
+)
+
--- /dev/null
+{
+ "root": "public",
+ "name": "Project Management",
+ "dashboard": "./dashboard/dashboard.jsx",
+ "order": 1,
+ "priority":2,
+ "admin_link": true,
+ "allow": ["rw-rbac-platform:super-admin", "rw-rbac-platform:platform-admin", "rw-rbac-platform:platform-oper", "rw-project:project-admin", "rw-project:project-oper"],
+ "routes": [
+ {
+ "label": "Project Management Dashboard",
+ "route": "project-management",
+ "component": "./dashboard/dashboard.jsx",
+ "type": "internal"
+ }]
+}
--- /dev/null
+{
+ "name": "config",
+ "version": "1.0.0",
+ "description": "",
+ "main": "routes.js",
+ "scripts": {
+ "start": "rm -rf public/ && mkdir public && cd public && mkdir build && cp ../src/index.html ./ && node ../server.js"
+ },
+ "author": "RIFT.io",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "alt": "^0.18.3",
+ "bluebird": "^3.4.1",
+ "express": "^4.13.3",
+ "history": "^1.17.0",
+ "jquery": "^2.2.1",
+ "json-loader": "^0.5.4",
+ "lodash": "^4.10.0",
+ "normalizr": "^2.1.0",
+ "open-iconic": "^1.1.1",
+ "prismjs": "^1.4.1",
+ "react": "^0.14.8",
+ "react-breadcrumbs": "^1.3.9",
+ "react-crouton": "^0.2.7",
+ "react-dom": "^0.14.6",
+ "react-router": "^2.0.1",
+ "react-slick": "^0.11.1",
+ "react-tabs": "^0.5.3",
+ "react-treeview": "^0.4.2",
+ "request-promise": "^3.0.0",
+ "underscore": "^1.8.3"
+ },
+ "devDependencies": {
+ "babel-core": "^6.4.5",
+ "babel-loader": "^6.2.1",
+ "babel-polyfill": "^6.9.1",
+ "babel-preset-es2015": "^6.6.0",
+ "babel-preset-react": "^6.5.0",
+ "babel-preset-stage-0": "^6.3.13",
+ "babel-runtime": "^6.3.19",
+ "cors": "^2.7.1",
+ "css-loader": "^0.23.1",
+ "file-loader": "^0.8.5",
+ "html-webpack-plugin": "^2.9.0",
+ "http-proxy": "^1.12.0",
+ "loaders.css": "^0.1.2",
+ "node-sass": "^3.4.2",
+ "react-addons-css-transition-group": "^0.14.7",
+ "sass-loader": "^3.1.2",
+ "style-loader": "^0.13.0",
+ "webpack": "^1.3.0",
+ "webpack-dev-server": "^1.10.1"
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+var app = require('express').Router();
+var cors = require('cors');
+var utils = require('../../framework/core/api_utils/utils.js')
+ // Begin Accounts API
+
+ utils.passThroughConstructor(app);
+
+module.exports = app;
--- /dev/null
+#!/bin/bash
+
+# STANDARD_RIFT_IO_COPYRIGHT
+
+PLUGIN_NAME=project-management
+# change to the directory of this script
+THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+cd $THIS_DIR
+cd ..
+
+echo 'Building plugin '$PLUGIN_NAME
+echo 'Fetching third-party node_modules for '$PLUGIN_NAME
+npm install
+echo 'Fetching third-party node_modules for '$PLUGIN_NAME'...done'
+echo 'Packaging '$PLUGIN_NAME' using webpack'
+ui_plugin_cmake_build=true ./node_modules/.bin/webpack --progress --config webpack.production.config.js
+echo 'Packaging '$PLUGIN_NAME' using webpack... done'
+echo 'Building plugin '$PLUGIN_NAME'... done'
--- /dev/null
+#!/bin/bash
+
+# STANDARD_RIFT_IO_COPYRIGHT
+
+plugin=project-management
+source_dir=$1
+dest_dir=$2
+bcache_dir=$3
+
+# Create destination and build cache directories
+mkdir -p $dest_dir
+mkdir -p $bcache_dir
+
+# Create necessary directories under dest and cache dirs
+mkdir -p $dest_dir/framework
+mkdir -p $dest_dir/plugins
+mkdir -p $bcache_dir/framework
+mkdir -p $bcache_dir/plugins
+
+# Copy over built plugin's public folder, config.json, routes.js and api folder as per installed_plugins.txt
+mkdir -p $dest_dir/plugins/$plugin
+cp -Lrf $source_dir/public $dest_dir/plugins/$plugin/.
+cp -Lrf $source_dir/config.json $dest_dir/plugins/$plugin/.
+cp -Lrf $source_dir/routes.js $dest_dir/plugins/$plugin/.
+cp -Lrp $source_dir/api $dest_dir/plugins/$plugin/.
+tar -cf $dest_dir/plugins/$plugin/node_modules.tar node_modules package.json -C $source_dir
+#cp -Lrp $source_dir/node_modules $dest_dir/plugins/$plugin/.
+mkdir -p $bcache_dir/plugins/$plugin
+cp -Lrf $source_dir/public $bcache_dir/plugins/$plugin/.
+cp -Lrf $source_dir/config.json $bcache_dir/plugins/$plugin/.
+cp -Lrf $source_dir/routes.js $bcache_dir/plugins/$plugin/.
+cp -Lrp $source_dir/api $bcache_dir/plugins/$plugin/.
+tar -cf $bcache_dir/plugins/$plugin/node_modules.tar $source_dir/node_modules $source_dir/package.json
+#cp -Lrp $source_dir/node_modules $bcache_dir/plugins/$plugin/.
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+var express = require('express');
+var path = require('path');
+var httpProxy = require('http-proxy');
+var bodyParser = require('body-parser');
+var cors = require('cors');
+var session = require('express-session');
+var proxy = httpProxy.createProxyServer();
+var app = express();
+
+var isProduction = process.env.NODE_ENV === 'production';
+var port = isProduction ? 8080 : 8888;
+var publicPath = path.resolve(__dirname, 'public');
+
+if (!isProduction) {
+
+ //Routes for local development
+ var lpRoutes = require('./routes.js');
+
+ app.use(express.static(publicPath));
+ app.use(session({
+ secret: 'ritio rocks',
+ }));
+ app.use(bodyParser.urlencoded({
+ extended: true
+ }));
+ app.use(bodyParser.json());
+ app.use(cors());
+ app.use('/', lpRoutes);
+ var bundle = require('./server/bundle.js');
+ bundle();
+
+ app.all('/build/*', function (req, res) {
+ proxy.web(req, res, {
+ target: 'http://localhost:8080'
+ });
+ });
+
+}
+proxy.on('error', function(e) {
+ console.log('Could not connect to proxy, please try again...');
+});
+
+app.listen(port, function () {
+ console.log('Server running on port ' + port);
+});
+
+app.get('/*')
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import AppHeader from 'widgets/header/header.jsx';
+import ProjectManagementStore from './projectMgmtStore.js';
+import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
+import SkyquakeRBAC from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+import 'style/layout.scss';
+import './projectMgmt.scss';
+import {Panel, PanelWrapper} from 'widgets/panel/panel';
+import {InputCollection, FormSection} from 'widgets/form_controls/formControls.jsx';
+
+import TextInput from 'widgets/form_controls/textInput.jsx';
+import Input from 'widgets/form_controls/input.jsx';
+import Button, {ButtonGroup} from 'widgets/button/sq-button.jsx';
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import 'widgets/form_controls/formControls.scss';
+import imgAdd from '../../node_modules/open-iconic/svg/plus.svg'
+import imgRemove from '../../node_modules/open-iconic/svg/trash.svg'
+
+import ROLES from 'utils/roleConstants.js';
+const PROJECT_ROLES = ROLES.PROJECT;
+const PLATFORM = ROLES.PLATFORM;
+
+class ProjectManagementDashboard extends React.Component {
+ constructor(props) {
+ super(props);
+ this.Store = this.props.flux.stores.hasOwnProperty('ProjectManagementStore') ? this.props.flux.stores.ProjectManagementStore : this.props.flux.createStore(ProjectManagementStore);
+ this.Store.getProjects();
+ this.Store.getUsers();
+ this.state = this.Store.getState();
+ this.actions = this.state.actions;
+ }
+ componentDidUpdate() {
+ let self = this;
+ ReactDOM.findDOMNode(this.projectList).addEventListener('transitionend', this.onTransitionEnd, false);
+ setTimeout(function() {
+ let element = self[`project-ref-${self.state.activeIndex}`]
+ element && !isElementInView(element) && element.scrollIntoView({block: 'end', behavior: 'smooth'});
+ })
+ }
+ componentWillMount() {
+ this.Store.listen(this.updateState);
+ }
+ componentWillUnmount() {
+ this.Store.unlisten(this.updateState);
+ }
+ updateState = (state) => {
+ this.setState(state);
+ }
+ updateInput = (key, e) => {
+ let property = key;
+ this.actions.handleUpdateInput({
+ [property]:e.target.value
+ })
+ }
+ disabledChange = (e) => {
+ this.actions.handleDisabledChange(e.target.checked);
+ }
+ platformChange = (platformRole, e) => {
+ this.actions.handlePlatformRoleUpdate(platformRole, e.currentTarget.checked);
+ }
+ addProjectRole = (e) => {
+ this.actions.handleAddProjectItem();
+ }
+ removeProjectRole = (i, e) => {
+ this.actions.handleRemoveProjectItem(i);
+ }
+ updateProjectRole = (i, e) => {
+ this.actions.handleUpdateProjectRole(i, e)
+ }
+ addProject = () => {
+ this.actions.handleAddProject();
+ }
+ viewProject = (un, index) => {
+ this.actions.viewProject(un, index);
+ }
+ editProject = () => {
+ this.actions.editProject(false);
+ }
+ cancelEditProject = () => {
+ this.actions.editProject(true)
+ }
+ closePanel = () => {
+ this.actions.handleCloseProjectPanel();
+ }
+
+ deleteProject = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ if (confirm('Are you sure you want to delete this project?')) {
+ this.Store.deleteProject({
+ 'name': this.state['name']
+ });
+ }
+ }
+ createProject = (e) => {
+ let self = this;
+ e.preventDefault();
+ e.stopPropagation();
+ let projectName = self.state['name'];
+ let projectUsers = self.state.projectUsers;
+ let cleanUsers = this.cleanUsers(projectUsers, projectName);
+
+
+ this.Store.createProject({
+ 'name': projectName,
+ 'description': self.state.description,
+ 'project-config' : {
+ 'user': cleanUsers
+ }
+ });
+ }
+ updateProject = (e) => {
+ let self = this;
+ e.preventDefault();
+ e.stopPropagation();
+ let projectName = self.state['name'];
+ let projectUsers = self.state.projectUsers;
+ let cleanUsers = this.cleanUsers(projectUsers, projectName);
+
+
+ this.Store.updateProject(_.merge({
+ 'name': projectName,
+ 'description': self.state.description,
+ 'project-config' : {
+ 'user': cleanUsers
+ }
+ }));
+ }
+ cleanUsers(projectUsers, projectName) {
+ let cleanUsers = [];
+ //Remove null values from role
+ projectUsers.map((u) => {
+ let cleanRoles = [];
+ u.role && u.role.map((r,i) => {
+ let role = {};
+ //you may add a user without a role or a keys, but if one is present then the other must be as well.
+ if(!r.role ) {
+ } else {
+ delete r.keys;
+ // r.keys = projectName;
+ cleanRoles.push(r)
+ }
+ });
+ u.role = cleanRoles;
+ cleanUsers.push(u);
+ });
+ return cleanUsers;
+ }
+ evaluateSubmit = (e) => {
+ if (e.keyCode == 13) {
+ if (this.props.isEdit) {
+ this.updateProject(e);
+ } else {
+ this.createProject(e);
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+ updateSelectedUser = (e) => {
+ this.setState({
+ selected
+ })
+ }
+ addUserToProject = (e) => {
+ let selectUserList = this.selectUserList;
+ console.log(ReactDOM.findDOMNode(selectUserList))
+ this.actions.handleAddUser(e);
+ }
+ removeUserFromProject = (userIndex, e) => {
+ this.actions.handleRemoveUserFromProject(userIndex);
+ }
+ updateUserRoleInProject = (userIndex, roleIndex, e) => {
+ this.actions.handleUpdateUserRoleInProject({
+ userIndex,
+ roleIndex,
+ value: JSON.parse(e.target.value)
+ })
+ }
+ toggleUserRoleInProject = (userIndex, roleIndex, e) => {
+ this.actions.handleToggleUserRoleInProject({
+ userIndex,
+ roleIndex,
+ checked: JSON.parse(e.currentTarget.checked)
+ })
+ }
+ removeRoleFromUserInProject = (userIndex, roleIndex, e) => {
+ this.actions.handleRemoveRoleFromUserInProject({
+ userIndex,
+ roleIndex
+ })
+ }
+ addRoleToUserInProject = (userIndex, e) => {
+ this.actions.addRoleToUserInProject(userIndex);
+ }
+ onTransitionEnd = (e) => {
+ this.actions.handleHideColumns(e);
+ console.log('transition end')
+ }
+ disableChange = (e) => {
+ let value = e.target.value;
+ value = value.toUpperCase();
+ if (value=="TRUE") {
+ value = true;
+ } else {
+ value = false;
+ }
+ console.log(value)
+ }
+ render() {
+ let self = this;
+ let html;
+ let props = this.props;
+ let state = this.state;
+ let passwordSectionHTML = null;
+ let formButtonsHTML = (
+ <ButtonGroup className="buttonGroup">
+ <Button label="EDIT" type="submit" onClick={this.editProject} />
+ </ButtonGroup>
+ );
+ let projectUsers = [];
+ self.state.projectUsers.map((u) => {
+ projectUsers.push(u['user-name']);
+ });
+ let availableUsers = state.users && state.users.filter((u) => {
+ return projectUsers.indexOf(u['user-name']) == -1
+ }).map((u) => {
+ return {
+ label: u['user-name'],
+ value: u
+ }
+ });
+
+ if(!this.state.isReadOnly) {
+ formButtonsHTML = (
+ state.isEdit ?
+ (
+ <ButtonGroup className="buttonGroup">
+ <Button label="Update" type="submit" onClick={this.updateProject} />
+ <Button label="Delete" onClick={this.deleteProject} />
+ <Button label="Cancel" onClick={this.cancelEditProject} />
+ </ButtonGroup>
+ )
+ : (
+ <ButtonGroup className="buttonGroup">
+ <Button label="Create" type="submit" onClick={this.createProject} />
+ </ButtonGroup>
+ )
+ )
+ }
+
+ html = (
+ <PanelWrapper className={`row projectManagement ${!this.state.projectOpen ? 'projectList-open' : ''}`} style={{'alignContent': 'center', 'flexDirection': 'row'}} >
+ <PanelWrapper ref={(div) => { this.projectList = div}} className={`column projectList expanded ${this.state.projectOpen ? 'collapsed ' : ' '} ${this.state.hideColumns ? 'hideColumns ' : ' '}`}>
+ <Panel title="Project List" style={{marginBottom: 0}} no-corners>
+ <div className="tableRow tableRow--header">
+ <div className="projectName">
+ Project Name
+ </div>
+ <div>
+ Description
+ </div>
+ </div>
+ {state.projects && state.projects.map((u, k) => {
+ let platformRoles = [];
+ for(let role in u.platformRoles) {
+ platformRoles.push(<div>{`${role}: ${u.platformRoles[role]}`}</div>)
+ }
+ return (
+ <div onClick={self.viewProject.bind(null, u, k)} ref={(el) => this[`project-ref-${k}`] = el} className={`tableRow tableRow--data ${((self.state.activeIndex == k) && self.state.projectOpen) ? 'tableRow--data-active' : ''}`} key={k}>
+ <div
+ className={`projectName projectName-header ${((self.state.activeIndex == k) && self.state.projectOpen) ? 'activeProject' : ''}`}
+ >
+ {u['name']}
+ </div>
+ <div>
+ {u['description']}
+ </div>
+
+
+ </div>
+ )
+ })}
+ </Panel>
+ <SkyquakeRBAC className="rbacButtonGroup">
+ <ButtonGroup className="buttonGroup">
+ <Button label="Add Project" onClick={this.addProject} />
+ </ButtonGroup>
+ </SkyquakeRBAC>
+ </PanelWrapper>
+ <PanelWrapper onKeyUp={this.evaluateSubmit}
+ className={`ProjectAdmin column`}>
+ <Panel
+ title={state.isEdit ? state['name'] : 'Create Project'}
+ style={{marginBottom: 0}}
+ hasCloseButton={this.closePanel}
+ no-corners>
+ <FormSection title="PROJECT INFO">
+ {
+ this.state.isEdit ?
+ null
+ : <Input readonly={state.isReadOnly} label="Name" value={state['name']} onChange={this.updateInput.bind(null, 'name')} />
+ }
+ <Input readonly={state.isReadOnly} type="textarea" label="Description" value={state['description']} onChange={this.updateInput.bind(null, 'description')}></Input>
+ </FormSection>
+ <FormSection title="USER ROLES" className="userTable">
+
+ <table>
+ <thead>
+ <tr>
+ {!state.isReadOnly ? <td></td> : null}
+ <td>User Name</td>
+ {
+ state.roles.map((r,i) => {
+ return <td key={i}>{r}</td>
+ })
+ }
+ </tr>
+ </thead>
+ <tbody>
+ {
+ state.projectUsers.map((u,i)=> {
+ let userRoles = u.role && u.role.map((r) => {
+ return r.role;
+ }) || [];
+ return (
+ <tr key={i}>
+ {!state.isReadOnly ? <td><span
+ className="removeInput"
+ onClick={self.removeUserFromProject.bind(self, i)}
+ >
+ <img src={imgRemove} />
+
+ </span></td> : null}
+ <td>
+ {u['user-name']}
+ </td>
+ {
+ state.roles.map((r,j) => {
+ return <td key={j}><Input readonly={state.isReadOnly} type="checkbox" onChange={self.toggleUserRoleInProject.bind(self, i, j)} checked={(userRoles.indexOf(r) > -1)} /></td>
+ })
+ }
+ </tr>
+ )
+ })
+ }
+ </tbody>
+ </table>
+
+ {
+ !state.isReadOnly ?
+ <div className="tableRow tableRow--header">
+ <div>
+ <div className="addUser">
+ <SelectOption
+ onChange={this.actions.handleSelectedUser}
+ value={state.selectedUser}
+ initial={true}
+ options={availableUsers}
+ ref={(el) => self.selectUserList = el}
+ />
+ <span className="addInput" onClick={this.addUserToProject}><img src={imgAdd} />
+ Add User
+ </span>
+ </div>
+ </div>
+ </div> : null
+ }
+
+ </FormSection>
+
+ </Panel>
+ <SkyquakeRBAC allow={[PROJECT_ROLES.PROJECT_ADMIN]} project={this.state.name} className="rbacButtonGroup">
+ {formButtonsHTML}
+ </SkyquakeRBAC>
+ </PanelWrapper>
+
+
+ </PanelWrapper>
+ );
+ return html;
+ }
+}
+// onClick={this.Store.update.bind(null, Account)}
+ProjectManagementDashboard.contextTypes = {
+ router: React.PropTypes.object
+};
+
+ProjectManagementDashboard.defaultProps = {
+ projectList: [],
+ selectedProject: {}
+}
+
+export default SkyquakeComponent(ProjectManagementDashboard);
+
+
+function isElementInView(el) {
+ var rect = el && el.getBoundingClientRect() || {};
+
+ return (
+ rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
+ );
+}
+
+
+// isReadOnly={state.isReadOnly} disabled={state.disabled} onChange={this.disableChange}
+
+class isDisabled extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+ render() {
+ let props = this.props;
+ return (<div/>)
+ }
+}
+
+
+
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+/* If there's time this really needs to be rewritten. Ideally with smooth animations.*/
+@import "style/_colors.scss";
+
+.projectManagement {
+ max-width: 1200px;
+
+ .skyquakePanel-wrapper {
+ overflow-x: hidden;
+ }
+ .projectList {
+
+ -ms-flex: 0 1 200px;
+ flex: 0 1 200px;
+
+ .activeUser {
+ font-weight:bold;
+ }
+
+ /* transition: all 2s;*/
+ &.expanded {
+ -ms-flex: 1 1 100%;
+ flex: 1 1 100%;
+ /* transition: all 300ms;*/
+ .tableRow>div:not(.projectName) {
+ opacity: 1;
+ /* width:auto;*/
+ /* transition: width 600ms;*/
+ /* transition: opacity 300ms;*/
+ }
+ &.collapsed {
+ -ms-flex: 0 1 200px;
+ flex: 0 1 200px;
+ /* transition: all 2s;*/
+ .tableRow>div:not(.projectName) {
+ /* opacity: 0;*/
+ /* width:0px;*/
+ display:none;
+ overflow:hidden;
+ /* transition: all 600ms;*/
+ }
+ }
+ }
+ &.hideColumns {
+ overflow:hidden;
+ >div {
+ overflow:hidden;
+ }
+ .tableRow>div:not(.projectName) {
+ width: 0px;
+ /* transition: all 600ms;*/
+ }
+ .projectName {
+ &--header {
+ /* display:none;*/
+ }
+ }
+ }
+ .projectName {
+ cursor:pointer;
+ }
+
+
+ }
+
+ .projectAdmin {
+ -ms-flex: 1 1;
+ flex: 1 1;
+ width:auto;
+ opacity:1;
+
+ textarea{
+ height: 100px;
+ }
+ }
+ &.projectList-open {
+ .projectAdmin {
+ -ms-flex: 0 1 0px;
+ flex: 0 1 0px;
+ opacity:0;
+ /* width: 0px;*/
+ display:none;
+ /* transition: opacity 300ms;*/
+ /* transition: width 600ms;*/
+
+ }
+ }
+ .rbacButtonGroup {
+ margin: 0 0.5rem 0.5rem;
+ background: #ddd;
+ padding-bottom: 0.5rem;
+ padding: 0.5rem 0;
+ }
+ .buttonGroup {
+ border-top: #d3d3d3 1px solid;
+ padding-top:0.5rem;
+ }
+ .addUser {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-direction:row;
+ flex-direction:row;
+ label {
+ -ms-flex: 0 1;
+ flex: 0 1;
+ width:150px;
+ select {
+ width:150px;
+ }
+ }
+ }
+ .projectUsers {
+ .userName {
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ padding-top: 0.75rem;
+ }
+ select {
+ margin-bottom:0.5rem;
+ }
+ .addRole {
+ margin:.25rem 0;
+ }
+ .buttonGroup {
+ display:-ms-flexbox;
+ display:flex;
+ }
+
+ }
+ .projectUsers.tableRow--data:hover {
+ background:none;
+ color: black;
+ }
+
+ table {
+ font-size: 0.8rem;
+ thead {
+ border-bottom:1px solid #d3d3d3;
+ td{
+ font-weight:bold;
+ }
+ }
+ td{
+ padding:0.25rem 0.5rem;
+ vertical-align: middle;
+ .checkbox {
+ -ms-flex-pack:center;
+ justify-content:center;
+ }
+ }
+ }
+ .userTable {
+ .FormSection-body {
+ max-width: 952px;
+ overflow-x: auto;
+ }
+ }
+}
+
+
+
+.FormSection {
+ &-title {
+ color: #000;
+ background: lightgray;
+ padding: 0.5rem;
+ border-top: 1px solid #f1f1f1;
+ border-bottom: 1px solid #f1f1f1;
+ }
+ &-body {
+ padding: 0.5rem 0.75rem;
+ }
+ label {
+ -ms-flex: 1 0;
+ flex: 1 0;
+ }
+ /* label {*/
+ /* display: -ms-flexbox;*/
+ /* display: flex;*/
+ /* -ms-flex-direction: column;*/
+ /* flex-direction: column;*/
+ /* width: 100%;*/
+ /* margin: 0.5rem 0;*/
+ /* -ms-flex-align: start;*/
+ /* align-items: flex-start;*/
+ /* -ms-flex-pack: start;*/
+ /* justify-content: flex-start;*/
+ /* }*/
+ select {
+ font-size: 1rem;
+ min-width: 75%;
+ height: 35px;
+ }
+}
+
+
+.InputCollection {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -ms-flex-align: center;
+ align-items: center;
+ button {
+ padding: 0.25rem;
+ height: 1.5rem;
+ font-size: 0.75rem;
+ }
+ select {
+ min-width: 100%;
+ }
+ margin-bottom:0.5rem;
+ &-wrapper {
+
+ }
+}
+.tableRow {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ padding: 0.25rem;
+ margin: .125rem 0;
+ >div {
+ padding: 0.25rem;
+ -ms-flex: 1 1 33%;
+ flex: 1 1 33%;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -ms-flex-pack: center;
+ justify-content: center;
+ }
+ &--header {
+ font-weight:bold;
+ }
+ &--data {
+ &:hover:not(&-active) {
+ background:$neutral-dark-1;
+ }
+ &:hover, .activeUser, &-active{
+ cursor:pointer;
+ color:white;
+ }
+ .activeUser, &-active{
+ background: #00acee;
+ }
+ }
+}
+
+.addInput, .removeInput {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-align:center;
+ align-items:center;
+ margin-left: 1rem;
+
+ font-size:0.75rem;
+ text-transform:uppercase;
+ font-weight:bold;
+
+ cursor:pointer;
+ img {
+ height:0.75rem;
+ margin-right:0.5rem;
+ width:auto;
+ }
+ span {
+ color: #5b5b5b;
+ text-transform: uppercase;
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+module.exports = function(Alt) {
+ return Alt.generateActions(
+ 'handleUpdateInput',
+ 'handleAddProjectItem',
+ 'handleRemoveProjectItem',
+ 'handleUpdateProjectRole',
+ 'viewProject',
+ 'editProject',
+ 'handleCloseProjectPanel',
+ 'handleHideColumns',
+ 'handleSelectedUser',
+ 'handleSelectedRole',
+ 'handleAddUser',
+ 'handleRemoveUserFromProject',
+ 'getProjectsSuccess',
+ 'getUsersSuccess',
+ 'getProjectsNotification',
+ 'handleDisabledChange',
+ 'handlePlatformRoleUpdate',
+ 'handleAddProject',
+ 'handleCreateProject',
+ 'handleUpdateProject',
+ 'handleUpdateSelectedUser',
+ 'handleUpdateUserRoleInProject',
+ 'handleToggleUserRoleInProject',
+ 'addRoleToUserInProject',
+ 'handleRemoveRoleFromUserInProject',
+ 'updateProjectSuccess',
+ 'createProjectSuccess',
+ 'deleteProjectSuccess'
+ );
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import $ from 'jquery';
+var Utils = require('utils/utils.js');
+let API_SERVER = require('utils/rw.js').getSearchParams(window.location).api_server;
+let HOST = API_SERVER;
+let NODE_PORT = require('utils/rw.js').getSearchParams(window.location).api_port || ((window.location.protocol == 'https:') ? 8443 : 8000);
+let DEV_MODE = require('utils/rw.js').getSearchParams(window.location).dev_mode || false;
+
+if (DEV_MODE) {
+ HOST = window.location.protocol + '//' + window.location.hostname;
+}
+
+
+
+module.exports = function(Alt) {
+ return {
+
+ getUsers: {
+ remote: function() {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'GET',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data.user);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error retrieving the resource orchestrator information.'
+ }),
+ success: Alt.actions.global.getUsersSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ getProjects: {
+ remote: function() {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/project?api_server=${API_SERVER}`,
+ type: 'GET',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data.project);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error retrieving the resource orchestrator information.'
+ }),
+ success: Alt.actions.global.getProjectsSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ updateProject: {
+ remote: function(state, project) {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/project?api_server=${API_SERVER}`,
+ type: 'PUT',
+ data: project,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the project.'
+ }),
+ success: Alt.actions.global.updateProjectSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ deleteProject: {
+ remote: function(state, project) {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/project/${project['name']}?api_server=${API_SERVER}`,
+ type: 'DELETE',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error deleting the user.'
+ }),
+ success: Alt.actions.global.deleteProjectSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ createProject: {
+ remote: function(state, project) {
+
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/project?api_server=${API_SERVER}`,
+ type: 'POST',
+ data: project,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the account.'
+ }),
+ success: Alt.actions.global.createProjectSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ }
+ }
+}
+
+function interceptResponse (responses) {
+ return function(data, action, args) {
+ if(responses.hasOwnProperty(data)) {
+ return {
+ type: data,
+ msg: responses[data]
+ }
+ } else {
+ return data;
+ }
+ }
+}
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import ProjectManagementActions from './projectMgmtActions.js';
+import ProjectManagementSource from './projectMgmtSource.js';
+import ROLES from 'utils/roleConstants.js';
+import _ from 'lodash';
+export default class ProjectManagementStore {
+ constructor() {
+ this.actions = ProjectManagementActions(this.alt);
+ this.bindActions(this.actions);
+ this.registerAsync(ProjectManagementSource);
+ this.projects = [];
+ this['name'] = '';
+ this['description'] = 'Some Description';
+ this.projectUsers = [];
+ this.selectedUser = null;
+ this.selectedRole = null;
+ this.roles = Object.keys(ROLES.PROJECT).map((p) => {
+ return ROLES.PROJECT[p];
+ })
+ // this.roles = ['rw-project:project-admin', 'rw-project:project-oper', 'rw-project:project-create'];
+ this.users = [];
+ this.activeIndex = null;
+ this.isReadOnly = true;
+ this.projectOpen = false;
+ this.hideColumns = false;
+ this.isEdit = false;
+ // this.exportPublicMethods({})
+ }
+ /**
+ * [handleFieldUpdate description]
+ * @param {Object} data {
+ * [store_property] : [value]
+ * }
+ * @return {[type]} [description]
+ */
+ handleUpdateInput(data) {
+ this.setState(data);
+ }
+ handleAddProjectItem(item) {
+ let projectRoles = this.projectRoles;
+ projectRoles.push('');
+ this.setState({projectRoles});
+ }
+ handleRemoveProjectItem(i) {
+ let projectRoles = this.projectRoles;
+ projectRoles.splice(i, 1);
+ console.log('Removing', projectRoles)
+ this.setState({projectRoles});
+ }
+ handleUpdateProjectRole(data) {
+ let i = data[0];
+ let e = data[1];
+ let projectRoles = this.projectRoles
+ projectRoles[i] = JSON.parse(e.currentTarget.value);
+ this.setState({
+ projectRoles
+ });
+ }
+ viewProject(data) {
+ let project = data[0];
+ let projectIndex = data[1];
+
+ let ProjectData = {
+ 'name': project['name'],
+ 'description': project['description'],
+ 'projectUsers': project['project-config'] && project['project-config']['user'] || []
+ }
+ let state = _.merge({
+ activeIndex: projectIndex,
+ projectOpen: true,
+ isEdit: true,
+ isReadOnly: true
+ }, ProjectData);
+ this.setState(state)
+ }
+ editProject(isEdit) {
+ this.setState({
+ isReadOnly: isEdit
+ })
+ }
+ handleCloseProjectPanel() {
+ this.setState({
+ projectOpen: false,
+ isEdit: false,
+ isReadOnly: true
+ })
+ }
+ handleHideColumns(e) {
+ if(this.projectOpen && e.currentTarget.classList.contains('hideColumns')) {
+ this.setState({
+ hideColumns: true
+ })
+ } else {
+ this.setState({
+ hideColumns: false
+ })
+ }
+ }
+ handleDisabledChange(isDisabled){
+ this.setState({
+ disabled: isDisabled
+ })
+ }
+ handlePlatformRoleUpdate(data){
+ let platform_role = data[0];
+ let checked = data[1];
+ let platformRoles = this.platformRoles;
+ platformRoles[platform_role] = checked;
+ this.setState({
+ platformRoles
+ })
+ }
+ handleSelectedUser(event) {
+ this.setState({
+ selectedUser: JSON.parse(event.currentTarget.value)
+ })
+ }
+
+ handleSelectedRole(event) {
+ this.setState({
+ selectedRole: JSON.parse(event.currentTarget.value)
+ })
+ }
+ resetProject() {
+ let name = '';
+ let description = '';
+ return {
+ 'name' : name,
+ 'description' : description
+ }
+ }
+ handleAddProject() {
+ this.setState(_.merge( this.resetProject() ,
+ {
+ isEdit: false,
+ projectOpen: true,
+ activeIndex: null,
+ isReadOnly: false,
+ projectUsers: []
+ }
+ ))
+ }
+
+ handleUpdateSelectedUser(user) {
+ this.setState({
+ selectedUser: JSON.parse(user)
+ });
+ }
+ handleAddUser(e) {
+ let self = this;
+ let u = JSON.parse(this.selectedUser);
+ let r = this.selectedRole;
+ let projectUsers = this.projectUsers;
+ console.log('adding user')
+ projectUsers.push({
+ 'user-name': u['user-name'],
+ 'user-domain': u['user-domain'],
+ "role":[{
+ "role": r,
+ "keys": self.name
+ }
+ ]
+ })
+ this.setState({projectUsers, selectedUser: JSON.stringify(null)})
+ }
+ handleToggleUserRoleInProject(data) {
+ let self = this;
+ let {userIndex, roleIndex, checked} = data;
+ let projectUsers = this.projectUsers;
+ let selectedRole = self.roles[roleIndex];
+ if(checked) {
+ if(!projectUsers[userIndex].role) projectUsers[userIndex].role = [];
+ projectUsers[userIndex].role.push({
+ role: self.roles[roleIndex]
+ })
+ } else {
+ let role = projectUsers[userIndex].role;
+ let roleIndex = _.findIndex(role, {role:selectedRole})
+ projectUsers[userIndex].role.splice(roleIndex, 1)
+ }
+ self.setState({projectUsers});
+
+ }
+ handleUpdateUserRoleInProject(data) {
+ let {userIndex, roleIndex, value} = data;
+ let projectUsers = this.projectUsers;
+ projectUsers[userIndex].role[roleIndex].role = value;
+
+ }
+ addRoleToUserInProject(userIndex) {
+ let projectUsers = this.projectUsers;
+ if(!projectUsers[userIndex].role) {
+ projectUsers[userIndex].role = [];
+ }
+ projectUsers[userIndex].role.push({
+ 'role': null
+ });
+ this.setState({
+ projectUsers
+ })
+ }
+ handleRemoveRoleFromUserInProject (data) {
+ let {userIndex, roleIndex} = data;
+ let projectUsers = this.projectUsers;
+ projectUsers[userIndex].role.splice(roleIndex, 1);
+ this.setState({
+ projectUsers
+ })
+ }
+ handleRemoveUserFromProject (userIndex) {
+ let projectUsers = this.projectUsers;
+ projectUsers.splice(userIndex, 1);
+ this.setState({
+ projectUsers
+ })
+ }
+ getProjectsSuccess(projects) {
+ this.alt.actions.global.hideScreenLoader.defer();
+ this.setState({projects: projects});
+ }
+ getUsersSuccess(users) {
+ console.log(users)
+ this.alt.actions.global.hideScreenLoader.defer();
+ this.setState({users});
+ }
+ updateProjectSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let self = this;
+ let projects = this.projects || [];
+ projects[this.activeIndex] = {
+ 'name': this['name'],
+ 'description': this['description'],
+ 'project-config': {
+ 'user': self.projectUsers
+ }
+ }
+ this.setState({
+ projects,
+ isEdit: true,
+ isReadOnly: true
+ })
+ }
+ deleteProjectSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let projects = this.projects;
+ projects.splice(this.activeIndex, 1);
+ this.setState({projects, projectOpen: false})
+ }
+ createProjectSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let projects = this.projects || [];
+ projects.push({
+ 'name': this['name'],
+ 'description': this['description']
+ });
+ let newState = {
+ projects,
+ isEdit: true,
+ isReadOnly: true,
+ activeIndex: projects.length - 1
+ };
+ _.merge(newState)
+ this.setState(newState);
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import "babel-polyfill";
+import { render } from 'react-dom';
+import SkyquakeRouter from 'widgets/skyquake_container/skyquakeRouter.jsx';
+const config = require('json!../config.json');
+
+let context = require.context('./', true, /^\.\/.*\.jsx$/);
+let router = SkyquakeRouter(config, context);
+let element = document.querySelector('#app');
+
+render(router, element);
+
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+var Webpack = require('webpack');
+var path = require('path');
+var nodeModulesPath = path.resolve(__dirname, 'node_modules');
+var buildPath = path.resolve(__dirname, 'public', 'build');
+var mainPath = path.resolve(__dirname, 'src', 'main.js');
+var uiPluginCmakeBuild = process.env.ui_plugin_cmake_build || false;
+var frameworkPath = uiPluginCmakeBuild?'../../../../skyquake/skyquake-build/framework':'../../framework';
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var CommonsPlugin = new require("webpack/lib/optimize/CommonsChunkPlugin")
+// Added to overcome node-sass bug https://github.com/iam4x/isomorphic-flux-boilerplate/issues/62
+process.env.UV_THREADPOOL_SIZE=64;
+var config = {
+ devtool: 'source-map',
+ entry: mainPath,
+ output: {
+ path: buildPath,
+ filename: 'bundle.js',
+ publicPath: "build/"
+ },
+ resolve: {
+ extensions: ['', '.js', '.jsx', '.css', '.scss'],
+ root: path.resolve(frameworkPath),
+ alias: {
+ 'widgets': path.resolve(frameworkPath) + '/widgets',
+ 'style': path.resolve(frameworkPath) + '/style',
+ 'utils': path.resolve(frameworkPath) + '/utils'
+ }
+ },
+ module: {
+ loaders: [{
+ test: /\.(jpe?g|png|gif|svg|ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/i,
+ loader: "file-loader"
+ },
+ {
+ test: /\.(js|jsx)$/,
+ exclude: /react-treeview/,
+ loader: 'babel-loader',
+ query: {
+ presets: ["es2015", "stage-0", "react"]
+ }
+ }, {
+ test: /\.css$/,
+ loader: 'style!css'
+ }, {
+ test: /\.scss/,
+ loader: 'style!css!sass?includePaths[]='+ path.resolve(frameworkPath)
+ }
+ ]
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ filename: '../index.html'
+ , templateContent: '<div id="app"></div>'
+ }),
+ new Webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity)
+ ]
+};
+module.exports = config;
--- /dev/null
+# RIFT_IO_STANDARD_CMAKE_COPYRIGHT_HEADER(BEGIN)
+# Author(s): Kiran Kashalkar
+# Creation Date: 08/18/2015
+# RIFT_IO_STANDARD_CMAKE_COPYRIGHT_HEADER(END)
+
+##
+# DEPENDENCY ALERT
+# The submodule dependencies must be specified in the
+# .gitmodules.dep file at the top level (supermodule) directory
+# If this submodule depends other submodules remember to update
+# the .gitmodules.dep
+##
+
+cmake_minimum_required(VERSION 2.8)
+
+##
+# Submodule specific includes will go here,
+# These are specified here, since these variables are accessed
+# from multiple sub directories. If the variable is subdirectory
+# specific it must be declared in the subdirectory.
+##
+
+rift_externalproject_add(
+ user_management
+ DEPENDS skyquake
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}
+ CONFIGURE_COMMAND echo
+ BUILD_COMMAND
+ ${CMAKE_CURRENT_BINARY_DIR}/user_management/user_management-build/scripts/build.sh
+ INSTALL_COMMAND
+ ${CMAKE_CURRENT_SOURCE_DIR}/scripts/install.sh
+ ${CMAKE_CURRENT_BINARY_DIR}/user_management/user_management-build
+ ${CMAKE_INSTALL_PREFIX}/usr/share/rw.ui/skyquake
+ ${RIFT_SUBMODULE_INSTALL_PREFIX}/skyquake/${CMAKE_INSTALL_PREFIX}/usr/share/rw.ui/skyquake
+
+ BCACHE_COMMAND echo
+)
+
--- /dev/null
+{
+ "root": "public",
+ "name": "User Management",
+ "dashboard": "./dashboard/dashboard.jsx",
+ "order": 1,
+ "priority":1,
+ "admin_link": true,
+ "allow": ["rw-rbac-platform:super-admin", "rw-rbac-platform:platform-admin", "rw-rbac-platform:platform-oper"],
+ "routes": [
+ {
+ "label": "User Management Dashboard",
+ "route": "user-management",
+ "component": "./dashboard/dashboard.jsx",
+ "type": "internal",
+ "allow": ["rw-rbac-platform:super-admin", "rw-rbac-platform:platform-admin", "rw-rbac-platform:platform-oper"]
+ },{
+ "label": "Platform Role Management",
+ "route": "platform",
+ "component": "./platformRoleManagement/platformRoleManagement.jsx",
+ "type": "external"
+ },
+ {
+ "label": "User Profile",
+ "route": "user-profile",
+ "component": "./userProfile/userProfile.jsx",
+ "type": "internal",
+ "unique" : true
+ }
+ ]
+}
--- /dev/null
+{
+ "name": "config",
+ "version": "1.0.0",
+ "description": "",
+ "main": "routes.js",
+ "scripts": {
+ "start": "rm -rf public/ && mkdir public && cd public && mkdir build && cp ../src/index.html ./ && node ../server.js"
+ },
+ "author": "RIFT.io",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "alt": "^0.18.3",
+ "bluebird": "^3.4.1",
+ "express": "^4.13.3",
+ "history": "^1.17.0",
+ "jquery": "^2.2.1",
+ "json-loader": "^0.5.4",
+ "lodash": "^4.10.0",
+ "normalizr": "^2.1.0",
+ "open-iconic": "^1.1.1",
+ "prismjs": "^1.4.1",
+ "react": "^0.14.8",
+ "react-breadcrumbs": "^1.3.9",
+ "react-crouton": "^0.2.7",
+ "react-dom": "^0.14.6",
+ "react-router": "^2.0.1",
+ "react-slick": "^0.11.1",
+ "react-tabs": "^0.5.3",
+ "react-treeview": "^0.4.2",
+ "request-promise": "^3.0.0",
+ "underscore": "^1.8.3"
+ },
+ "devDependencies": {
+ "babel-core": "^6.4.5",
+ "babel-loader": "^6.2.1",
+ "babel-polyfill": "^6.9.1",
+ "babel-preset-es2015": "^6.6.0",
+ "babel-preset-react": "^6.5.0",
+ "babel-preset-stage-0": "^6.3.13",
+ "babel-runtime": "^6.3.19",
+ "cors": "^2.7.1",
+ "css-loader": "^0.23.1",
+ "file-loader": "^0.8.5",
+ "html-webpack-plugin": "^2.9.0",
+ "http-proxy": "^1.12.0",
+ "loaders.css": "^0.1.2",
+ "node-sass": "^3.4.2",
+ "react-addons-css-transition-group": "^0.14.7",
+ "sass-loader": "^3.1.2",
+ "style-loader": "^0.13.0",
+ "webpack": "^1.3.0",
+ "webpack-dev-server": "^1.10.1"
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+var app = require('express').Router();
+var cors = require('cors');
+var utils = require('../../framework/core/api_utils/utils.js')
+ // Begin Accounts API
+
+ utils.passThroughConstructor(app);
+
+module.exports = app;
--- /dev/null
+#!/bin/bash
+
+# STANDARD_RIFT_IO_COPYRIGHT
+
+PLUGIN_NAME=user-management
+# change to the directory of this script
+THIS_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+cd $THIS_DIR
+cd ..
+
+echo 'Building plugin '$PLUGIN_NAME
+echo 'Fetching third-party node_modules for '$PLUGIN_NAME
+npm install
+echo 'Fetching third-party node_modules for '$PLUGIN_NAME'...done'
+echo 'Packaging '$PLUGIN_NAME' using webpack'
+ui_plugin_cmake_build=true ./node_modules/.bin/webpack --progress --config webpack.production.config.js
+echo 'Packaging '$PLUGIN_NAME' using webpack... done'
+echo 'Building plugin '$PLUGIN_NAME'... done'
--- /dev/null
+#!/bin/bash
+
+# STANDARD_RIFT_IO_COPYRIGHT
+
+plugin=user-management
+source_dir=$1
+dest_dir=$2
+bcache_dir=$3
+
+# Create destination and build cache directories
+mkdir -p $dest_dir
+mkdir -p $bcache_dir
+
+# Create necessary directories under dest and cache dirs
+mkdir -p $dest_dir/framework
+mkdir -p $dest_dir/plugins
+mkdir -p $bcache_dir/framework
+mkdir -p $bcache_dir/plugins
+
+# Copy over built plugin's public folder, config.json, routes.js and api folder as per installed_plugins.txt
+mkdir -p $dest_dir/plugins/$plugin
+cp -Lrf $source_dir/public $dest_dir/plugins/$plugin/.
+cp -Lrf $source_dir/config.json $dest_dir/plugins/$plugin/.
+cp -Lrf $source_dir/routes.js $dest_dir/plugins/$plugin/.
+cp -Lrp $source_dir/api $dest_dir/plugins/$plugin/.
+tar -cf $dest_dir/plugins/$plugin/node_modules.tar node_modules package.json -C $source_dir
+#cp -Lrp $source_dir/node_modules $dest_dir/plugins/$plugin/.
+mkdir -p $bcache_dir/plugins/$plugin
+cp -Lrf $source_dir/public $bcache_dir/plugins/$plugin/.
+cp -Lrf $source_dir/config.json $bcache_dir/plugins/$plugin/.
+cp -Lrf $source_dir/routes.js $bcache_dir/plugins/$plugin/.
+cp -Lrp $source_dir/api $bcache_dir/plugins/$plugin/.
+tar -cf $bcache_dir/plugins/$plugin/node_modules.tar $source_dir/node_modules $source_dir/package.json
+#cp -Lrp $source_dir/node_modules $bcache_dir/plugins/$plugin/.
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+var express = require('express');
+var path = require('path');
+var httpProxy = require('http-proxy');
+var bodyParser = require('body-parser');
+var cors = require('cors');
+var session = require('express-session');
+var proxy = httpProxy.createProxyServer();
+var app = express();
+
+var isProduction = process.env.NODE_ENV === 'production';
+var port = isProduction ? 8080 : 8888;
+var publicPath = path.resolve(__dirname, 'public');
+
+if (!isProduction) {
+
+ //Routes for local development
+ var lpRoutes = require('./routes.js');
+
+ app.use(express.static(publicPath));
+ app.use(session({
+ secret: 'ritio rocks',
+ }));
+ app.use(bodyParser.urlencoded({
+ extended: true
+ }));
+ app.use(bodyParser.json());
+ app.use(cors());
+ app.use('/', lpRoutes);
+ var bundle = require('./server/bundle.js');
+ bundle();
+
+ app.all('/build/*', function (req, res) {
+ proxy.web(req, res, {
+ target: 'http://localhost:8080'
+ });
+ });
+
+}
+proxy.on('error', function(e) {
+ console.log('Could not connect to proxy, please try again...');
+});
+
+app.listen(port, function () {
+ console.log('Server running on port ' + port);
+});
+
+app.get('/*')
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import AppHeader from 'widgets/header/header.jsx';
+import UserManagementStore from './userMgmtStore.js';
+import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
+import 'style/layout.scss';
+import './userMgmt.scss';
+import {Panel, PanelWrapper} from 'widgets/panel/panel';
+import SkyquakeRBAC from 'widgets/skyquake_rbac/skyquakeRBAC.jsx';
+
+import TextInput from 'widgets/form_controls/textInput.jsx';
+import Input from 'widgets/form_controls/input.jsx';
+import Button, {ButtonGroup} from 'widgets/button/sq-button.jsx';
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import 'widgets/form_controls/formControls.scss';
+import imgAdd from '../../node_modules/open-iconic/svg/plus.svg'
+import imgRemove from '../../node_modules/open-iconic/svg/trash.svg';
+
+import ROLES from 'utils/roleConstants.js';
+const PLATFORM = ROLES.PLATFORM;
+
+class UserManagementDashboard extends React.Component {
+ constructor(props) {
+ super(props);
+ this.Store = this.props.flux.stores.hasOwnProperty('UserManagementStore') ? this.props.flux.stores.UserManagementStore : this.props.flux.createStore(UserManagementStore);
+ this.state = this.Store.getState();
+ this.actions = this.state.actions;
+ }
+ componentDidUpdate() {
+ let self = this;
+ ReactDOM.findDOMNode(this.UserList).addEventListener('transitionend', this.onTransitionEnd, false);
+ setTimeout(function() {
+ let element = self[`user-ref-${self.state.activeIndex}`]
+ element && !isElementInView(element) && element.scrollIntoView({block: 'end', behavior: 'smooth'});
+ })
+ }
+ componentWillMount() {
+ this.Store.listen(this.updateState);
+ this.Store.getUsers();
+ }
+ componentWillUnmount() {
+ this.Store.unlisten(this.updateState);
+ }
+ updateState = (state) => {
+ this.setState(state);
+ }
+ updateInput = (key, e) => {
+ let property = key;
+ this.actions.handleUpdateInput({
+ [property]:e.target.value
+ })
+ }
+ disabledChange = (e) => {
+ this.actions.handleDisabledChange(e.target.checked);
+ }
+ platformChange = (platformRole, e) => {
+ this.actions.handlePlatformRoleUpdate(platformRole, e.currentTarget.checked);
+ }
+ addProjectRole = (e) => {
+ this.actions.handleAddProjectItem();
+ }
+ removeProjectRole = (i, e) => {
+ this.actions.handleRemoveProjectItem(i);
+ }
+ updateProjectRole = (i, e) => {
+ this.actions.handleUpdateProjectRole(i, e)
+ }
+ addUser = () => {
+ this.actions.handleAddUser();
+ }
+ viewUser = (un, index) => {
+ this.actions.viewUser(un, index);
+ }
+ editUser = () => {
+ this.actions.editUser(false);
+ }
+ cancelEditUser = () => {
+ this.actions.editUser(true)
+ }
+ osePanel = () => {
+ this.actions.handleCloseUserPanel();
+ }
+ // updateUser = (e) => {
+ // e.preventDefault();
+ // e.stopPropagation();
+
+ // this.Store.updateUser();
+ // }
+ deleteUser = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ if (confirm('Are you sure you want to delete this user?')) {
+ this.Store.deleteUser({
+ 'user-name': this.state['user-name'],
+ 'user-domain': this.state['user-domain']
+ });
+ }
+
+ }
+ createUser = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ if(this.state['new-password'] != this.state['confirm-password']) {
+ this.props.actions.showNotification('Passwords do not match')
+ } else {
+ this.Store.createUser({
+ 'user-name': this.state['user-name'],
+ 'user-domain': this.state['user-domain'],
+ 'password': this.state['new-password']
+ // 'confirm-password': this.state['confirm-password']
+ });
+ }
+ }
+ updateUser = (e) => {
+ let self = this;
+ e.preventDefault();
+ e.stopPropagation();
+ let validatedPasswords = validatePasswordFields(this.state);
+ if(validatedPasswords) {
+ this.Store.updateUser(_.merge({
+ 'user-name': this.state['user-name'],
+ 'user-domain': this.state['user-domain'],
+ 'password': this.state['new-password']
+ }));
+ }
+ function validatePasswordFields(state) {
+ let oldOne = state['old-password'];
+ let newOne = state['new-password'];
+ let confirmOne = state['confirm-password'];
+ if(true) {
+ if(oldOne == newOne) {
+ self.props.actions.showNotification('Your new password must not match your old one');
+ return false;
+ }
+ if(newOne != confirmOne) {
+ self.props.actions.showNotification('Passwords do not match');
+ return false;
+ }
+ return {
+ // 'old-password': oldOne,
+ 'new-password': newOne,
+ 'confirm-password': confirmOne
+ }
+ } else {
+ return {};
+ }
+ }
+ }
+ evaluateSubmit = (e) => {
+ if (e.keyCode == 13) {
+ if (this.props.isEdit) {
+ this.updateUser(e);
+ } else {
+ this.createUser(e);
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+ onTransitionEnd = (e) => {
+ this.actions.handleHideColumns(e);
+ console.log('transition end')
+ }
+ disableChange = (e) => {
+ let value = e.target.value;
+ value = value.toUpperCase();
+ if (value=="TRUE") {
+ value = true;
+ } else {
+ value = false;
+ }
+ console.log(value)
+ }
+ render() {
+ let self = this;
+ let html;
+ let props = this.props;
+ let state = this.state;
+ let passwordSectionHTML = null;
+ let formButtonsHTML = (
+ <ButtonGroup className="buttonGroup">
+ <Button label="EDIT" type="submit" onClick={this.editUser} />
+ </ButtonGroup>
+ );
+ if(!this.state.isReadOnly) {
+ passwordSectionHTML = ( this.state.isEdit ?
+ (
+ <FormSection title="PASSWORD CHANGE">
+ <Input label="NEW PASSWORD" type="password" value={state['new-password']} onChange={this.updateInput.bind(null, 'new-password')}/>
+ <Input label="REPEAT NEW PASSWORD" type="password" value={state['confirm-password']} onChange={this.updateInput.bind(null, 'confirm-password')}/>
+ </FormSection>
+ ) :
+ (
+ <FormSection title="CREATE PASSWORD">
+ <Input label="CREATE PASSWORD" type="password" value={state.newPassword} onChange={this.updateInput.bind(null, 'new-password')}/>
+ <Input label="REPEAT PASSWORD" type="password" value={state.repeatNewPassword} onChange={this.updateInput.bind(null, 'confirm-password')}/>
+ </FormSection>
+ )
+ );
+ formButtonsHTML = (
+ state.isEdit ?
+ (
+ <ButtonGroup className="buttonGroup">
+ <Button label="Update" type="submit" onClick={this.updateUser} />
+ <Button label="Delete" onClick={this.deleteUser} />
+ <Button label="Cancel" onClick={this.cancelEditUser} />
+ </ButtonGroup>
+ )
+ : (
+ <ButtonGroup className="buttonGroup">
+ <Button label="Create" type="submit" onClick={this.createUser} />
+ </ButtonGroup>
+ )
+ )
+ }
+ html = (
+ <PanelWrapper column>
+ <SkyquakeRBAC allow={[PLATFORM.SUPER, PLATFORM.ADMIN]} >
+ <AppHeader nav={[{name: 'PLATFORM ROLE MANAGEMENT', onClick: this.context.router.push.bind(this, {pathname: '/platform'})}]}/>
+ </SkyquakeRBAC>
+ <PanelWrapper className={`row userManagement ${!this.state.userOpen ? 'userList-open' : ''}`} style={{'flexDirection': 'row'}} >
+ <PanelWrapper ref={(div) => { this.UserList = div}} className={`column userList expanded ${this.state.userOpen ? 'collapsed ' : ' '} ${this.state.hideColumns ? 'hideColumns ' : ' '}`}>
+ <Panel title="User List" style={{marginBottom: 0}} no-corners>
+ <div className="tableRow tableRow--header">
+ <div className="userName">
+ Username
+ </div>
+ <div>
+ Domain
+ </div>
+ </div>
+ {state.users && state.users.map((u, k) => {
+ let platformRoles = [];
+ for(let role in u.platformRoles) {
+ platformRoles.push(<div>{`${role}: ${u.platformRoles[role]}`}</div>)
+ }
+ return (
+ <div ref={(el) => this[`user-ref-${k}`] = el} className={`tableRow tableRow--data ${((self.state.activeIndex == k) && self.state.userOpen) ? 'tableRow--data-active' : ''}`}
+ key={k}
+ onClick={self.viewUser.bind(null, u, k)}>
+ <div
+ className={`userName userName-header ${((self.state.activeIndex == k) && self.state.userOpen) ? 'activeUser' : ''}`}
+ >
+ {u['user-name']}
+ </div>
+ <div>
+ {u['user-domain']}
+ </div>
+
+
+ </div>
+ )
+ })}
+ </Panel>
+ <SkyquakeRBAC allow={[PLATFORM.SUPER, PLATFORM.ADMIN]} className="rbacButtonGroup">
+ <ButtonGroup className="buttonGroup">
+ <Button label="Add User" onClick={this.addUser} />
+ </ButtonGroup>
+ </SkyquakeRBAC>
+ </PanelWrapper>
+ <PanelWrapper onKeyUp={this.evaluateSubmit}
+ className={`userAdmin column`}>
+ <Panel
+ title={state.isEdit ? state['user-name'] : 'Create User'}
+ style={{marginBottom: 0}}
+ hasCloseButton={this.closePanel}
+ no-corners>
+ <FormSection title="USER INFO">
+ {
+ this.state.isEdit ?
+ null
+ : <Input readonly={state.isReadOnly} label="Username" value={state['user-name']} onChange={this.updateInput.bind(null, 'user-name')} />
+ }
+ <Input readonly={true} label="Domain" value={state['user-domain']} onChange={this.updateInput.bind(null, 'user-domain')}></Input>
+ </FormSection>
+ <FormSection title="PLATFORM ROLES" style={{display:'none'}}>
+ <Input label="Super Admin" onChange={this.platformChange.bind(null, 'super_admin')} checked={state.platformRoles.super_admin} type="checkbox" />
+ <Input label="Platform Admin" onChange={this.platformChange.bind(null, 'platform_admin')} checked={state.platformRoles.platform_admin} type="checkbox" />
+ <Input label="Platform Oper" onChange={this.platformChange.bind(null, 'platform_oper')} checked={state.platformRoles.platform_oper} type="checkbox" />
+ </FormSection>
+ <FormSection title="PROJECT ROLES" style={{display:'none'}}>
+ <InputCollection
+ inital={true}
+ type='select'
+ readonly={state.isReadOnly}
+ options={state.projectRolesOptions}
+ collection={state.projectRoles}
+ onChange={this.updateProjectRole}
+ AddItemFn={this.addProjectRole}
+ RemoveItemFn={this.removeProjectRole}
+ />
+ </FormSection>
+ {passwordSectionHTML}
+
+ </Panel>
+ <SkyquakeRBAC allow={[PLATFORM.SUPER, PLATFORM.ADMIN]} className="rbacButtonGroup">
+ {formButtonsHTML}
+ </SkyquakeRBAC>
+ </PanelWrapper>
+ </PanelWrapper>
+ </PanelWrapper>
+ );
+ return html;
+ }
+}
+// onClick={this.Store.update.bind(null, Account)}
+UserManagementDashboard.contextTypes = {
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
+};
+
+UserManagementDashboard.defaultProps = {
+ userList: [],
+ selectedUser: {}
+}
+
+export default SkyquakeComponent(UserManagementDashboard);
+
+
+function isElementInView(el) {
+ var rect = el && el.getBoundingClientRect() || {};
+
+ return (
+ rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
+ );
+}
+
+
+// isReadOnly={state.isReadOnly} disabled={state.disabled} onChange={this.disableChange}
+
+class isDisabled extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+ render() {
+ let props = this.props;
+ return (<div/>)
+ }
+}
+
+/**
+ * AddItemFn:
+ */
+class InputCollection extends React.Component {
+ constructor(props) {
+ super(props);
+ this.collection = props.collection;
+ }
+ buildTextInput(onChange, v, i) {
+ return (
+ <Input
+ readonly={this.props.readonly}
+ style={{flex: '1 1'}}
+ key={i}
+ value={v}
+ onChange= {onChange.bind(null, i)}
+ />
+ )
+ }
+ buildSelectOption(initial, options, onChange, v, i) {
+ return (
+ <SelectOption
+ readonly={this.props.readonly}
+ key={`${i}-${v.replace(' ', '_')}`}
+ intial={initial}
+ defaultValue={v}
+ options={options}
+ onChange={onChange.bind(null, i)}
+ />
+ );
+ }
+ showInput() {
+
+ }
+ render() {
+ const props = this.props;
+ let inputType;
+ let className = "InputCollection";
+ if (props.className) {
+ className = `${className} ${props.className}`;
+ }
+ if (props.type == 'select') {
+ inputType = this.buildSelectOption.bind(this, props.initial, props.options, props.onChange);
+ } else {
+ inputType = this.buildTextInput.bind(this, props.onChange)
+ }
+ let html = (
+ <div className="InputCollection-wrapper">
+ {props.collection.map((v,i) => {
+ return (
+ <div key={i} className={className} >
+ {inputType(v, i)}
+ {
+ props.readonly ? null : <span onClick={props.RemoveItemFn.bind(null, i)} className="removeInput"><img src={imgRemove} />Remove</span>}
+ </div>
+ )
+ })}
+ { props.readonly ? null : <span onClick={props.AddItemFn} className="addInput"><img src={imgAdd} />Add</span>}
+ </div>
+ );
+ return html;
+ }
+}
+
+InputCollection.defaultProps = {
+ input: Input,
+ collection: [],
+ onChange: function(i, e) {
+ console.log(`
+ Updating with: ${e.target.value}
+ At index of: ${i}
+ `)
+ },
+ AddItemFn: function(e) {
+ console.log(`Adding a new item to collection`)
+ },
+ RemoveItemFn: function(i, e) {
+ console.log(`Removing item from collection at index of: ${i}`)
+ }
+}
+
+class FormSection extends React.Component {
+ render() {
+ let className = 'FormSection ' + this.props.className;
+ let html = (
+ <div
+ style={this.props.style}
+ className={className}
+ >
+ <div className="FormSection-title">
+ {this.props.title}
+ </div>
+ <div className="FormSection-body">
+ {this.props.children}
+ </div>
+ </div>
+ );
+ return html;
+ }
+}
+
+FormSection.defaultProps = {
+ className: ''
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+/* If there's time this really needs to be rewritten. Ideally with smooth animations.*/
+@import "style/_colors.scss";
+
+.userManagement {
+ max-width: 900px;
+
+ .skyquakePanel-wrapper {
+ overflow-x: hidden;
+ }
+ .userList {
+
+ -ms-flex: 0 1 200px;
+ flex: 0 1 200px;
+
+ .activeUser {
+ font-weight:bold;
+ }
+
+ /* transition: all 2s;*/
+ &.expanded {
+ -ms-flex: 1 1 100%;
+ flex: 1 1 100%;
+ /* transition: all 300ms;*/
+ .tableRow>div:not(.userName) {
+ opacity: 1;
+ /* width:auto;*/
+ /* transition: width 600ms;*/
+ /* transition: opacity 300ms;*/
+ }
+ &.collapsed {
+ -ms-flex: 0 1 200px;
+ flex: 0 1 200px;
+ /* transition: all 2s;*/
+ .tableRow>div:not(.userName) {
+ /* opacity: 0;*/
+ /* width:0px;*/
+ display:none;
+ overflow:hidden;
+ /* transition: all 600ms;*/
+ }
+ }
+ }
+ &.hideColumns {
+ overflow:hidden;
+ >div {
+ overflow:hidden;
+ }
+ .tableRow>div:not(.userName) {
+ width: 0px;
+ /* transition: all 600ms;*/
+ }
+ .userName {
+ &--header {
+ /* display:none;*/
+ }
+ }
+ }
+ .userName {
+ cursor:pointer;
+ }
+
+ }
+
+ .userAdmin {
+ -ms-flex: 1 1;
+ flex: 1 1;
+ width:auto;
+ opacity:1;
+ }
+ &.userList-open {
+ .userAdmin {
+ -ms-flex: 0 1 0px;
+ flex: 0 1 0px;
+ opacity:0;
+ /* width: 0px;*/
+ display:none;
+ /* transition: opacity 300ms;*/
+ /* transition: width 600ms;*/
+
+ }
+ }
+ .rbacButtonGroup, .buttonSection {
+ margin: 0 0.5rem 0.5rem;
+ background: #ddd;
+ padding-bottom: 0.5rem;
+ padding: 0.5rem 0;
+ }
+ .buttonGroup {
+ border-top: #d3d3d3 1px solid;
+ padding-top:0.5rem;
+ }
+ table {
+ font-size: 0.8rem;
+ thead {
+ border-bottom:1px solid #d3d3d3;
+ td{
+ font-weight:bold;
+ }
+ }
+ td{
+ padding:0.25rem 0.5rem;
+ vertical-align: middle;
+ .checkbox {
+ -ms-flex-pack:center;
+ justify-content:center;
+ }
+ }
+ }
+}
+
+
+
+
+.tableRow {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ padding: 0.25rem;
+ margin: .125rem 0;
+ >div {
+ padding:0.25rem 1rem 0.25rem 0;
+ -ms-flex: 1 1 33%;
+ flex: 1 1 33%;
+ }
+ &--header {
+ font-weight:bold;
+ }
+ &--data {
+ &:hover:not(&-active) {
+ background:$neutral-dark-1;
+ }
+ &:hover, .activeUser, &-active{
+ cursor:pointer;
+ color:white;
+ }
+ .activeUser, &-active{
+ background: #00acee;
+ }
+ }
+
+
+ .userProfile {
+ &-table {
+ thead{
+ font-weight:bold;
+ }
+ font-size: 1rem;
+ tr {
+ td {
+ vertical-align:top;
+ }
+ }
+ }
+ }
+}
+
+.addInput, .removeInput {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-align:center;
+ align-items:center;
+ margin-left: 1rem;
+
+ font-size:0.75rem;
+ text-transform:uppercase;
+ font-weight:bold;
+
+ cursor:pointer;
+ img {
+ height:0.75rem;
+ margin-right:0.5rem;
+ width:auto;
+ }
+ span {
+ color: #5b5b5b;
+ text-transform: uppercase;
+ }
+}
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+module.exports = function(Alt) {
+ return Alt.generateActions(
+ 'handleUpdateInput',
+ 'handleAddProjectItem',
+ 'handleRemoveProjectItem',
+ 'handleUpdateProjectRole',
+ 'viewUser',
+ 'editUser',
+ 'handleCloseUserPanel',
+ 'handleHideColumns',
+ 'getUsersSuccess',
+ 'getUsersNotification',
+ 'handleDisabledChange',
+ 'handlePlatformRoleUpdate',
+ 'handleAddUser',
+ 'handleCreateUser',
+ 'handleUpdateUser',
+ 'updateUserSuccess',
+ 'createUserSuccess',
+ 'deleteUserSuccess'
+ );
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import $ from 'jquery';
+var Utils = require('utils/utils.js');
+let API_SERVER = require('utils/rw.js').getSearchParams(window.location).api_server;
+let HOST = API_SERVER;
+let NODE_PORT = require('utils/rw.js').getSearchParams(window.location).api_port || ((window.location.protocol == 'https:') ? 8443 : 8000);
+let DEV_MODE = require('utils/rw.js').getSearchParams(window.location).dev_mode || false;
+
+if (DEV_MODE) {
+ HOST = window.location.protocol + '//' + window.location.hostname;
+}
+
+
+
+
+module.exports = function(Alt) {
+ return {
+ getUsers: {
+ remote: function() {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'GET',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data.user);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error retrieving the resource orchestrator information.'
+ }),
+ success: Alt.actions.global.getUsersSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ updateUser: {
+ remote: function(state, user) {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'PUT',
+ data: user,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the user.'
+ }),
+ success: Alt.actions.global.updateUserSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ deleteUser: {
+ remote: function(state, user) {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user/${user['user-name']}/${user['user-domain']}?api_server=${API_SERVER}`,
+ type: 'DELETE',
+ data: user,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error deleting the user.'
+ }),
+ success: Alt.actions.global.deleteUserSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ createUser: {
+ remote: function(state, user) {
+
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'POST',
+ data: user,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the account.'
+ }),
+ success: Alt.actions.global.createUserSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ }
+ }
+}
+
+function interceptResponse (responses) {
+ return function(data, action, args) {
+ if(responses.hasOwnProperty(data)) {
+ return {
+ type: data,
+ msg: responses[data]
+ }
+ } else {
+ return data;
+ }
+ }
+}
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import UserManagementActions from './userMgmtActions.js';
+import UserManagementSource from './userMgmtSource.js';
+import _ from 'lodash';
+export default class UserManagementStore {
+ constructor() {
+ this.actions = UserManagementActions(this.alt);
+ this.bindActions(this.actions);
+ this.registerAsync(UserManagementSource);
+ this.users = [];
+ this['user-name'] = '';
+ this['user-domain'] = 'system';
+ this.disabled = false;
+ this.platformRoles = {
+ super_admin: false,
+ platform_admin: false,
+ platform_oper: false
+ };
+ this.projectRoles = ['Project:Role'];
+ this.projectRolesOptions = ['Choose your adventure', 'Project:Role', 'Project:Another Role'];
+ this.currentPassword = '';
+ this['old-password'] = '';
+ this['new-password'] = '';
+ this['confirm-password'] = '';
+
+ this.activeIndex = null;
+ this.isReadOnly = true;
+ this.userOpen = false;
+ this.hideColumns = false;
+ this.isEdit = false;
+ // this.exportPublicMethods({})
+ }
+ /**
+ * [handleFieldUpdate description]
+ * @param {Object} data {
+ * [store_property] : [value]
+ * }
+ * @return {[type]} [description]
+ */
+ handleUpdateInput(data) {
+ this.setState(data);
+ }
+ handleAddProjectItem(item) {
+ let projectRoles = this.projectRoles;
+ projectRoles.push('');
+ this.setState({projectRoles});
+ }
+ handleRemoveProjectItem(i) {
+ let projectRoles = this.projectRoles;
+ projectRoles.splice(i, 1);
+ console.log('Removing', projectRoles)
+ this.setState({projectRoles});
+ }
+ handleUpdateProjectRole(data) {
+ let i = data[0];
+ let e = data[1];
+ let projectRoles = this.projectRoles
+ projectRoles[i] = JSON.parse(e.currentTarget.value);
+ this.setState({
+ projectRoles
+ });
+ }
+ viewUser(data) {
+ let user = data[0];
+ let userIndex = data[1];
+
+ let ActiveUser = {
+ 'user-name': user['user-name'],
+ 'user-domain': user['user-domain'],
+ platformRoles: user.platformRoles || this.platformRoles,
+ disabled: user.disabled || this.disabled,
+ projectRoles: user.projectRoles || this.projectRoles
+ }
+ let state = _.merge({
+ activeIndex: userIndex,
+ userOpen: true,
+ isEdit: true,
+ isReadOnly: true
+ }, ActiveUser);
+ this.setState(state)
+ }
+ editUser(isEdit) {
+ this.setState({
+ isReadOnly: isEdit
+ })
+ }
+ handleCloseUserPanel() {
+ this.setState({
+ userOpen: false,
+ isEdit: false,
+ isReadOnly: true
+ })
+ }
+ handleHideColumns(e) {
+ if(this.userOpen && e.currentTarget.classList.contains('hideColumns')) {
+ this.setState({
+ hideColumns: true
+ })
+ } else {
+ this.setState({
+ hideColumns: false
+ })
+ }
+ }
+ handleDisabledChange(isDisabled){
+ this.setState({
+ disabled: isDisabled
+ })
+ }
+ handlePlatformRoleUpdate(data){
+ let platform_role = data[0];
+ let checked = data[1];
+ let platformRoles = this.platformRoles;
+ platformRoles[platform_role] = checked;
+ this.setState({
+ platformRoles
+ })
+ }
+ resetUser() {
+ let username = '';
+ let domain = 'system';
+ let disabled = false;
+ let platformRoles = {
+ super_admin: false,
+ platform_admin: false,
+ platform_oper: false
+ };
+ let projectRoles = [];
+ let currentPassword = '';
+ let oldPassword = '';
+ let newPassword = '';
+ let confirmPassword = '';
+ return {
+ 'user-name' : username,
+ 'user-domain' : domain,
+ disabled,
+ platformRoles,
+ projectRoles,
+ currentPassword,
+ 'old-password': oldPassword,
+ 'new-password': newPassword,
+ 'confirm-password': confirmPassword
+ }
+ }
+ resetPassword() {
+ let currentPassword = '';
+ let oldPassword = '';
+ let newPassword = '';
+ let confirmPassword = '';
+ return {
+ currentPassword,
+ 'old-password': oldPassword,
+ 'new-password': newPassword,
+ 'confirm-password': confirmPassword
+ }
+ }
+ handleAddUser() {
+ this.setState(_.merge( this.resetUser() ,
+ {
+ isEdit: false,
+ userOpen: true,
+ activeIndex: null,
+ isReadOnly: false
+ }
+ ))
+ }
+ handleCreateUser() {
+
+ }
+ handleUpdateUser() {
+
+ }
+
+ getUsersSuccess(users) {
+ this.alt.actions.global.hideScreenLoader.defer();
+ this.setState({users});
+ }
+ updateUserSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let users = this.users || [];
+ users[this.activeIndex] = {
+ 'user-name': this['user-name'],
+ 'user-domain': this['user-domain'],
+ platformRoles: this.platformRoles,
+ disabled: this.disabled,
+ projectRoles: this.projectRoles
+ }
+ this.setState({
+ users,
+ isEdit: true,
+ isReadOnly: true
+ })
+ }
+ deleteUserSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let users = this.users;
+ users.splice(this.activeIndex, 1);
+ this.setState({users, userOpen: false})
+ }
+ createUserSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let users = this.users || [];
+ users.push({
+ 'user-name': this['user-name'],
+ 'user-domain': this['user-domain'],
+ platformRoles: this.platformRoles,
+ disabled: this.disabled,
+ projectRoles: this.projectRoles,
+ });
+ let newState = {
+ users,
+ isEdit: true,
+ isReadOnly: true,
+ activeIndex: users.length - 1
+ };
+ _.merge(newState, this.resetPassword())
+ this.setState(newState);
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import "babel-polyfill";
+import { render } from 'react-dom';
+import SkyquakeRouter from 'widgets/skyquake_container/skyquakeRouter.jsx';
+const config = require('json!../config.json');
+
+let context = require.context('./', true, /^\.\/.*\.jsx$/);
+let router = SkyquakeRouter(config, context);
+let element = document.querySelector('#app');
+
+render(router, element);
+
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import AppHeader from 'widgets/header/header.jsx';
+import PlatformRoleManagementStore from './platformRoleManagementStore.js';
+import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
+import 'style/layout.scss';
+import './platformRoleManagement.scss';
+import {Panel, PanelWrapper} from 'widgets/panel/panel';
+import {InputCollection, FormSection} from 'widgets/form_controls/formControls.jsx';
+
+import TextInput from 'widgets/form_controls/textInput.jsx';
+import Input from 'widgets/form_controls/input.jsx';
+import Button, {ButtonGroup} from 'widgets/button/sq-button.jsx';
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import 'widgets/form_controls/formControls.scss';
+import imgAdd from '../../node_modules/open-iconic/svg/plus.svg'
+import imgRemove from '../../node_modules/open-iconic/svg/trash.svg'
+
+class PlatformRoleManagement extends React.Component {
+ constructor(props) {
+ super(props);
+ this.Store = this.props.flux.stores.hasOwnProperty('PlatformRoleManagementStore') ? this.props.flux.stores.PlatformRoleManagementStore : this.props.flux.createStore(PlatformRoleManagementStore);
+ this.state = this.Store.getState();
+ this.actions = this.state.actions;
+ this.Store.getPlatform();
+ this.Store.getUsers();
+ }
+ componentDidUpdate() {
+
+ }
+ componentWillMount() {
+ this.Store.listen(this.updateState);
+ }
+ componentWillUnmount() {
+ this.Store.unlisten(this.updateState);
+ }
+ updateState = (state) => {
+ this.setState(state);
+ }
+ updateInput = (key, e) => {
+ let property = key;
+ this.actions.handleUpdateInput({
+ [property]:e.target.value
+ })
+ }
+ disabledChange = (e) => {
+ this.actions.handleDisabledChange(e.target.checked);
+ }
+ platformChange = (platformRole, e) => {
+ this.actions.handlePlatformRoleUpdate(platformRole, e.currentTarget.checked);
+ }
+ addProjectRole = (e) => {
+ this.actions.handleAddProjectItem();
+ }
+ removeProjectRole = (i, e) => {
+ this.actions.handleRemoveProjectItem(i);
+ }
+ updateProjectRole = (i, e) => {
+ this.actions.handleUpdateProjectRole(i, e)
+ }
+ addProject = () => {
+ this.actions.handleAddProject();
+ }
+ viewProject = (un, index) => {
+ this.actions.viewProject(un, index);
+ }
+ editProject = () => {
+ this.actions.editProject(false);
+ }
+ cancelEditProject = () => {
+ this.actions.editProject(true)
+ }
+ closePanel = () => {
+ this.actions.handleCloseProjectPanel();
+ }
+
+ deleteProject = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ this.Store.deleteProject({
+ 'name': this.state['name']
+ });
+ }
+ updatePlatform = (e) => {
+ let self = this;
+ e.preventDefault();
+ e.stopPropagation();
+ let platformUsers = self.state.platformUsers;
+ let cleanUsers = this.cleanUsers(platformUsers);
+
+
+ this.Store.updatePlatform({
+ 'user': JSON.stringify(platformUsers)
+ }
+ );
+ }
+ cleanUsers(projectUsers) {
+ let cleanUsers = [];
+ //Remove null values from role
+ projectUsers.map((u) => {
+ let cleanRoles = [];
+ u.role && u.role.map((r,i) => {
+ let role = {};
+ if(r.role){
+ //removing key for rbac-platform
+ delete r.keys;
+ cleanRoles.push(r)
+ }
+ });
+ u.role = cleanRoles;
+ cleanUsers.push(u);
+ });
+ return cleanUsers;
+ }
+ evaluateSubmit = (e) => {
+ if (e.keyCode == 13) {
+ if (this.props.isEdit) {
+ this.updatePlatform(e);
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+ updateSelectedUser = (e) => {
+ this.setState({
+ selected
+ })
+ }
+ addUserToProject = (e) => {
+ this.actions.handleAddUser();
+ }
+ removeUserFromProject = (userIndex, e) => {
+ this.actions.handleRemoveUserFromProject(userIndex);
+ }
+ updateUserRoleInProject = (userIndex, roleIndex, e) => {
+ this.actions.handleUpdateUserRoleInProject({
+ userIndex,
+ roleIndex,
+ value: JSON.parse(e.target.value)
+ })
+ }
+ toggleUserRoleInProject = (userIndex, roleIndex, e) => {
+ this.actions.handleToggleUserRoleInProject({
+ userIndex,
+ roleIndex,
+ checked: JSON.parse(e.currentTarget.checked)
+ })
+ }
+ removeRoleFromUserInProject = (userIndex, roleIndex, e) => {
+ this.actions.handleRemoveRoleFromUserInProject({
+ userIndex,
+ roleIndex
+ })
+ }
+ addRoleToUserInProject = (userIndex, e) => {
+ this.actions.addRoleToUserInProject(userIndex);
+ }
+ onTransitionEnd = (e) => {
+ this.actions.handleHideColumns(e);
+ console.log('transition end')
+ }
+ disableChange = (e) => {
+ let value = e.target.value;
+ value = value.toUpperCase();
+ if (value=="TRUE") {
+ value = true;
+ } else {
+ value = false;
+ }
+ console.log(value)
+ }
+ render() {
+ let self = this;
+ let html;
+ let props = this.props;
+ let state = this.state;
+ let passwordSectionHTML = null;
+ let formButtonsHTML = (
+ <ButtonGroup className="buttonGroup">
+ <Button label="EDIT" type="submit" onClick={this.editProject} />
+ </ButtonGroup>
+ );
+ let platformUsers = [];
+ self.state.platformUsers.map((u) => {
+ platformUsers.push(u['user-name']);
+ });
+
+ if(!this.state.isReadOnly) {
+ formButtonsHTML = (
+ state.isEdit ?
+ (
+ <ButtonGroup className="buttonGroup">
+ <Button label="Update" type="submit" onClick={this.updatePlatform} />
+ <Button label="Delete" onClick={this.deleteProject} />
+ <Button label="Cancel" onClick={this.cancelEditProject} />
+ </ButtonGroup>
+ )
+ : (
+ <ButtonGroup className="buttonGroup">
+ <Button label="Edit" type="submit" onClick={this.updatePlatform} />
+ </ButtonGroup>
+ )
+ )
+ }
+
+ html = (
+ <PanelWrapper column>
+ <AppHeader nav={[{name: 'USER MANAGEMENT', onClick: this.context.router.push.bind(this, {pathname: '/'})}]}/>
+ <PanelWrapper className={`row projectManagement ${false ? 'projectList-open' : ''}`} style={{'alignContent': 'center', 'flexDirection': 'row'}} >
+ <PanelWrapper onKeyUp={this.evaluateSubmit}
+ className={`ProjectAdmin column`}>
+ <Panel
+ title="Manage Roles"
+ style={{marginBottom: 0}}
+ no-corners>
+ <FormSection title="USER ROLES">
+
+ <table>
+ <thead>
+ <tr>
+ {!state.isReadOnly ? <td></td> : null}
+ <td>User Name</td>
+ {
+ state.roles.map((r,i) => {
+ return <td key={i}>{r}</td>
+ })
+ }
+ </tr>
+ </thead>
+ <tbody>
+ {
+ state.platformUsers.map((u,i)=> {
+ let userRoles = u.role && u.role.map((r) => {
+ return r.role;
+ }) || [];
+ return (
+ <tr key={i}>
+ {!state.isReadOnly ? <td><span
+ className="removeInput"
+ onClick={self.removeUserFromProject.bind(self, u)}
+ >
+ <img src={imgRemove} />
+
+ </span></td> : null}
+ <td>
+ {u['user-name']}
+ </td>
+ {
+ state.roles.map((r,j) => {
+ return <td key={j}><Input readonly={state.isReadOnly} type="checkbox" onChange={self.toggleUserRoleInProject.bind(self, i, j)} checked={(userRoles.indexOf(r) > -1)} /></td>
+ })
+ }
+ </tr>
+ )
+ })
+ }
+ </tbody>
+ </table>
+ {
+ !state.isReadOnly ?
+ <div className="tableRow tableRow--header">
+ <div>
+ <div className="addUser">
+ <SelectOption
+ onChange={this.actions.handleSelectedUser}
+ defaultValue={state.selectedUser}
+ initial={true}
+ options={state.users && state.users.filter((u) => {
+ return platformUsers.indexOf(u['user-name']) == -1
+ }).map((u) => {
+ return {
+ label: u['user-name'],
+ value: u
+ }
+ })}
+ />
+ <span className="addInput" onClick={this.addUserToProject}><img src={imgAdd} />
+ Add User
+ </span>
+ </div>
+ </div>
+ </div> : null
+ }
+
+ </FormSection>
+ </Panel>
+ {formButtonsHTML}
+ </PanelWrapper>
+ </PanelWrapper>
+ </PanelWrapper>
+ );
+ return html;
+ }
+}
+// onClick={this.Store.update.bind(null, Account)}
+PlatformRoleManagement.contextTypes = {
+ router: React.PropTypes.object
+};
+
+PlatformRoleManagement.defaultProps = {
+ projectList: [],
+ selectedProject: {}
+}
+
+export default SkyquakeComponent(PlatformRoleManagement);
+
+
+function isElementInView(el) {
+ var rect = el && el.getBoundingClientRect() || {};
+
+ return (
+ rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
+ );
+}
+
+
+// isReadOnly={state.isReadOnly} disabled={state.disabled} onChange={this.disableChange}
+
+class isDisabled extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+ render() {
+ let props = this.props;
+ return (<div/>)
+ }
+}
+
+
+
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+/* If there's time this really needs to be rewritten. Ideally with smooth animations.*/
+@import "style/_colors.scss";
+
+.projectManagement {
+ max-width: 900px;
+
+ .skyquakePanel-wrapper {
+ overflow-x: hidden;
+ }
+ .projectList {
+
+ -ms-flex: 0 1 200px;
+ flex: 0 1 200px;
+
+ .activeUser {
+ font-weight:bold;
+ }
+
+ /* transition: all 2s;*/
+ &.expanded {
+ -ms-flex: 1 1 100%;
+ flex: 1 1 100%;
+ /* transition: all 300ms;*/
+ .tableRow>div:not(.projectName) {
+ opacity: 1;
+ /* width:auto;*/
+ /* transition: width 600ms;*/
+ /* transition: opacity 300ms;*/
+ }
+ &.collapsed {
+ -ms-flex: 0 1 200px;
+ flex: 0 1 200px;
+ /* transition: all 2s;*/
+ .tableRow>div:not(.projectName) {
+ /* opacity: 0;*/
+ /* width:0px;*/
+ display:none;
+ overflow:hidden;
+ /* transition: all 600ms;*/
+ }
+ }
+ }
+ &.hideColumns {
+ overflow:hidden;
+ >div {
+ overflow:hidden;
+ }
+ .tableRow>div:not(.projectName) {
+ width: 0px;
+ /* transition: all 600ms;*/
+ }
+ .projectName {
+ &--header {
+ /* display:none;*/
+ }
+ }
+ }
+ .projectName {
+ cursor:pointer;
+ }
+
+
+ }
+
+ .projectAdmin {
+ -ms-flex: 1 1;
+ flex: 1 1;
+ width:auto;
+ opacity:1;
+
+ textarea{
+ height: 100px;
+ }
+ }
+ &.projectList-open {
+ .projectAdmin {
+ -ms-flex: 0 1 0px;
+ flex: 0 1 0px;
+ opacity:0;
+ /* width: 0px;*/
+ display:none;
+ /* transition: opacity 300ms;*/
+ /* transition: width 600ms;*/
+
+ }
+ }
+ .buttonGroup {
+ margin: 0 0.5rem 0.5rem;
+ background: #ddd;
+ padding-bottom: 0.5rem;
+ padding: 0.5rem 0;
+ border-top: #d3d3d3 1px solid;
+ }
+ .addUser {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-direction:row;
+ flex-direction:row;
+ label {
+ -ms-flex: 0 1;
+ flex: 0 1;
+ width:150px;
+ select {
+ width:150px;
+ }
+ }
+ }
+ .projectUsers {
+ .userName {
+ -ms-flex-pack: start;
+ justify-content: flex-start;
+ padding-top: 0.75rem;
+ }
+ select {
+ margin-bottom:0.5rem;
+ }
+ .addRole {
+ margin:.25rem 0;
+ }
+ .buttonGroup {
+ display:-ms-flexbox;
+ display:flex;
+ }
+
+ }
+ .projectUsers.tableRow--data:hover {
+ background:none;
+ color: black;
+ }
+
+ table {
+ thead {
+ border-bottom:1px solid #d3d3d3;
+ td{
+ font-weight:bold;
+ }
+ }
+ td{
+ padding:0.25rem 0.5rem;
+ vertical-align: middle;
+ .checkbox {
+ -ms-flex-pack:center;
+ justify-content:center;
+ }
+ }
+ }
+}
+
+
+
+.FormSection {
+ &-title {
+ color: #000;
+ background: lightgray;
+ padding: 0.5rem;
+ border-top: 1px solid #f1f1f1;
+ border-bottom: 1px solid #f1f1f1;
+ }
+ &-body {
+ padding: 0.5rem 0.75rem;
+ }
+ label {
+ -ms-flex: 1 0;
+ flex: 1 0;
+ }
+ /* label {*/
+ /* display: -ms-flexbox;*/
+ /* display: flex;*/
+ /* -ms-flex-direction: column;*/
+ /* flex-direction: column;*/
+ /* width: 100%;*/
+ /* margin: 0.5rem 0;*/
+ /* -ms-flex-align: start;*/
+ /* align-items: flex-start;*/
+ /* -ms-flex-pack: start;*/
+ /* justify-content: flex-start;*/
+ /* }*/
+ select {
+ font-size: 1rem;
+ min-width: 75%;
+ height: 35px;
+ }
+}
+
+
+.InputCollection {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ -ms-flex-align: center;
+ align-items: center;
+ button {
+ padding: 0.25rem;
+ height: 1.5rem;
+ font-size: 0.75rem;
+ }
+ select {
+ min-width: 100%;
+ }
+ margin-bottom:0.5rem;
+ &-wrapper {
+
+ }
+}
+.tableRow {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-wrap: nowrap;
+ flex-wrap: nowrap;
+ padding: 0.25rem;
+ margin: .125rem 0;
+ >div {
+ padding: 0.25rem;
+ -ms-flex: 1 1 33%;
+ flex: 1 1 33%;
+ display: -ms-flexbox;
+ display: flex;
+ -ms-flex-direction: column;
+ flex-direction: column;
+ -ms-flex-pack: center;
+ justify-content: center;
+ }
+ &--header {
+ font-weight:bold;
+ }
+ &--data {
+ &:hover:not(&-active) {
+ background:$neutral-dark-1;
+ }
+ &:hover, .activeUser, &-active{
+ cursor:pointer;
+ color:white;
+ }
+ .activeUser, &-active{
+ background: #00acee;
+ }
+ }
+}
+
+.addInput, .removeInput {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-align:center;
+ align-items:center;
+ margin-left: 1rem;
+
+ font-size:0.75rem;
+ text-transform:uppercase;
+ font-weight:bold;
+
+ cursor:pointer;
+ img {
+ height:0.75rem;
+ margin-right:0.5rem;
+ width:auto;
+ }
+ span {
+ color: #5b5b5b;
+ text-transform: uppercase;
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+module.exports = function(Alt) {
+ return Alt.generateActions(
+ 'handleUpdateInput',
+ 'handleAddProjectItem',
+ 'handleRemoveProjectItem',
+ 'handleUpdateProjectRole',
+ 'viewProject',
+ 'editProject',
+ 'handleCloseProjectPanel',
+ 'handleHideColumns',
+ 'handleSelectedUser',
+ 'handleSelectedRole',
+ 'handleAddUser',
+ 'handleRemoveUserFromProject',
+ 'getProjectsSuccess',
+ 'getPlatformSuccess',
+ 'getPlatformRoleUsersSuccess',
+ 'getProjectsNotification',
+ 'handleDisabledChange',
+ 'handlePlatformRoleUpdate',
+ 'handleAddProject',
+ 'handleCreateProject',
+ 'handleUpdateProject',
+ 'handleUpdateSelectedUser',
+ 'handleUpdateUserRoleInProject',
+ 'handleToggleUserRoleInProject',
+ 'addRoleToUserInProject',
+ 'handleRemoveRoleFromUserInProject',
+ 'updateProjectSuccess',
+ 'createProjectSuccess',
+ 'deleteProjectSuccess'
+ );
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import $ from 'jquery';
+var Utils = require('utils/utils.js');
+let API_SERVER = require('utils/rw.js').getSearchParams(window.location).api_server;
+let HOST = API_SERVER;
+let NODE_PORT = require('utils/rw.js').getSearchParams(window.location).api_port || ((window.location.protocol == 'https:') ? 8443 : 8000);
+let DEV_MODE = require('utils/rw.js').getSearchParams(window.location).dev_mode || false;
+
+if (DEV_MODE) {
+ HOST = window.location.protocol + '//' + window.location.hostname;
+}
+
+
+
+module.exports = function(Alt) {
+ return {
+
+ getUsers: {
+ remote: function() {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'GET',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data.user);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error retrieving the resource orchestrator information.'
+ }),
+ success: Alt.actions.global.getPlatformRoleUsersSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ getPlatform: {
+ remote: function() {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/platform?api_server=${API_SERVER}`,
+ type: 'GET',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data.platform);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error retrieving the resource orchestrator information.'
+ }),
+ success: Alt.actions.global.getPlatformSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ updatePlatform: {
+ remote: function(state, project) {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/platform?api_server=${API_SERVER}`,
+ type: 'PUT',
+ data: project,
+ dataType: 'json',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the project.'
+ }),
+ success: Alt.actions.global.updateProjectSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ deleteProject: {
+ remote: function(state, project) {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/project/${project['name']}?api_server=${API_SERVER}`,
+ type: 'DELETE',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error deleting the user.'
+ }),
+ success: Alt.actions.global.deleteProjectSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ createProject: {
+ remote: function(state, project) {
+
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/project?api_server=${API_SERVER}`,
+ type: 'POST',
+ data: project,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the account.'
+ }),
+ success: Alt.actions.global.createProjectSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ }
+ }
+}
+
+function interceptResponse (responses) {
+ return function(data, action, args) {
+ if(responses.hasOwnProperty(data)) {
+ return {
+ type: data,
+ msg: responses[data]
+ }
+ } else {
+ return data;
+ }
+ }
+}
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import PlatformRoleManagementActions from './platformRoleManagementActions.js';
+import PlatformRoleManagementSource from './platformRoleManagementSource.js';
+import _ from 'lodash';
+export default class PlatformRoleManagementStore {
+ constructor() {
+ this.actions = PlatformRoleManagementActions(this.alt);
+ this.bindActions(this.actions);
+ this.registerAsync(PlatformRoleManagementSource);
+ this.projects = [];
+ this['name'] = '';
+ this['description'] = 'Some Description';
+ this.platformUsers = [];
+ this.selectedUser = null;
+ this.selectedRole = null;
+ this.roles = ['rw-rbac-platform:platform-admin', 'rw-rbac-platform:platform-oper', 'rw-rbac-platform:super-admin'
+ // 'some_other_role', 'yet_another_role', 'operator_role', 'some_other_role', 'yet_another_role'
+ ];
+ this.users = [];
+ this.activeIndex = null;
+ this.isReadOnly = true;
+ this.projectOpen = false;
+ this.hideColumns = false;
+ this.isEdit = false;
+ // this.exportPublicMethods({})
+ }
+ /**
+ * [handleFieldUpdate description]
+ * @param {Object} data {
+ * [store_property] : [value]
+ * }
+ * @return {[type]} [description]
+ */
+ handleUpdateInput(data) {
+ this.setState(data);
+ }
+ handleAddProjectItem(item) {
+ let projectRoles = this.projectRoles;
+ projectRoles.push('');
+ this.setState({projectRoles});
+ }
+ handleRemoveProjectItem(i) {
+ let projectRoles = this.projectRoles;
+ projectRoles.splice(i, 1);
+ console.log('Removing', projectRoles)
+ this.setState({projectRoles});
+ }
+ handleUpdateProjectRole(data) {
+ let i = data[0];
+ let e = data[1];
+ let projectRoles = this.projectRoles
+ projectRoles[i] = JSON.parse(e.currentTarget.value);
+ this.setState({
+ projectRoles
+ });
+ }
+ viewProject(data) {
+ let project = data[0];
+ let projectIndex = data[1];
+
+ let ProjectUser = {
+ 'name': project['name'],
+ 'description': project['description'],
+ 'platformUsers': project['project-config'] && project['project-config']['user'] || []
+ }
+ let state = _.merge({
+ activeIndex: projectIndex,
+ projectOpen: true,
+ isEdit: true,
+ isReadOnly: true
+ }, ProjectUser);
+ this.setState(state)
+ }
+ editProject(isEdit) {
+ this.setState({
+ isReadOnly: isEdit
+ })
+ }
+ handleCloseProjectPanel() {
+ this.setState({
+ projectOpen: false,
+ isEdit: false,
+ isReadOnly: true
+ })
+ }
+ handleHideColumns(e) {
+ if(this.projectOpen && e.currentTarget.classList.contains('hideColumns')) {
+ this.setState({
+ hideColumns: true
+ })
+ } else {
+ this.setState({
+ hideColumns: false
+ })
+ }
+ }
+ handleDisabledChange(isDisabled){
+ this.setState({
+ disabled: isDisabled
+ })
+ }
+ handlePlatformRoleUpdate(data){
+ let platform_role = data[0];
+ let checked = data[1];
+ let platformRoles = this.platformRoles;
+ platformRoles[platform_role] = checked;
+ this.setState({
+ platformRoles
+ })
+ }
+ handleSelectedUser(event) {
+ this.setState({
+ selectedUser: JSON.parse(event.currentTarget.value)
+ })
+ }
+
+ handleSelectedRole(event) {
+ this.setState({
+ selectedRole: JSON.parse(event.currentTarget.value)
+ })
+ }
+ resetProject() {
+ let name = '';
+ let description = '';
+ return {
+ 'name' : name,
+ 'description' : description
+ }
+ }
+ handleAddProject() {
+ this.setState(_.merge( this.resetProject() ,
+ {
+ isEdit: false,
+ projectOpen: true,
+ activeIndex: null,
+ isReadOnly: false,
+ platformUsers: []
+ }
+ ))
+ }
+
+ handleUpdateSelectedUser(user) {
+ this.setState({
+ selectedUser: JSON.parse(user)
+ });
+ }
+ handleAddUser() {
+ let u = JSON.parse(this.selectedUser);
+ let r = this.selectedRole;
+ let platformUsers = this.platformUsers;
+ console.log('adding user')
+ platformUsers.push({
+ 'user-name': u['user-name'],
+ 'user-domain': u['user-domain'],
+ "role":[{
+ "role": r
+ }
+ ]
+ })
+ this.setState({platformUsers, selectedUser: null})
+ }
+ handleToggleUserRoleInProject(data) {
+ let self = this;
+ let {userIndex, roleIndex, checked} = data;
+ let platformUsers = this.platformUsers;
+ let selectedRole = self.roles[roleIndex];
+ if(checked) {
+ if(!platformUsers[userIndex].role) platformUsers[userIndex].role = [];
+ platformUsers[userIndex].role.push({
+ role: selectedRole
+ })
+ } else {
+ let role = platformUsers[userIndex].role;
+ platformUsers[userIndex].role.splice(_.findIndex(role, function(r) { return r.role == selectedRole; }), 1)
+ }
+ self.setState({platformUsers});
+
+ }
+ handleUpdateUserRoleInProject(data) {
+ let {userIndex, roleIndex, value} = data;
+ let platformUsers = this.platformUsers;
+ platformUsers[userIndex].role[roleIndex].role = value;
+
+ }
+ addRoleToUserInProject(userIndex) {
+ let platformUsers = this.platformUsers;
+ if(!platformUsers[userIndex].role) {
+ platformUsers[userIndex].role = [];
+ }
+ platformUsers[userIndex].role.push({
+ 'role': null
+ });
+ this.setState({
+ platformUsers
+ })
+ }
+ handleRemoveRoleFromUserInProject (data) {
+ let {userIndex, roleIndex} = data;
+ let platformUsers = this.platformUsers;
+ platformUsers[userIndex].role.splice(roleIndex, 1);
+ this.setState({
+ platformUsers
+ })
+ }
+ handleRemoveUserFromProject (userIndex) {
+ let platformUsers = this.platformUsers;
+ platformUsers.splice(userIndex, 1);
+ this.setState({
+ platformUsers
+ })
+ }
+ getProjectsSuccess(projects) {
+ this.alt.actions.global.hideScreenLoader.defer();
+ this.setState({projects: projects});
+ }
+ getPlatformSuccess(platform) {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let platformUsers = platform && platform.user || [];
+ let state = _.merge({
+ platform: platform,
+ projectOpen: true,
+ isEdit: true,
+ isReadOnly: true,
+ platformUsers: platformUsers
+ });
+ this.setState(state)
+ }
+ getPlatformRoleUsersSuccess(users) {
+ console.log(users)
+ this.alt.actions.global.hideScreenLoader.defer();
+ this.setState({users});
+ }
+ updateProjectSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let projects = this.projects || [];
+ projects[this.activeIndex] = {
+ 'name': this['name'],
+ 'description': this['description']
+ }
+ this.setState({
+ projects,
+ isEdit: true,
+ isReadOnly: true
+ })
+ }
+ deleteProjectSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let projects = this.projects;
+ projects.splice(this.activeIndex, 1);
+ this.setState({projects, projectOpen: false})
+ }
+ createProjectSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let projects = this.projects || [];
+ projects.push({
+ 'name': this['name'],
+ 'description': this['description']
+ });
+ let newState = {
+ projects,
+ isEdit: true,
+ isReadOnly: true,
+ activeIndex: projects.length - 1
+ };
+ _.merge(newState)
+ this.setState(newState);
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import AppHeader from 'widgets/header/header.jsx';
+import UserProfileStore from './userProfileStore.js';
+import SkyquakeComponent from 'widgets/skyquake_container/skyquakeComponent.jsx';
+import 'style/layout.scss';
+import '../dashboard/userMgmt.scss';
+import {Panel, PanelWrapper} from 'widgets/panel/panel';
+
+
+import TextInput from 'widgets/form_controls/textInput.jsx';
+import Input from 'widgets/form_controls/input.jsx';
+import Button, {ButtonGroup} from 'widgets/button/sq-button.jsx';
+import SelectOption from 'widgets/form_controls/selectOption.jsx';
+import 'widgets/form_controls/formControls.scss';
+import imgAdd from '../../node_modules/open-iconic/svg/plus.svg'
+import imgRemove from '../../node_modules/open-iconic/svg/trash.svg';
+
+class UserProfileDashboard extends React.Component {
+ constructor(props) {
+ super(props);
+ this.Store = this.props.flux.stores.hasOwnProperty('UserProfileStore') ? this.props.flux.stores.UserProfileStore : this.props.flux.createStore(UserProfileStore);
+ this.state = this.Store.getState();
+ this.actions = this.state.actions;
+
+ }
+ componentDidUpdate() {
+ let self = this;
+ ReactDOM.findDOMNode(this.UserList).addEventListener('transitionend', this.onTransitionEnd, false);
+ setTimeout(function() {
+ let element = self[`user-ref-${self.state.activeIndex}`]
+ element && !isElementInView(element) && element.scrollIntoView({block: 'end', behavior: 'smooth'});
+ })
+ }
+ componentWillMount() {
+ this.Store.listen(this.updateState);
+ }
+ componentWillUnmount() {
+ this.Store.unlisten(this.updateState);
+ }
+ updateState = (state) => {
+ this.setState(state);
+ }
+ updateInput = (key, e) => {
+ let property = key;
+ this.actions.handleUpdateInput({
+ [property]:e.target.value
+ })
+ }
+ disabledChange = (e) => {
+ this.actions.handleDisabledChange(e.target.checked);
+ }
+ platformChange = (platformRole, e) => {
+ this.actions.handlePlatformRoleUpdate(platformRole, e.currentTarget.checked);
+ }
+ addProjectRole = (e) => {
+ this.actions.handleAddProjectItem();
+ }
+ removeProjectRole = (i, e) => {
+ this.actions.handleRemoveProjectItem(i);
+ }
+ updateProjectRole = (i, e) => {
+ this.actions.handleUpdateProjectRole(i, e)
+ }
+ addUser = () => {
+ this.actions.handleAddUser();
+ }
+ viewUser = (un, index) => {
+ this.actions.viewUser(un, index);
+ }
+ editUser = () => {
+ this.actions.editUser(false);
+ }
+ cancelEditUser = () => {
+ this.actions.editUser(true)
+ }
+ osePanel = () => {
+ this.actions.handleCloseUserPanel();
+ }
+ // updateUser = (e) => {
+ // e.preventDefault();
+ // e.stopPropagation();
+
+ // this.Store.updateUser();
+ // }
+ deleteUser = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ this.Store.deleteUser({
+ 'user-name': this.state['user-name'],
+ 'user-domain': this.state['user-domain']
+ });
+ }
+ createUser = (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ if(this.state['new-password'] != this.state['confirm-password']) {
+ this.props.actions.showNotification('Passwords do not match')
+ } else {
+ this.Store.createUser({
+ 'user-name': this.state['user-name'],
+ 'user-domain': this.state['user-domain'],
+ 'password': this.state['new-password']
+ // 'confirm-password': this.state['confirm-password']
+ });
+ }
+ }
+ updateUser = (e) => {
+ let self = this;
+ e.preventDefault();
+ e.stopPropagation();
+ let validatedPasswords = validatePasswordFields(this.state);
+ if(validatedPasswords) {
+ this.Store.updateUser(_.merge({
+ 'user-name': this.context.userProfile.userId,
+ 'user-domain': this.state['user-domain'],
+ 'password': this.state['new-password']
+ }));
+ }
+ function validatePasswordFields(state) {
+ let oldOne = state['old-password'];
+ let newOne = state['new-password'];
+ let confirmOne = state['confirm-password'];
+ if(true) {
+ if(oldOne == newOne) {
+ self.props.actions.showNotification('Your new password must not match your old one');
+ return false;
+ }
+ if(newOne != confirmOne) {
+ self.props.actions.showNotification('Passwords do not match');
+ return false;
+ }
+ return {
+ // 'old-password': oldOne,
+ 'new-password': newOne,
+ 'confirm-password': confirmOne
+ }
+ } else {
+ return {};
+ }
+ }
+ }
+ evaluateSubmit = (e) => {
+ if (e.keyCode == 13) {
+ if (this.props.isEdit) {
+ this.updateUser(e);
+ } else {
+ this.createUser(e);
+ }
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+ onTransitionEnd = (e) => {
+ this.actions.handleHideColumns(e);
+ console.log('transition end')
+ }
+ disableChange = (e) => {
+ let value = e.target.value;
+ value = value.toUpperCase();
+ if (value=="TRUE") {
+ value = true;
+ } else {
+ value = false;
+ }
+ console.log(value)
+ }
+ render() {
+
+ let self = this;
+ const User = this.context.userProfile || {};
+ let html;
+ let props = this.props;
+ let state = this.state;
+ let passwordSectionHTML = null;
+ let formButtonsHTML = (
+ <ButtonGroup className="buttonGroup">
+ <Button label="EDIT" type="submit" onClick={this.editUser} />
+ </ButtonGroup>
+ );
+ passwordSectionHTML = (
+ (
+ <FormSection title="PASSWORD CHANGE">
+ <Input label="NEW PASSWORD" type="password" value={state['new-password']} onChange={this.updateInput.bind(null, 'new-password')}/>
+ <Input label="REPEAT NEW PASSWORD" type="password" value={state['confirm-password']} onChange={this.updateInput.bind(null, 'confirm-password')}/>
+ </FormSection>
+ )
+ );
+ formButtonsHTML = (
+ <ButtonGroup className="buttonGroup">
+ <Button label="Update" type="submit" onClick={this.updateUser} />
+ </ButtonGroup>
+ )
+
+ html = (
+ <PanelWrapper column>
+ <PanelWrapper className={`row userManagement ${!this.state.userOpen ? 'userList-open' : ''}`} style={{'flexDirection': 'row'}} >
+ <PanelWrapper ref={(div) => { this.UserList = div}} className={`column userList expanded hideColumns`}>
+ <Panel title={User.userId} style={{marginBottom: 0}} no-corners>
+ <FormSection title="USER INFO">
+ <table className="userProfile-table">
+ <thead>
+ <tr>
+ <td>Project</td>
+ <td>Role</td>
+ </tr>
+ </thead>
+ <tbody>
+ {
+ User.data && User.data.projectId && User.data.projectId.map((p,i)=> {
+ let project = User.data.project[p];
+ let projectConfig = project && project.data['project-config'];
+ let userRoles = [];
+ return (
+ <tr key={i}>
+ <td>
+ {p}
+ </td>
+ <td>
+ {
+ project && Object.keys(project.role).map(function(k) {
+ return <div>{k}</div>
+ })
+ }
+ </td>
+ </tr>
+ )
+ })
+ }
+ </tbody>
+ </table>
+ </FormSection>
+ {passwordSectionHTML}
+
+ </Panel>
+ <div className="buttonSection">
+ {formButtonsHTML}
+ </div>
+ </PanelWrapper>
+
+ </PanelWrapper>
+ </PanelWrapper>
+ );
+ return html;
+ }
+}
+// onClick={this.Store.update.bind(null, Account)}
+UserProfileDashboard.contextTypes = {
+ router: React.PropTypes.object,
+ userProfile: React.PropTypes.object
+};
+
+UserProfileDashboard.defaultProps = {
+ userList: [],
+ selectedUser: {}
+}
+
+export default SkyquakeComponent(UserProfileDashboard);
+
+
+function isElementInView(el) {
+ var rect = el && el.getBoundingClientRect() || {};
+
+ return (
+ rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
+ );
+}
+
+
+// isReadOnly={state.isReadOnly} disabled={state.disabled} onChange={this.disableChange}
+
+class isDisabled extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+ render() {
+ let props = this.props;
+ return (<div/>)
+ }
+}
+
+/**
+ * AddItemFn:
+ */
+class InputCollection extends React.Component {
+ constructor(props) {
+ super(props);
+ this.collection = props.collection;
+ }
+ buildTextInput(onChange, v, i) {
+ return (
+ <Input
+ readonly={this.props.readonly}
+ style={{flex: '1 1'}}
+ key={i}
+ value={v}
+ onChange= {onChange.bind(null, i)}
+ />
+ )
+ }
+ buildSelectOption(initial, options, onChange, v, i) {
+ return (
+ <SelectOption
+ readonly={this.props.readonly}
+ key={`${i}-${v.replace(' ', '_')}`}
+ intial={initial}
+ defaultValue={v}
+ options={options}
+ onChange={onChange.bind(null, i)}
+ />
+ );
+ }
+ showInput() {
+
+ }
+ render() {
+ const props = this.props;
+ let inputType;
+ let className = "InputCollection";
+ if (props.className) {
+ className = `${className} ${props.className}`;
+ }
+ if (props.type == 'select') {
+ inputType = this.buildSelectOption.bind(this, props.initial, props.options, props.onChange);
+ } else {
+ inputType = this.buildTextInput.bind(this, props.onChange)
+ }
+ let html = (
+ <div className="InputCollection-wrapper">
+ {props.collection.map((v,i) => {
+ return (
+ <div key={i} className={className} >
+ {inputType(v, i)}
+ {
+ props.readonly ? null : <span onClick={props.RemoveItemFn.bind(null, i)} className="removeInput"><img src={imgRemove} />Remove</span>}
+ </div>
+ )
+ })}
+ { props.readonly ? null : <span onClick={props.AddItemFn} className="addInput"><img src={imgAdd} />Add</span>}
+ </div>
+ );
+ return html;
+ }
+}
+
+InputCollection.defaultProps = {
+ input: Input,
+ collection: [],
+ onChange: function(i, e) {
+ console.log(`
+ Updating with: ${e.target.value}
+ At index of: ${i}
+ `)
+ },
+ AddItemFn: function(e) {
+ console.log(`Adding a new item to collection`)
+ },
+ RemoveItemFn: function(i, e) {
+ console.log(`Removing item from collection at index of: ${i}`)
+ }
+}
+
+class FormSection extends React.Component {
+ render() {
+ let className = 'FormSection ' + this.props.className;
+ let html = (
+ <div
+ style={this.props.style}
+ className={className}
+ >
+ <div className="FormSection-title">
+ {this.props.title}
+ </div>
+ <div className="FormSection-body">
+ {this.props.children}
+ </div>
+ </div>
+ );
+ return html;
+ }
+}
+
+FormSection.defaultProps = {
+ className: ''
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+module.exports = function(Alt) {
+ return Alt.generateActions(
+ 'handleUpdateInput',
+ 'handleAddProjectItem',
+ 'handleRemoveProjectItem',
+ 'handleUpdateProjectRole',
+ 'viewUser',
+ 'editUser',
+ 'handleCloseUserPanel',
+ 'handleHideColumns',
+ 'getUsersSuccess',
+ 'getUsersNotification',
+ 'handleDisabledChange',
+ 'handlePlatformRoleUpdate',
+ 'handleAddUser',
+ 'handleCreateUser',
+ 'handleUpdateUser',
+ 'updateUserSuccess',
+ 'createUserSuccess',
+ 'deleteUserSuccess'
+ );
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import $ from 'jquery';
+var Utils = require('utils/utils.js');
+let API_SERVER = require('utils/rw.js').getSearchParams(window.location).api_server;
+let HOST = API_SERVER;
+let NODE_PORT = require('utils/rw.js').getSearchParams(window.location).api_port || ((window.location.protocol == 'https:') ? 8443 : 8000);
+let DEV_MODE = require('utils/rw.js').getSearchParams(window.location).dev_mode || false;
+
+if (DEV_MODE) {
+ HOST = window.location.protocol + '//' + window.location.hostname;
+}
+
+
+
+
+module.exports = function(Alt) {
+ return {
+ getUsers: {
+ remote: function() {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'GET',
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data.user);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error retrieving the resource orchestrator information.'
+ }),
+ success: Alt.actions.global.getUsersSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ updateUser: {
+ remote: function(state, user) {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'PUT',
+ data: user,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the user.'
+ }),
+ success: Alt.actions.global.updateUserSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ deleteUser: {
+ remote: function(state, user) {
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user/${user['user-name']}/${user['user-domain']}?api_server=${API_SERVER}`,
+ type: 'DELETE',
+ data: user,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error deleting the user.'
+ }),
+ success: Alt.actions.global.deleteUserSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ },
+ createUser: {
+ remote: function(state, user) {
+
+ return new Promise(function(resolve, reject) {
+ $.ajax({
+ url: `/user?api_server=${API_SERVER}`,
+ type: 'POST',
+ data: user,
+ beforeSend: Utils.addAuthorizationStub,
+ success: function(data, textStatus, jqXHR) {
+ resolve(data);
+ }
+ }).fail(function(xhr){
+ //Authentication and the handling of fail states should be wrapped up into a connection class.
+ Utils.checkAuthentication(xhr.status);
+ let msg = xhr.responseText;
+ if(xhr.errorMessage) {
+ msg = xhr.errorMessage
+ }
+ reject(msg);
+ });
+ });
+ },
+ interceptResponse: interceptResponse({
+ 'error': 'There was an error updating the account.'
+ }),
+ success: Alt.actions.global.createUserSuccess,
+ loading: Alt.actions.global.showScreenLoader,
+ error: Alt.actions.global.showNotification
+ }
+ }
+}
+
+function interceptResponse (responses) {
+ return function(data, action, args) {
+ if(responses.hasOwnProperty(data)) {
+ return {
+ type: data,
+ msg: responses[data]
+ }
+ } else {
+ return data;
+ }
+ }
+}
+
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+import UserProfileActions from './userProfileActions.js';
+import UserProfileSource from './userProfileSource.js';
+import _ from 'lodash';
+export default class UserProfileStore {
+ constructor() {
+ this.actions = UserProfileActions(this.alt);
+ this.bindActions(this.actions);
+ this.registerAsync(UserProfileSource);
+ this.users = [];
+ this['user-name'] = '';
+ this['user-domain'] = 'system';
+ this.disabled = false;
+ this.roles = ['rw-project:project-admin', 'rw-project:project-oper', 'rw-project:project-create'
+ ];
+ this.currentPassword = '';
+ this['old-password'] = '';
+ this['new-password'] = '';
+ this['confirm-password'] = '';
+
+ this.activeIndex = null;
+ this.isReadOnly = true;
+ this.userOpen = false;
+ this.hideColumns = false;
+ this.isEdit = false;
+ // this.exportPublicMethods({})
+ }
+ /**
+ * [handleFieldUpdate description]
+ * @param {Object} data {
+ * [store_property] : [value]
+ * }
+ * @return {[type]} [description]
+ */
+ handleUpdateInput(data) {
+ this.setState(data);
+ }
+ handleAddProjectItem(item) {
+ let projectRoles = this.projectRoles;
+ projectRoles.push('');
+ this.setState({projectRoles});
+ }
+ handleRemoveProjectItem(i) {
+ let projectRoles = this.projectRoles;
+ projectRoles.splice(i, 1);
+ console.log('Removing', projectRoles)
+ this.setState({projectRoles});
+ }
+ handleUpdateProjectRole(data) {
+ let i = data[0];
+ let e = data[1];
+ let projectRoles = this.projectRoles
+ projectRoles[i] = JSON.parse(e.currentTarget.value);
+ this.setState({
+ projectRoles
+ });
+ }
+ viewUser(data) {
+ let user = data[0];
+ let userIndex = data[1];
+
+ let ActiveUser = {
+ 'user-name': user['user-name'],
+ 'user-domain': user['user-domain'],
+ platformRoles: user.platformRoles || this.platformRoles,
+ disabled: user.disabled || this.disabled,
+ projectRoles: user.projectRoles || this.projectRoles
+ }
+ let state = _.merge({
+ activeIndex: userIndex,
+ userOpen: true,
+ isEdit: true,
+ isReadOnly: true
+ }, ActiveUser);
+ this.setState(state)
+ }
+ editUser(isEdit) {
+ this.setState({
+ isReadOnly: isEdit
+ })
+ }
+ handleCloseUserPanel() {
+ this.setState({
+ userOpen: false,
+ isEdit: false,
+ isReadOnly: true
+ })
+ }
+ handleHideColumns(e) {
+ if(this.userOpen && e.currentTarget.classList.contains('hideColumns')) {
+ this.setState({
+ hideColumns: true
+ })
+ } else {
+ this.setState({
+ hideColumns: false
+ })
+ }
+ }
+ handleDisabledChange(isDisabled){
+ this.setState({
+ disabled: isDisabled
+ })
+ }
+ handlePlatformRoleUpdate(data){
+ let platform_role = data[0];
+ let checked = data[1];
+ let platformRoles = this.platformRoles;
+ platformRoles[platform_role] = checked;
+ this.setState({
+ platformRoles
+ })
+ }
+ resetUser() {
+ let username = '';
+ let domain = 'system';
+ let disabled = false;
+ let platformRoles = {
+ super_admin: false,
+ platform_admin: false,
+ platform_oper: false
+ };
+ let projectRoles = [];
+ let currentPassword = '';
+ let oldPassword = '';
+ let newPassword = '';
+ let confirmPassword = '';
+ return {
+ 'user-name' : username,
+ 'user-domain' : domain,
+ disabled,
+ platformRoles,
+ projectRoles,
+ currentPassword,
+ 'old-password': oldPassword,
+ 'new-password': newPassword,
+ 'confirm-password': confirmPassword
+ }
+ }
+ resetPassword() {
+ let currentPassword = '';
+ let oldPassword = '';
+ let newPassword = '';
+ let confirmPassword = '';
+ return {
+ currentPassword,
+ 'old-password': oldPassword,
+ 'new-password': newPassword,
+ 'confirm-password': confirmPassword
+ }
+ }
+ handleAddUser() {
+ this.setState(_.merge( this.resetUser() ,
+ {
+ isEdit: false,
+ userOpen: true,
+ activeIndex: null,
+ isReadOnly: false
+ }
+ ))
+ }
+ handleCreateUser() {
+
+ }
+ handleUpdateUser() {
+
+ }
+
+ getUsersSuccess(users) {
+ this.alt.actions.global.hideScreenLoader.defer();
+ this.setState({users});
+ }
+ updateUserSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let users = this.users || [];
+ users[this.activeIndex] = {
+ 'user-name': this['user-name'],
+ 'user-domain': this['user-domain'],
+ platformRoles: this.platformRoles,
+ disabled: this.disabled,
+ projectRoles: this.projectRoles
+ }
+ this.setState({
+ users,
+ isEdit: true,
+ isReadOnly: true
+ })
+ }
+ deleteUserSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let users = this.users;
+ users.splice(this.activeIndex, 1);
+ this.setState({users, userOpen: false})
+ }
+ createUserSuccess() {
+ this.alt.actions.global.hideScreenLoader.defer();
+ let users = this.users || [];
+ users.push({
+ 'user-name': this['user-name'],
+ 'user-domain': this['user-domain'],
+ platformRoles: this.platformRoles,
+ disabled: this.disabled,
+ projectRoles: this.projectRoles,
+ });
+ let newState = {
+ users,
+ isEdit: true,
+ isReadOnly: true,
+ activeIndex: users.length - 1
+ };
+ _.merge(newState, this.resetPassword())
+ this.setState(newState);
+ }
+}
--- /dev/null
+/*
+ * STANDARD_RIFT_IO_COPYRIGHT
+ */
+var Webpack = require('webpack');
+var path = require('path');
+var nodeModulesPath = path.resolve(__dirname, 'node_modules');
+var buildPath = path.resolve(__dirname, 'public', 'build');
+var mainPath = path.resolve(__dirname, 'src', 'main.js');
+var uiPluginCmakeBuild = process.env.ui_plugin_cmake_build || false;
+var frameworkPath = uiPluginCmakeBuild?'../../../../skyquake/skyquake-build/framework':'../../framework';
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var CommonsPlugin = new require("webpack/lib/optimize/CommonsChunkPlugin")
+// Added to overcome node-sass bug https://github.com/iam4x/isomorphic-flux-boilerplate/issues/62
+process.env.UV_THREADPOOL_SIZE=64;
+var config = {
+ devtool: 'source-map',
+ entry: mainPath,
+ output: {
+ path: buildPath,
+ filename: 'bundle.js',
+ publicPath: "build/"
+ },
+ resolve: {
+ extensions: ['', '.js', '.jsx', '.css', '.scss'],
+ root: path.resolve(frameworkPath),
+ alias: {
+ 'widgets': path.resolve(frameworkPath) + '/widgets',
+ 'style': path.resolve(frameworkPath) + '/style',
+ 'utils': path.resolve(frameworkPath) + '/utils'
+ }
+ },
+ module: {
+ loaders: [{
+ test: /\.(jpe?g|png|gif|svg|ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/i,
+ loader: "file-loader"
+ },
+ {
+ test: /\.(js|jsx)$/,
+ exclude: /react-treeview/,
+ loader: 'babel-loader',
+ query: {
+ presets: ["es2015", "stage-0", "react"]
+ }
+ }, {
+ test: /\.css$/,
+ loader: 'style!css'
+ }, {
+ test: /\.scss/,
+ loader: 'style!css!sass?includePaths[]='+ path.resolve(frameworkPath)
+ }
+ ]
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ filename: '../index.html'
+ , templateContent: '<div id="app"></div>'
+ }),
+ new Webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js", Infinity)
+ ]
+};
+module.exports = config;
var app = express();
+ app.set('views', __dirname + '/framework/core/views');
+ app.engine('html', require('ejs').renderFile);
+
app.use(session({
secret: 'ritio rocks',
- resave: true,
+ resave: false,
saveUninitialized: true
}));
app.use(bodyParser.json());
var descriptor_routes = require('./framework/core/modules/routes/descriptorModel');
var configuration_routes = require('./framework/core/modules/routes/configuration');
var configurationAPI = require('./framework/core/modules/api/configuration');
+ var userManagement_routes = require('./framework/core/modules/routes/userManagement');
+ var projectManagement_routes = require('./framework/core/modules/routes/projectManagement');
+ var session_routes = require('./framework/core/modules/routes/sessions');
/**
* Processing when a plugin is added or modified
* @param {string} plugin_name - Name of the plugin
}
+ /**
+ * Serve jquery
+ */
+ app.use('/jquery', express.static('./node_modules/jquery/dist/jquery.min.js'));
+ /**
+ * Serve images
+ */
+ app.use('/img', express.static('./framework/style/img'));
+
/**
* Start listening on a port
* @param {string} port - Port to listen on
//Configure descriptor route(s)
app.use(descriptor_routes);
+ //Configure user management route(s)
+ app.use(userManagement_routes);
+
+ //Configure project management route(s)
+ app.use(projectManagement_routes);
+
+ //Configure session route(s)
+ app.use(session_routes);
+
// app.get('/testme', function(req, res) {
// res.sendFile(__dirname + '/index.html');
// });