Initial commit
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
<div class="CDB-Text Dialog-header u-inner">
|
||||
<div class="Dialog-headerIcon Dialog-headerIcon--negative">
|
||||
<i class="CDB-IconFont CDB-IconFont-keys"></i>
|
||||
</div>
|
||||
<p class="Dialog-headerTitle u-ellipsLongText">
|
||||
You are about to delete your API key
|
||||
</p>
|
||||
<p class="Dialog-headerText">
|
||||
All deployed apps with this API key will stop working. Are you sure you want to continue?
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="Dialog-footer u-inner">
|
||||
<button type="button" class="CDB-Button CDB-Button--secondary js-cancel">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Cancel</span>
|
||||
</button>
|
||||
<button type="button" class="CDB-Button CDB-Button--error js-submit">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Delete API key</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,32 @@
|
||||
const CoreView = require('backbone/core-view');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
|
||||
var REQUIRED_OPTS = [
|
||||
'modalModel',
|
||||
'onSubmit',
|
||||
'template'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
events: {
|
||||
'click .js-submit': '_onSubmitClicked',
|
||||
'click .js-cancel': '_closeDialog'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
return this.$el.html(this._template());
|
||||
},
|
||||
|
||||
_onSubmitClicked: function () {
|
||||
this._onSubmit();
|
||||
this._closeDialog();
|
||||
},
|
||||
|
||||
_closeDialog: function () {
|
||||
this._modalModel.destroy();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
<div class="CDB-Text Dialog-header u-inner">
|
||||
<div class="Dialog-headerIcon Dialog-headerIcon--negative">
|
||||
<i class="CDB-IconFont CDB-IconFont-keys"></i>
|
||||
</div>
|
||||
<p class="Dialog-headerTitle u-ellipsLongText">
|
||||
You are about to regenerate your API key
|
||||
</p>
|
||||
<p class="Dialog-headerText">
|
||||
You will need to update all deployed apps with the new API key. Are you sure you want to continue?
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="Dialog-footer u-inner">
|
||||
<button type="button" class="CDB-Button CDB-Button--secondary js-cancel">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Cancel</span>
|
||||
</button>
|
||||
<button type="button" class="CDB-Button CDB-Button--error js-submit">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Regenerate API key</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,287 @@
|
||||
const _ = require('underscore');
|
||||
const Backbone = require('backbone');
|
||||
const CoreView = require('backbone/core-view');
|
||||
require('dashboard/components/form-components/index');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
const ApiKeyModel = require('dashboard/data/api-key-model');
|
||||
const TableGrantsView = require('dashboard/components/table-grants/table-grants-view');
|
||||
const TipsyTooltipView = require('builder/components/tipsy-tooltip-view');
|
||||
const template = require('./api-keys-form.tpl');
|
||||
const ApiKeysCollection = require('dashboard/data/api-keys-collection');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'stackLayoutModel',
|
||||
'userTablesModel',
|
||||
'userModel'
|
||||
];
|
||||
|
||||
const API_TYPES = {
|
||||
maps: 'maps',
|
||||
sql: 'sql'
|
||||
};
|
||||
|
||||
const DATASET_SCOPE_TYPES = {
|
||||
create: 'create',
|
||||
listing: 'listing'
|
||||
};
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
className: 'ApiKeysForm',
|
||||
|
||||
events: {
|
||||
'click .js-back': '_onClickBack',
|
||||
'click .js-submit': '_onFormSubmit',
|
||||
'change input#create': '_onChangeCreateCheckbox',
|
||||
'change input#sql': '_onChangeSqlCheckbox'
|
||||
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this._apiKeysCollection = new ApiKeysCollection(null, { userModel: this._userModel });
|
||||
this._apiKeyModel = options.apiKeyModel || new ApiKeyModel(null, { userModel: this._userModel });
|
||||
this._formView = this._generateForm();
|
||||
|
||||
this.listenTo(this._formView, 'change', this._onFormChanged);
|
||||
this.listenTo(this._apiKeyModel, 'change:tables', this._onFormChanged);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.$el.empty();
|
||||
|
||||
this._initViews();
|
||||
|
||||
this._handleCheckboxState();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_initViews: function () {
|
||||
this.$el.append(template({ modelIsNew: this._isNew() }));
|
||||
|
||||
this.$('.js-api-keys-form').append(this._formView.render().el);
|
||||
|
||||
this._tableGrantsView = new TableGrantsView({
|
||||
apiKeyModel: this._apiKeyModel,
|
||||
userTablesModel: this._userTablesModel
|
||||
});
|
||||
|
||||
this.addView(this._tableGrantsView);
|
||||
|
||||
this.$('.js-api-keys-tables').append(this._tableGrantsView.render().el);
|
||||
|
||||
if (this._isNew()) {
|
||||
this._renderTooltip();
|
||||
}
|
||||
},
|
||||
|
||||
_generateForm: function () {
|
||||
const isDisabled = !this._isNew();
|
||||
|
||||
const schema = {
|
||||
name: {
|
||||
type: 'Text',
|
||||
title: 'Name',
|
||||
validators: ['required'],
|
||||
hideValidationErrors: true,
|
||||
editorAttrs: {
|
||||
disabled: isDisabled,
|
||||
placeholder: 'Your API key name',
|
||||
id: 'js-api-key-name'
|
||||
}
|
||||
},
|
||||
token: {
|
||||
type: 'Text',
|
||||
title: 'API Key',
|
||||
hasCopyButton: isDisabled,
|
||||
editorAttrs: {
|
||||
disabled: true
|
||||
}
|
||||
},
|
||||
apis: {
|
||||
type: 'MultiCheckbox',
|
||||
title: 'APIs',
|
||||
validators: ['required'],
|
||||
hideValidationErrors: true,
|
||||
fieldClass: 'u-iBlock',
|
||||
optional: true,
|
||||
inputs: [
|
||||
{ name: API_TYPES.sql, label: 'SQL' },
|
||||
{ name: API_TYPES.maps, label: 'MAPS' }
|
||||
],
|
||||
editorAttrs: {
|
||||
disabled: isDisabled
|
||||
}
|
||||
},
|
||||
datasets: {
|
||||
type: 'MultiCheckbox',
|
||||
title: 'Datasets',
|
||||
hideValidationErrors: true,
|
||||
optional: true,
|
||||
inputs: [
|
||||
{ name: DATASET_SCOPE_TYPES.create, label: 'CREATE' },
|
||||
{ name: DATASET_SCOPE_TYPES.listing, label: 'LISTING' }
|
||||
],
|
||||
editorAttrs: {
|
||||
disabled: isDisabled
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this._formView = new Backbone.Form({ model: this._apiKeyModel, schema });
|
||||
|
||||
return this._formView;
|
||||
},
|
||||
|
||||
_isNew: function () {
|
||||
return !this._apiKeyModel.get('id');
|
||||
},
|
||||
|
||||
_onClickBack: function () {
|
||||
this._stackLayoutModel.goToStep(0);
|
||||
},
|
||||
|
||||
_renderTooltip: function () {
|
||||
this._validationTooltip = new TipsyTooltipView({
|
||||
el: this.$('.js-submit'),
|
||||
gravity: 's',
|
||||
title: () => 'Name and Datasets fields are required (Choose SQL or MAPS for specific permissions in selected datasets)'
|
||||
});
|
||||
this.addView(this._validationTooltip);
|
||||
},
|
||||
|
||||
_hasErrors: function () {
|
||||
const formErrors = this._formView.validate();
|
||||
const selectedDatasetsPermissions = this._apiKeyModel.hasPermissionsSelected();
|
||||
const selectedApis = _.some(this._formView.getValue().apis);
|
||||
const selectedCreate = this._formView.getValue().datasets.create;
|
||||
const selectedListing = this._formView.getValue().datasets.listing;
|
||||
const selectedPermissions =
|
||||
(selectedDatasetsPermissions && selectedApis) ||
|
||||
selectedCreate ||
|
||||
(selectedListing && !selectedApis);
|
||||
|
||||
return !!formErrors || !selectedPermissions;
|
||||
},
|
||||
|
||||
_addApiKeyNameError: function (message) {
|
||||
this._errorTooltip = new TipsyTooltipView({
|
||||
el: this.$('#js-api-key-name'),
|
||||
gravity: 'w',
|
||||
title: () => message
|
||||
});
|
||||
this.addView(this._errorTooltip);
|
||||
this._errorTooltip.showTipsy();
|
||||
|
||||
this.$('#js-api-key-name').addClass('has-error');
|
||||
},
|
||||
|
||||
_onFormChanged: function () {
|
||||
this._handleFormErrors();
|
||||
this._handleCheckboxState();
|
||||
this.$('.js-error').hide();
|
||||
},
|
||||
|
||||
_onChangeCreateCheckbox: function () {
|
||||
const createCheckbox = this._formView.getValue().datasets.create;
|
||||
|
||||
if (createCheckbox) {
|
||||
const apisValues = _.clone(this._formView.getValue().apis);
|
||||
apisValues.sql = createCheckbox;
|
||||
this._formView.setValue('apis', apisValues);
|
||||
this.$('input#sql').prop('checked', createCheckbox);
|
||||
}
|
||||
this._onFormChanged();
|
||||
},
|
||||
|
||||
_onChangeSqlCheckbox: function () {
|
||||
const SqlCheckbox = this._formView.getValue().apis.sql;
|
||||
|
||||
if (!SqlCheckbox) {
|
||||
const datasetsValues = _.clone(this._formView.getValue().datasets);
|
||||
datasetsValues.create = SqlCheckbox;
|
||||
this._formView.setValue('datasets', datasetsValues);
|
||||
this.$('input#create').prop('checked', SqlCheckbox);
|
||||
}
|
||||
this._onFormChanged();
|
||||
},
|
||||
|
||||
_handleCheckboxState: function () {
|
||||
const apis = this._isNew()
|
||||
? this._formView.getValue().apis
|
||||
: this._apiKeyModel.get('apis');
|
||||
const activeApis = _.keys(apis).filter(name => apis[name]);
|
||||
const disableCheckboxes = activeApis.length === 1 && _.contains(activeApis, API_TYPES.maps);
|
||||
|
||||
this.$('.ApiKeysForm-grantsTable').toggleClass('showOnlySelect', disableCheckboxes);
|
||||
},
|
||||
|
||||
_handleFormErrors: function () {
|
||||
const hasErrors = this._hasErrors();
|
||||
|
||||
this.$('.js-submit').toggleClass('is-disabled', hasErrors);
|
||||
|
||||
if (hasErrors) {
|
||||
this._validationTooltip || this._renderTooltip();
|
||||
} else {
|
||||
this._validationTooltip && this._validationTooltip.clean();
|
||||
this._validationTooltip = null;
|
||||
}
|
||||
|
||||
this.$('#js-api-key-name').removeClass('has-error');
|
||||
this._errorTooltip && this._errorTooltip.clean();
|
||||
},
|
||||
|
||||
_onFormSubmit: function (event) {
|
||||
const saveButton = this.$('.js-submit');
|
||||
const isButtonLoading = saveButton.hasClass('is-loading');
|
||||
|
||||
if (this._hasErrors() || isButtonLoading) return;
|
||||
|
||||
saveButton.addClass('is-loading');
|
||||
|
||||
const errors = this._formView.commit({ validate: true });
|
||||
|
||||
if (errors) return;
|
||||
|
||||
this._apiKeysCollection.create(this._apiKeyModel.attributes, {
|
||||
success: (model) => {
|
||||
this._apiKeyModel = model;
|
||||
this._generateForm();
|
||||
this.render();
|
||||
},
|
||||
error: (model, request) => {
|
||||
this._handleServerErrors(request.responseText);
|
||||
saveButton.removeClass('is-loading');
|
||||
},
|
||||
userModel: this._userModel
|
||||
});
|
||||
},
|
||||
|
||||
_handleServerErrors: function (error) {
|
||||
let message;
|
||||
|
||||
if (error.indexOf('Name has already been taken') !== -1) {
|
||||
message = 'Name already exists';
|
||||
} else if (error.indexOf('Name can\'t be blank') !== -1) {
|
||||
message = 'Name can\'t be blank';
|
||||
}
|
||||
|
||||
message && this._addApiKeyNameError(message);
|
||||
|
||||
if (!message) {
|
||||
this._displayUnhandledError(error);
|
||||
}
|
||||
},
|
||||
|
||||
_displayUnhandledError: function (errorJSON) {
|
||||
const parsed = JSON.parse(errorJSON);
|
||||
this.$('.js-error').text(parsed.errors).show();
|
||||
},
|
||||
|
||||
clean: function () {
|
||||
this._userTablesModel.clearParams();
|
||||
CoreView.prototype.clean.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
<section>
|
||||
<header class="ApiKeysForm-title">
|
||||
<button class="js-back">
|
||||
<i class="CDB-IconFont CDB-IconFont-arrowPrev u-actionTextColor u-rSpace--xl"></i>
|
||||
</button>
|
||||
<h3 class="CDB-Text CDB-Size-medium is-semibold u-mainTextColor">
|
||||
<% if (modelIsNew) { %>
|
||||
Configure your key
|
||||
<% } else { %>
|
||||
Your API key details
|
||||
<% } %>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<div class="js-api-keys-form"></div>
|
||||
<div class="js-api-keys-tables"></div>
|
||||
|
||||
<footer class="Editor-footer u-tSpace-m">
|
||||
<p class="CDB-Text CDB-Size-medium u-altTextColor">Changes to the key permissions are not possible once key is generated</p>
|
||||
|
||||
<% if (modelIsNew) { %>
|
||||
<button type="submit" class="CDB-Button CDB-Button--primary CDB-Button--loading is-disabled js-submit">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">Save changes</span>
|
||||
<div class="CDB-Button-loader CDB-LoaderIcon is-white">
|
||||
<svg class="CDB-LoaderIcon-spinner" viewbox="0 0 50 50">
|
||||
<circle class="CDB-LoaderIcon-path" cx="25" cy="25" r="20" fill="none"/>
|
||||
</svg>
|
||||
</div>
|
||||
</button>
|
||||
<% } %>
|
||||
</footer>
|
||||
<div class="CDB-Text CDB-Size-small u-errorTextColor js-error">
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,11 @@
|
||||
<section>
|
||||
<h4 class="CDB-Text CDB-Size-medium is-semibold u-flex u-alignCenter u-actionTextColor">
|
||||
<button class="js-edit"><%- name %></button>
|
||||
</h4>
|
||||
<p class="CDB-Text CDB-Size-medium u-secondaryTextColor u-tSpace--m u-flex u-alignCenter">
|
||||
<span class="js-token"><%- token %></span>
|
||||
<button class="js-copy">
|
||||
<i class="CDB-IconFont CDB-IconFont-anchor u-hintTextColor CDB-Size-large u-lSpace--xl"></i>
|
||||
</button>
|
||||
</p>
|
||||
</section>
|
||||
@@ -0,0 +1,25 @@
|
||||
<section class="u-width--100">
|
||||
<h4 class="CDB-Text CDB-Size-medium is-semibold u-flex u-alignCenter">
|
||||
<%- name %>
|
||||
</h4>
|
||||
<div class="u-flex u-alignCenter u-justifySpace u-tSpace--m">
|
||||
<p class="CDB-Text CDB-Size-medium u-secondaryTextColor u-flex u-alignCenter">
|
||||
<span class="js-token"><%- token %></span>
|
||||
<button class="js-copy">
|
||||
<i class="CDB-IconFont CDB-IconFont-anchor u-hintTextColor CDB-Size-large u-lSpace--xl"></i>
|
||||
</button>
|
||||
</p>
|
||||
<ul class="u-flex">
|
||||
<li>
|
||||
<button class="CDB-Text CDB-Size-medium u-actionTextColor js-regenerate">Regenerate</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="u-tSpace">
|
||||
<p class="ApiKeys-warning-text">
|
||||
<span class="js-icon-warning ApiKeys-warning-icon"></span>
|
||||
<span>For testing and development only! This API key can be used to perform any API request without restriction!</span>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<section>
|
||||
<h4 class="CDB-Text CDB-Size-medium is-semibold u-flex u-alignCenter u-actionTextColor">
|
||||
<button class="js-edit"><%- name %></button>
|
||||
|
||||
<% apiGrants.forEach(function (apiGrant) { %>
|
||||
<span class="CDB-Tag CDB-Text is-gray is-semibold CDB-Size-small u-iBlock u-lSpace--xl u-upperCase">
|
||||
<%- apiGrant %>
|
||||
</span>
|
||||
<% }) %>
|
||||
</h4>
|
||||
<p class="CDB-Text CDB-Size-medium u-secondaryTextColor u-tSpace--m u-flex u-alignCenter">
|
||||
<span class="js-token"><%- token %></span>
|
||||
<button class="js-copy">
|
||||
<i class="CDB-IconFont CDB-IconFont-anchor u-hintTextColor CDB-Size-large u-lSpace--xl"></i>
|
||||
</button>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<ul class="u-flex">
|
||||
<li>
|
||||
<button class="CDB-Text CDB-Size-medium u-actionTextColor u-rSpace--m js-regenerate">Regenerate</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="CDB-Text CDB-Size-medium u-errorTextColor js-delete">Delete</button>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,98 @@
|
||||
const $ = require('jquery');
|
||||
const CoreView = require('backbone/core-view');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
const AlertDialogView = require('dashboard/views/api-keys/alert-dialog-view');
|
||||
const ModalsServiceModel = require('builder/components/modals/modals-service-model');
|
||||
const templateDefault = require('./api-keys-list-item-default.tpl');
|
||||
const templateMaster = require('./api-keys-list-item-master.tpl');
|
||||
const templateRegular = require('./api-keys-list-item-regular.tpl');
|
||||
const deleteKeyTemplate = require('./alert-delete-key.tpl');
|
||||
const regenerateKeyTemplate = require('./alert-regenerate-key.tpl');
|
||||
const IconView = require('builder/components/icon/icon-view');
|
||||
|
||||
const TEMPLATES = {
|
||||
default: templateDefault,
|
||||
master: templateMaster,
|
||||
regular: templateRegular
|
||||
};
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'apiKeyModel',
|
||||
'onEdit'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
tagName: 'li',
|
||||
|
||||
className: 'ApiKeys-list-item',
|
||||
|
||||
events: {
|
||||
'click .js-edit': '_onItemClick',
|
||||
'click .js-delete': '_onDeleteClick',
|
||||
'click .js-regenerate': '_onRegenerateClick',
|
||||
'click .js-copy': '_onCopyClick'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this._modals = new ModalsServiceModel();
|
||||
|
||||
this._initBinds();
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._apiKeyModel, 'change', this.render);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
const template = TEMPLATES[this._apiKeyModel.get('type')];
|
||||
|
||||
this.$el.html(
|
||||
template({
|
||||
name: this._apiKeyModel.get('name'),
|
||||
token: this._apiKeyModel.get('token'),
|
||||
apiGrants: this._apiKeyModel.getApiGrants()
|
||||
})
|
||||
);
|
||||
|
||||
var warningIcon = new IconView({
|
||||
placeholder: this.$el.find('.js-icon-warning'),
|
||||
icon: 'warning'
|
||||
});
|
||||
warningIcon.render();
|
||||
this.addView(warningIcon);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_onDeleteClick: function (event) {
|
||||
const onSubmit = () => this._apiKeyModel.destroy();
|
||||
|
||||
this._modals.create(function (modalModel) {
|
||||
return new AlertDialogView({ modalModel, onSubmit, template: deleteKeyTemplate });
|
||||
});
|
||||
},
|
||||
|
||||
_onRegenerateClick: function () {
|
||||
const onSubmit = () => this._apiKeyModel.regenerate();
|
||||
|
||||
this._modals.create(function (modalModel) {
|
||||
return new AlertDialogView({ modalModel, onSubmit, template: regenerateKeyTemplate });
|
||||
});
|
||||
},
|
||||
|
||||
_onCopyClick: function () {
|
||||
const $temp = $('<input>');
|
||||
const $token = this.$('.js-token');
|
||||
|
||||
$('body').append($temp);
|
||||
$temp.val($token.text()).select();
|
||||
document.execCommand('copy');
|
||||
$temp.remove();
|
||||
},
|
||||
|
||||
_onItemClick: function () {
|
||||
this._onEdit(this._apiKeyModel);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
<li class="ApiKeys-list-loader">
|
||||
<div class="Spinner"></div>
|
||||
</li>
|
||||
@@ -0,0 +1,81 @@
|
||||
const CoreView = require('backbone/core-view');
|
||||
const PaginationView = require('builder/components/pagination/pagination-view');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
const template = require('./api-keys-list.tpl');
|
||||
const ApiKeysListItemView = require('dashboard/views/api-keys/api-keys-list-item-view');
|
||||
const loaderTemplate = require('./api-keys-list-loader.tpl');
|
||||
const ApiKeysCollection = require('dashboard/data/api-keys-collection');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'stackLayoutModel',
|
||||
'userModel',
|
||||
'apiKeysType',
|
||||
'title',
|
||||
'showNewApiKeyButton'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
events: {
|
||||
'click .js-add': '_onAddClick'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
|
||||
this._apiKeysCollection = new ApiKeysCollection(null, { userModel: this._userModel, type: this._apiKeysType });
|
||||
this._initBinds();
|
||||
this._apiKeysCollection.fetch();
|
||||
|
||||
this._onEdit = this._onEdit.bind(this);
|
||||
},
|
||||
|
||||
_initBinds: function () {
|
||||
this.listenTo(this._apiKeysCollection, 'add change remove sync', this.render);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
|
||||
this.$el.html(template({
|
||||
title: this._title,
|
||||
showNewApiKeyButton: this._showNewApiKeyButton
|
||||
}));
|
||||
|
||||
this._apiKeysCollection.status === 'fetched'
|
||||
? this._renderKeys()
|
||||
: this._renderLoading();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_renderLoading: function () {
|
||||
this.$('.js-api-keys-list').append(loaderTemplate());
|
||||
},
|
||||
|
||||
_renderKeys: function () {
|
||||
this._apiKeysCollection.forEach(apiKeyModel => {
|
||||
const view = new ApiKeysListItemView({
|
||||
apiKeyModel,
|
||||
onEdit: this._onEdit
|
||||
});
|
||||
|
||||
this.addView(view);
|
||||
|
||||
this.$('.js-api-keys-list').append(view.render().el);
|
||||
});
|
||||
|
||||
this.paginationView = new PaginationView({
|
||||
model: this._apiKeysCollection.getPaginationModel()
|
||||
});
|
||||
this.addView(this.paginationView);
|
||||
this.$('.js-api-keys-list').append(this.paginationView.render().el);
|
||||
},
|
||||
|
||||
_onAddClick: function () {
|
||||
this._stackLayoutModel.goToStep(1);
|
||||
},
|
||||
|
||||
_onEdit: function (apiKeyModel) {
|
||||
this._stackLayoutModel.goToStep(1, apiKeyModel);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,12 @@
|
||||
<section>
|
||||
<header class="ApiKeys-title">
|
||||
<h3 class="CDB-Text CDB-Size-medium is-semibold u-mainTextColor"><%= title %></h3>
|
||||
<% if (showNewApiKeyButton) { %>
|
||||
<button type="submit" class="CDB-Button CDB-Button--primary js-add">
|
||||
<span class="CDB-Button-Text CDB-Text is-semibold CDB-Size-small u-upperCase">New API key</span>
|
||||
</button>
|
||||
<% } %>
|
||||
</header>
|
||||
|
||||
<ul class="ApiKeys-list js-api-keys-list"></ul>
|
||||
</section>
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
const CoreView = require('backbone/core-view');
|
||||
const checkAndBuildOpts = require('builder/helpers/required-opts');
|
||||
const template = require('./api-keys-page.tpl');
|
||||
const ApiKeysListView = require('dashboard/views/api-keys/api-keys-list-view');
|
||||
const apiKeysCollectionTypes = require('dashboard/data/api-keys-collection-types');
|
||||
|
||||
const REQUIRED_OPTS = [
|
||||
'stackLayoutModel',
|
||||
'userModel'
|
||||
];
|
||||
|
||||
module.exports = CoreView.extend({
|
||||
initialize: function (options) {
|
||||
checkAndBuildOpts(options, REQUIRED_OPTS, this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
this.clearSubViews();
|
||||
|
||||
this.$el.html(template({
|
||||
showGoogleApiKeys: this._userModel.showGoogleApiKeys(),
|
||||
isInsideOrg: this._userModel.isInsideOrg(),
|
||||
isOrgOwner: this._userModel.isOrgOwner(),
|
||||
organizationName: this._userModel.getOrgName(),
|
||||
googleApiKey: this._userModel.getGoogleApiKey()
|
||||
}));
|
||||
|
||||
this._renderList(
|
||||
[apiKeysCollectionTypes.MASTER, apiKeysCollectionTypes.DEFAULT].join(','),
|
||||
'Default API Keys',
|
||||
false
|
||||
);
|
||||
this._renderList(apiKeysCollectionTypes.REGULAR,
|
||||
'Custom API Keys',
|
||||
true
|
||||
);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
_renderList: function (apiKeysType, title, showNewApiKeyButton) {
|
||||
const view = new ApiKeysListView({
|
||||
stackLayoutModel: this._stackLayoutModel,
|
||||
userModel: this._userModel,
|
||||
apiKeysType: apiKeysType,
|
||||
title,
|
||||
showNewApiKeyButton
|
||||
});
|
||||
|
||||
this.addView(view);
|
||||
this.$('.js-api-keys-page').append(view.render().el);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
<div class="js-api-keys-page"></div>
|
||||
|
||||
<% if (showGoogleApiKeys) { %>
|
||||
<section>
|
||||
<div class="FormAccount-title">
|
||||
<p class="FormAccount-titleText">Configure API keys from external providers</p>
|
||||
</div>
|
||||
|
||||
<span class="FormAccount-separator"></span>
|
||||
|
||||
<div class="FormAccount-row">
|
||||
<div class="FormAccount-rowLabel">
|
||||
<label class="CDB-Text CDB-Size-medium is-semibold u-mainTextColor FormAccount-label">Google Maps</label>
|
||||
</div>
|
||||
<div class="FormAccount-rowData">
|
||||
<input type="text" value="<%- googleApiKey %>" class="CDB-InputText CDB-Text FormAccount-input FormAccount-input--long is-disabled" readonly />
|
||||
</div>
|
||||
<div class="FormAccount-rowInfo">
|
||||
<% if (!isInsideOrg) { %>
|
||||
<p class="CDB-Text CDB-Size-small u-altTextColor">
|
||||
This is your Google Maps query string, contact with <a href="mailto:support@carto.com">support@carto.com</a> to change it.
|
||||
</p>
|
||||
<% } else if (isOrgOwner) { %>
|
||||
<p class="CDB-Text CDB-Size-small u-altTextColor">
|
||||
This is the <%= organizationName %> Google Maps query string, contact with <a href="mailto:support@carto.com">support@carto.com</a> to change it.
|
||||
</p>
|
||||
<% } else { %>
|
||||
<p class="CDB-Text CDB-Size-small u-altTextColor">This is the organization Google Maps API key</p>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<% } %>
|
||||
|
||||
<footer class="ApiKeys-footer">
|
||||
<p class="ApiKeys-warning-text">
|
||||
<i class="CDB-IconFont CDB-IconFont-info ApiKeys-info-icon"></i>
|
||||
<span class="u-altTextColor">Learn more about location app authorization and API key management <a href="https://carto.com/developers/fundamentals/authorization/" target="_blank">here</a></span>
|
||||
</p>
|
||||
</footer>
|
||||
@@ -0,0 +1,17 @@
|
||||
const Backbone = require('backbone');
|
||||
|
||||
/**
|
||||
* Header view model to handle state for dashboard header view.
|
||||
*/
|
||||
|
||||
module.exports = Backbone.Model.extend({
|
||||
breadcrumbTitle: () => 'Configuration',
|
||||
|
||||
isBreadcrumbDropdownEnabled: () => false,
|
||||
|
||||
isDisplayingDatasets: () => false,
|
||||
|
||||
isDisplayingMaps: () => false,
|
||||
|
||||
isDisplayingLockedItems: () => false
|
||||
});
|
||||
Reference in New Issue
Block a user