mirror of
https://github.com/Piwigo/Piwigo.git
synced 2026-06-02 04:15:05 +02:00
fixes #2355 implement API key management system
- Added API key get, creation, editing, and revocation methods. - Updated the profile template to include API key management features. - Updated the database schema to support the new API key system, including additional fields for key management. - Added client-side JavaScript functionality to handle API key operations and display responses. - Update tools/htm.ws with the new way to authenticate. - Restriction of certain api methods when used with an api key - Backward compatibility with older apps
This commit is contained in:
@@ -10,23 +10,14 @@ $(function() {
|
||||
// close
|
||||
element.style.maxHeight = element.scrollHeight + 'px';
|
||||
void element.offsetHeight;
|
||||
element.style.maxHeight = '0px';
|
||||
element.style.maxHeight = '1px';
|
||||
selector.removeClass('open');
|
||||
$(this).addClass('close');
|
||||
} else {
|
||||
// open
|
||||
selector.addClass('open');
|
||||
element.style.maxHeight = element.scrollHeight + 'px';
|
||||
resetSection(display);
|
||||
$(this).removeClass('close');
|
||||
if ('account-display' !== display) {
|
||||
setTimeout(() => {
|
||||
const el = $(`#${display.split('-')[0]}-section`).get(0);
|
||||
el.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -85,7 +76,6 @@ $(function() {
|
||||
});
|
||||
|
||||
standardSaveSelector.forEach((selector, i) => {
|
||||
// console.log(i, selector);
|
||||
$(selector).on('click', function() {
|
||||
const values = {};
|
||||
$(`#${i}-section`).find('input, textarea, select').each((i, element) => {
|
||||
@@ -126,9 +116,79 @@ $(function() {
|
||||
$('#opt_comment').prop('checked', preferencesDefaultValues.opt_comment);
|
||||
$('#opt_hits').prop('checked', preferencesDefaultValues.opt_hits);
|
||||
});
|
||||
|
||||
// API KEY BELOW
|
||||
if (!can_manage_api) {
|
||||
$('.can-manage').hide();
|
||||
$('#cant_manage_api').show();
|
||||
return;
|
||||
};
|
||||
$('#new_apikey').on('click', function() {
|
||||
openApiModal();
|
||||
});
|
||||
|
||||
$('#close_api_modal, #cancel_apikey').on('click', function() {
|
||||
closeApiModal();
|
||||
});
|
||||
|
||||
$('#close_api_modal_edit').on('click', function() {
|
||||
closeApiEditModal();
|
||||
});
|
||||
|
||||
$('#close_api_modal_revoke, #cancel_api_revoke').on('click', function() {
|
||||
closeApiRevokeModal();
|
||||
});
|
||||
|
||||
$('#show_expired_list').on('click', function() {
|
||||
const api_list_expired = $('#api_key_list_expired');
|
||||
const isOpen = $(this).data('show');
|
||||
if(!isOpen) {
|
||||
api_list_expired.get(0).style.maxHeight = 'max-content';
|
||||
$(this).text(str_hide_expired);
|
||||
} else {
|
||||
api_list_expired.get(0).style.maxHeight = '0';
|
||||
$(this).text(str_show_expired);
|
||||
}
|
||||
|
||||
$(this).data('show', !isOpen);
|
||||
|
||||
resetSection('apikey-display', false, true);
|
||||
});
|
||||
|
||||
$(window).on('keydown', function(e) {
|
||||
const haveApiModal = $('#api_modal').is(':visible');
|
||||
const haveApiEditModal = $('#api_modal_edit').is(':visible');
|
||||
const haveApiRevokeModal = $('#api_modal_revoke').is(':visible');
|
||||
if (haveApiModal && e.key === 'Escape') {
|
||||
closeApiModal();
|
||||
}
|
||||
if (haveApiEditModal && e.key === 'Escape') {
|
||||
closeApiEditModal();
|
||||
}
|
||||
if (haveApiRevokeModal && e.key === 'Escape') {
|
||||
closeApiRevokeModal();
|
||||
}
|
||||
});
|
||||
|
||||
$('select[name="api_expiration"]').on('change', function() {
|
||||
const custom_date = $('#api_custom_date');
|
||||
const value = $(this).val();
|
||||
if ('custom' === value) {
|
||||
custom_date.css('display', 'flex');
|
||||
} else {
|
||||
custom_date.css('display', 'none');
|
||||
}
|
||||
$('#error_api_key_date').hide();
|
||||
});
|
||||
|
||||
$('#api_expiration_date').on('change', function() {
|
||||
$('#error_api_key_date').hide();
|
||||
});
|
||||
|
||||
getAllApiKeys();
|
||||
});
|
||||
|
||||
function setInfos(params, method='pwg.users.setMyInfo') {
|
||||
function setInfos(params, method='pwg.users.setMyInfo', callback=null, errCallback=null) {
|
||||
// for debug
|
||||
// console.log('setInfos', params);
|
||||
const all_params = {
|
||||
@@ -142,15 +202,359 @@ function setInfos(params, method='pwg.users.setMyInfo') {
|
||||
data: all_params,
|
||||
success: (data) => {
|
||||
if (data.stat == 'ok') {
|
||||
if (typeof callback === 'function') {
|
||||
callback(data.result);
|
||||
return;
|
||||
};
|
||||
pwgToaster({ text: data.result, icon: 'success' });
|
||||
} else if (data.stat == 'fail') {
|
||||
pwgToaster({ text: data.message, icon: 'error' });
|
||||
} else {
|
||||
pwgToaster({ text: 'Error try later...', icon: 'error' });
|
||||
pwgToaster({ text: str_handle_error, icon: 'error' });
|
||||
}
|
||||
if (typeof callback === 'function') {
|
||||
errCallback(data);
|
||||
return;
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
pwgToaster({ text: e.responseJSON?.message ?? 'Server Internal Error try later...', icon: 'error' });
|
||||
pwgToaster({ text: e.responseJSON?.message ?? str_handle_error, icon: 'error' });
|
||||
if (typeof callback === 'function') {
|
||||
errCallback(e);
|
||||
return;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getAllApiKeys(reset = false) {
|
||||
$.ajax({
|
||||
url: 'ws.php?format=json&method=pwg.users.api_key.get',
|
||||
type: "POST",
|
||||
dataType: 'json',
|
||||
data: {
|
||||
pwg_token: PWG_TOKEN
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.stat == 'ok') {
|
||||
if (typeof res.result === 'string') {
|
||||
// No keys
|
||||
} else {
|
||||
AddApiLine(res.result, reset);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
pwgToaster({ text: e.responseJSON?.message ?? str_handle_error + 'getAllApiKeys', icon: 'error' });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function AddApiLine(lines, reset) {
|
||||
const api_list = $('#api_key_list');
|
||||
const api_list_expired = $('#api_key_list_expired');
|
||||
|
||||
$('#api_key_list .api-tab-line:not(.template-api), #api_key_list .api-tab-collapse:not(.template-api)').remove();
|
||||
$('#api_key_list_expired .api-tab-line:not(.template-api), #api_key_list_expired .api-tab-collapse:not(.template-api)').remove();
|
||||
|
||||
lines.forEach((line, i) => {
|
||||
const api_line = $('#api_line').clone();
|
||||
const api_collapse = $('#api_collapse').clone();
|
||||
const tmp_id = line.auth_key.slice(24, 34);
|
||||
|
||||
api_line.removeClass('template-api').addClass('api-tab');
|
||||
api_line.attr('id', `api_${tmp_id}`);
|
||||
api_line.find('.icon-collapse').data('api', tmp_id);
|
||||
api_line.find('.api_name').text(line.apikey_name).attr('title', line.apikey_name);
|
||||
api_line.find('.api_creation').text(line.created_on_format);
|
||||
api_line.find('.api_last_use').text(line.last_used_on_since).attr('title', line.last_used_on_since);
|
||||
api_line.find('.api_expiration').text(line.expiration);
|
||||
api_line.find('.api-icon-action').attr('data-api', `api_${tmp_id}`);
|
||||
api_line.find('.api-icon-action').attr('data-pkid', line.auth_key);
|
||||
|
||||
api_collapse.attr('id', `api_collapse_${tmp_id}`);
|
||||
api_collapse.removeClass('template-api');
|
||||
api_collapse.find('.api_key').text(line.auth_key);
|
||||
api_collapse.find('.icon-clone').attr({
|
||||
'data-copy': line.auth_key,
|
||||
'data-success': `api_copy_success_${tmp_id}`
|
||||
});
|
||||
api_collapse.find('.api-copy').attr('id', `api_copy_success_${tmp_id}`);
|
||||
|
||||
if (!line.revoked_on && !line.is_expired) {
|
||||
api_list.append(api_line);
|
||||
api_line.after(api_collapse);
|
||||
} else {
|
||||
api_list_expired.append(api_line);
|
||||
api_line.after(api_collapse);
|
||||
api_line.find('.api-icon-action').remove();
|
||||
if (line.is_expired) {
|
||||
api_line.find('.api_expiration').html(`<i class="gallery-icon-skull api-skull"></i> <span data-tooltip="${line.expired_on_format}">${line.expired_on_since}</span>`);
|
||||
} else {
|
||||
api_line.find('.api_expiration').html(`<i class="gallery-icon-skull api-skull"></i> <span>${/\d/.test(line.revoked_on_since) ? line.revoked_on_since : no_time_elapsed}</span> <i data-tooltip="${line.revoked_on_message}" class="icon-info-circled-1 api-info"></i>`);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
apiLineEvent();
|
||||
if (reset) {
|
||||
resetSection('apikey-display');
|
||||
}
|
||||
}
|
||||
|
||||
function apiLineEvent() {
|
||||
$('.icon-collapse').off('click').on('click', function() {
|
||||
const api_collapse = $(`#api_collapse_${$(this).data('api')}`);
|
||||
const api_line = $(`#api_${$(this).data('api')}`);
|
||||
|
||||
if (api_collapse.is(':visible')) {
|
||||
api_collapse.removeClass('open');
|
||||
api_line.removeClass('open');
|
||||
api_line.find('.icon-collapse').addClass('close');
|
||||
api_collapse.css('display', 'none');
|
||||
api_collapse.find('.api-copy').addClass('api-hide');
|
||||
} else {
|
||||
api_collapse.addClass('open');
|
||||
api_line.addClass('open');
|
||||
api_line.find('.icon-collapse').removeClass('close');
|
||||
api_collapse.css('display', 'grid');
|
||||
}
|
||||
|
||||
resetSection('apikey-display', false, true);
|
||||
});
|
||||
|
||||
$('.api-tab-collapse .icon-clone').off('click').on('click', function() {
|
||||
const data_to_copy = $(this).data('copy');
|
||||
const selector = $(this).data('success');
|
||||
copyToClipboard(data_to_copy, str_copy_key_id, `#${selector}`);
|
||||
});
|
||||
|
||||
$('.api-tab-line .edit-mode').off('click').on('click', function() {
|
||||
const selector = $(this).parent().data('api');
|
||||
openApiEditModal(`#${selector}`);
|
||||
});
|
||||
|
||||
$('.api-tab-line .delete-mode').off('click').on('click', function() {
|
||||
const selector = $(this).parent().data('api');
|
||||
openApiRevokeModal(`#${selector}`);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function resetSection(selector, scroll = true, maxContent = false) {
|
||||
const el = $(`#${selector}`);
|
||||
const element = el.get(0);
|
||||
const scrollH = maxContent ? 'max-content' : element.scrollHeight + 'px';
|
||||
element.style.maxHeight = scrollH;
|
||||
|
||||
if ('account-display' !== selector && scroll) {
|
||||
setTimeout(() => {
|
||||
const el = $(`#${selector.split('-')[0]}-section`).get(0);
|
||||
el.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
function openApiModal() {
|
||||
$('#api_modal').fadeIn();
|
||||
$('#api_key_name').trigger('focus');
|
||||
saveApiKeyEvent();
|
||||
}
|
||||
|
||||
function closeApiModal() {
|
||||
$('#api_modal').fadeOut(() => {
|
||||
$('#api_key_name').val('');
|
||||
$('select[name="api_expiration"]').val(selected_date).trigger('change');
|
||||
$('#api_expiration_date').val('');
|
||||
|
||||
$('#api_secret_key').val('');
|
||||
$('#retrieves_keyapi').hide();
|
||||
$('#generate_keyapi').show();
|
||||
$('#done_apikey').attr('disabled', true);
|
||||
$('#api_key_copy_success, #api_id_copy_success').addClass('api-hide');
|
||||
});
|
||||
unbindApiKeyEvents();
|
||||
}
|
||||
|
||||
function successApiModal(secret, id) {
|
||||
$('#api_secret_key').val(secret);
|
||||
$('#api_id_key').val(id);
|
||||
|
||||
$('#generate_keyapi').hide();
|
||||
$('#retrieves_keyapi').fadeIn();
|
||||
|
||||
$('#api_secret_copy').off('click').on('click', function() {
|
||||
const copy = copyToClipboard(secret, str_copy_key_secret, '#api_key_copy_success');
|
||||
|
||||
$('#done_apikey').removeAttr('disabled');
|
||||
$('#done_apikey').on('click', closeApiModal);
|
||||
});
|
||||
|
||||
$('#api_id_copy').off('click').on('click', function() {
|
||||
const copy = copyToClipboard(id, str_copy_key_id, '#api_id_copy_success');
|
||||
});
|
||||
}
|
||||
|
||||
//api edit modal
|
||||
function openApiEditModal(selector) {
|
||||
const value = $(selector).find('.api_name').text();
|
||||
const pkid = $(selector).find('.api-icon-action').data('pkid');
|
||||
$('#api_key_edit').val(value);
|
||||
$('#api_modal_edit').fadeIn();
|
||||
$('#api_key_edit').trigger('focus');
|
||||
saveApiEditEvents(pkid);
|
||||
}
|
||||
|
||||
function closeApiEditModal() {
|
||||
$('#api_modal_edit').fadeOut(() => {
|
||||
$('#api_key_edit').val('');
|
||||
unbindApiEditEvents();
|
||||
});
|
||||
}
|
||||
|
||||
function saveApiEditEvents(pkid) {
|
||||
$('#save_api_edit').on('click', function() {
|
||||
const value = $('#api_key_edit').val();
|
||||
|
||||
if ('' == value) {
|
||||
$('#error_api_key_edit').show();
|
||||
return;
|
||||
}
|
||||
setInfos(
|
||||
{
|
||||
pkid,
|
||||
key_name: value,
|
||||
},
|
||||
'pwg.users.api_key.edit',
|
||||
(res) => {
|
||||
pwgToaster({ text: str_api_edited, icon: 'success' });
|
||||
getAllApiKeys(true);
|
||||
closeApiEditModal();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function unbindApiEditEvents() {
|
||||
$('#save_api_edit').off('click');
|
||||
}
|
||||
|
||||
// api revoke modal
|
||||
function openApiRevokeModal(selector) {
|
||||
const apiName = $(selector).find('.api_name').text();
|
||||
const pkid = $(selector).find('.api-icon-action').data('pkid');
|
||||
const text = sprintf(str_revoke_key, apiName);
|
||||
$('#api_modal_revoke_title').text(text);
|
||||
|
||||
$('#api_modal_revoke').fadeIn();
|
||||
saveApiRevokeEvents(pkid);
|
||||
}
|
||||
|
||||
function closeApiRevokeModal() {
|
||||
$('#api_modal_revoke').fadeOut(() => {
|
||||
$('#api_modal_revoke_title').text('');
|
||||
unbindApiRevokeEvents();
|
||||
});
|
||||
}
|
||||
|
||||
function saveApiRevokeEvents(pkid) {
|
||||
$('#revoke_api_key').on('click', function() {
|
||||
setInfos(
|
||||
{
|
||||
pkid,
|
||||
},
|
||||
'pwg.users.api_key.revoke',
|
||||
(res) => {
|
||||
pwgToaster({ text: str_api_revoked, icon: 'success' });
|
||||
getAllApiKeys(true);
|
||||
closeApiRevokeModal();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function unbindApiRevokeEvents() {
|
||||
$('#revoke_api_key').off('click');
|
||||
}
|
||||
|
||||
function copyToClipboard(copy, message, selector = null) {
|
||||
if (window.isSecureContext && navigator.clipboard) {
|
||||
navigator.clipboard.writeText(copy);
|
||||
if (selector) {
|
||||
$(selector).removeClass('api-hide');
|
||||
// auto hide
|
||||
// setTimeout(() => {
|
||||
// $(selector).addClass('api-hide');
|
||||
// }, 1000);
|
||||
} else {
|
||||
pwgToaster({ text: message, icon: 'success' });
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
pwgToaster({ text: str_cant_copy, icon: 'error' });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function saveApiKeyEvent() {
|
||||
const handler = () => {
|
||||
const api_name = $('#api_key_name').val();
|
||||
let api_duration = $('select[name="api_expiration"]').val();
|
||||
|
||||
if (api_name == '') {
|
||||
$('#error_api_key_name').show();
|
||||
return;
|
||||
}
|
||||
|
||||
if ('custom' === api_duration && !$('#api_expiration_date').val()) {
|
||||
$('#error_api_key_date').show();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
unbindApiKeyEvents();
|
||||
|
||||
if ('custom' === api_duration) {
|
||||
const today = new Date();
|
||||
const custom_date = new Date($('#api_expiration_date').val());
|
||||
const one_day = 1000 * 60 * 60 * 24;
|
||||
const days = Math.ceil((custom_date.getTime() - today.getTime() ) / (one_day));
|
||||
api_duration = days;
|
||||
} else {
|
||||
api_duration = Number(api_duration) ?? 1;
|
||||
}
|
||||
|
||||
setInfos(
|
||||
{
|
||||
key_name: api_name,
|
||||
duration: api_duration
|
||||
},
|
||||
'pwg.users.api_key.create',
|
||||
(res) => {
|
||||
pwgToaster({ text: str_api_added, icon: 'success' });
|
||||
getAllApiKeys(true);
|
||||
successApiModal(res.apikey_secret, res.auth_key);
|
||||
},
|
||||
(err) => {
|
||||
saveApiKeyEvent();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$('#save_apikey').on('click.apikey', handler);
|
||||
$(window).on('keydown.apikey', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
handler();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function unbindApiKeyEvents() {
|
||||
$('#api_modal').find('*').addBack().off('.apikey');
|
||||
$(window).off('.apikey');
|
||||
}
|
||||
|
||||
@@ -3,21 +3,39 @@
|
||||
{combine_css path="admin/themes/default/fontello/css/fontello.css" order=-11}
|
||||
|
||||
<script>
|
||||
var selected_language = `{$language_options[$current_language]}`;
|
||||
var selected_language = `{$language_options[$current_language]}`;
|
||||
var url_logo_light = `{$ROOT_URL}themes/standard_pages/images/piwigo_logo.svg`;
|
||||
var url_logo_dark = `{$ROOT_URL}themes/standard_pages/images/piwigo_logo_dark.svg`;
|
||||
</script>
|
||||
{combine_script id='standard_pages_js' load='async' require='jquery' path='themes/standard_pages/js/standard_pages.js'}
|
||||
{combine_script id='standard_profile_js' load='async' require='jquery' path='themes/standard_pages/js/profile.js'}
|
||||
{combine_script id='common' load='footer' require='jquery' path='admin/themes/default/js/common.js'}
|
||||
{footer_script}
|
||||
const standardSaveSelector = [];
|
||||
const preferencesDefaultValues = {
|
||||
nb_image_page: {$DEFAULT_USER_VALUES['nb_image_page']},
|
||||
recent_period: {$DEFAULT_USER_VALUES['recent_period']},
|
||||
opt_album: {$DEFAULT_USER_VALUES['expand']},
|
||||
opt_comment: {$DEFAULT_USER_VALUES['show_nb_comments']},
|
||||
opt_hits: {$DEFAULT_USER_VALUES['show_nb_hits']},
|
||||
nb_image_page: {$DEFAULT_USER_VALUES['nb_image_page']},
|
||||
recent_period: {$DEFAULT_USER_VALUES['recent_period']},
|
||||
opt_album: {$DEFAULT_USER_VALUES['expand']},
|
||||
opt_comment: {$DEFAULT_USER_VALUES['show_nb_comments']},
|
||||
opt_hits: {$DEFAULT_USER_VALUES['show_nb_hits']},
|
||||
};
|
||||
const selected_date = "{$API_SELECTED_EXPIRATION}";
|
||||
const can_manage_api = {($API_CAN_MANAGE) ? "true" : "false"};
|
||||
|
||||
const str_copy_key_id = "{"Public key copied."|translate|escape:javascript}";
|
||||
const str_copy_key_secret = "{"Secret key copied. Keep it in a safe place."|translate|escape:javascript}";
|
||||
const str_cant_copy = "{"Impossible to copy automatically. Please copy manually."|translate|escape:javascript}";
|
||||
const str_api_added = "{"The api key has been successfully created."|translate|escape:javascript}";
|
||||
const str_revoked = "{"Revoked"|translate|escape:javascript}";
|
||||
const str_show_expired = "{"Show expired keys"|translate|escape:javascript}";
|
||||
const str_hide_expired = "{"Hide expired keys"|translate|escape:javascript}";
|
||||
const str_handle_error = "{"An error has occured"|translate|escape:javascript}";
|
||||
const str_expires_in = "{"Expires in"|translate|escape:javascript}";
|
||||
const str_expires_on = "{"Expired on"|translate|escape:javascript}";
|
||||
const str_revoke_key = "{'Do you really want to revoke the "%s" API key?'|translate|escape:javascript}";
|
||||
const str_api_revoked = "{"API Key has been successfully revoked."|translate|escape:javascript}";
|
||||
const str_api_edited = "{"API Key has been successfully edited."|translate|escape:javascript}";
|
||||
const no_time_elapsed = "{"right now"|translate|escape:javascript}";
|
||||
{/footer_script}
|
||||
|
||||
<container id="mode" class="light">
|
||||
@@ -28,7 +46,6 @@ const preferencesDefaultValues = {
|
||||
</div>
|
||||
<div>
|
||||
<a href="{$HELP_LINK}" target="_blank">{'Help'|translate}</a>
|
||||
{include file='toaster.tpl'}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -49,7 +66,7 @@ const preferencesDefaultValues = {
|
||||
</div>
|
||||
<div class="form" id="account-display">
|
||||
<div class="column-flex first">
|
||||
<label for="username">{'Username'|translate}</label>
|
||||
<label>{'Username'|translate}</label>
|
||||
<div class="row-flex input-container username">
|
||||
<i class="gallery-icon-user"></i>
|
||||
<p>{$USERNAME}</p>
|
||||
@@ -57,9 +74,9 @@ const preferencesDefaultValues = {
|
||||
</div>
|
||||
</div>
|
||||
<div class="column-flex">
|
||||
<label for="mail_address">{'Email address'|translate}</label>
|
||||
<label for="email">{'Email address'|translate}</label>
|
||||
<div class="row-flex input-container">
|
||||
<i class="gallery-icon-user"></i>
|
||||
<i class="icon-mail-alt"></i>
|
||||
<input type="email" name="mail_address" id="email" value="{$EMAIL}" />
|
||||
</div>
|
||||
<p id="email_error" class="error-message"><i class="gallery-icon-attention-circled"></i>
|
||||
@@ -94,7 +111,7 @@ const preferencesDefaultValues = {
|
||||
</div>
|
||||
|
||||
<div class="column-flex">
|
||||
<label for="theme">{'Theme'|translate}</label>
|
||||
<label>{'Theme'|translate}</label>
|
||||
<div class="row-flex input-container">
|
||||
<i class="icon-brush"></i>
|
||||
{html_options name=theme options=$template_options selected=$template_selection}
|
||||
@@ -103,7 +120,7 @@ const preferencesDefaultValues = {
|
||||
</div>
|
||||
|
||||
<div class="column-flex">
|
||||
<label for="language">{'Language'|translate}</label>
|
||||
<label>{'Language'|translate}</label>
|
||||
<div class="row-flex input-container">
|
||||
<i class="icon-language"></i>
|
||||
{html_options name=language options=$language_options selected=$language_selection}
|
||||
@@ -212,6 +229,205 @@ const preferencesDefaultValues = {
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{* API KEY *}
|
||||
<section id="apikey-section" class="profile-section">
|
||||
<div class="title">
|
||||
<div class="column-flex">
|
||||
<h1>{'API Keys'|translate}</h1>
|
||||
<p>{'Create API Keys to secure your acount'|translate}</p>
|
||||
</div>
|
||||
<i class="gallery-icon-up-open display-btn close" data-display="apikey-display"></i>
|
||||
</div>
|
||||
|
||||
<div class="form" id="apikey-display">
|
||||
<div class="api-cant-manage" id="cant_manage_api">
|
||||
<p>{'To manage your API keys, please log in with your username/password.'|translate|escape:html}</p>
|
||||
</div>
|
||||
|
||||
<div class="new-apikey can-manage">
|
||||
<button class="btn btn-main" id="new_apikey">{'New API Key'|translate}</button>
|
||||
</div>
|
||||
<div class="api-list can-manage">
|
||||
<div class="api-list-head api-tab">
|
||||
<div aria-hidden="true"></div>
|
||||
<p>{'API Key name'|translate}</p>
|
||||
<p>{'Created at'|translate}</p>
|
||||
<p>{'Last use'|translate}</p>
|
||||
<p id="api_expires_in">{'Expires in'|translate}</p>
|
||||
<div aria-hidden="true"></div>
|
||||
</div>
|
||||
<div class="api-list-body" id="api_key_list">
|
||||
|
||||
<div class="api-tab-line border-line template-api" id="api_line">
|
||||
<div class="api-icon-collapse">
|
||||
<i class="gallery-icon-up-open icon-collapse close" data-api=""></i>
|
||||
</div>
|
||||
<p class="api_name"></p>
|
||||
<p class="api_creation"></p>
|
||||
<p class="api_last_use"></p>
|
||||
<p class="api_expiration"></p>
|
||||
<div class="api-icon-action row-flex" data-api="" data-pkid="">
|
||||
<i class="icon-pencil edit-mode"></i>
|
||||
<i class="icon-trash-1 delete-mode"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="api-tab-collapse border-line template-api" style="display: none;" id="api_collapse">
|
||||
<div aria-hidden="true"></div>
|
||||
<div class="keys">
|
||||
<div class="row-flex key">
|
||||
<i class="gallery-icon-hash"></i>
|
||||
<p class="api_key"></p>
|
||||
<i class="icon-clone" data-copy="" data-success=""></i>
|
||||
<p id="" class="api-copy api-hide success-message">{"Public key copied."|translate|escape:html}</p>
|
||||
</div>
|
||||
<div class="row-flex key">
|
||||
<i class="icon-key"></i>
|
||||
<p>{"The secret key can no longer be displayed."|translate}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="new-apikey">
|
||||
<button class="btn btn-link" id="show_expired_list" data-show="false">{'Show expired keys'|translate}</button>
|
||||
</div>
|
||||
<div class="api-list-body" id="api_key_list_expired">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{* API KEY MODAL *}
|
||||
<div class="bg-modal" id="api_modal">
|
||||
<div class="body-modal">
|
||||
<a class="icon-cancel close-modal" id="close_api_modal"></a>
|
||||
|
||||
<div id="generate_keyapi">
|
||||
<div class="head-modal">
|
||||
<p class="title-modal">{'Generate API Key'|translate}</p>
|
||||
<p class="subtitle-modal">{'Create a new API key to secure your account.'|translate}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="column-flex first">
|
||||
<label for="api_key_name">{'API Key name'|translate}</label>
|
||||
<div class="row-flex input-container">
|
||||
<i class="icon-key"></i>
|
||||
<input type="text" id="api_key_name" />
|
||||
</div>
|
||||
<p id="error_api_key_name" class="error-message"><i class="gallery-icon-attention-circled"></i>
|
||||
{'must not be empty'|translate}</p>
|
||||
</div>
|
||||
|
||||
<div class="row-flex section-expiration">
|
||||
<div class="column-flex">
|
||||
<label>{'Duration'|translate}</label>
|
||||
<div class="row-flex input-container api-expiration">
|
||||
<i class="gallery-icon-calendar"></i>
|
||||
{html_options name=api_expiration options=$API_EXPIRATION}
|
||||
</div>
|
||||
<p id="error_api_key_date" class="error-message"><i class="gallery-icon-attention-circled"></i>
|
||||
{'you must choose a date'|translate}</p>
|
||||
</div>
|
||||
|
||||
<div class="column-flex" id="api_custom_date">
|
||||
<label for="api_expiration_date">{'Custom date'|translate}</label>
|
||||
<div class="row-flex input-container api-expiration">
|
||||
<input type="date" id="api_expiration_date" name="api_expiration_custom" min="{$API_CURRENT_DATE}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="api-mail-infos">{$API_EMAIL_INFOS}</p>
|
||||
|
||||
<div class="save">
|
||||
<button class="btn btn-cancel" id="cancel_apikey">{'Cancel'|translate}</button>
|
||||
<button class="btn btn-main" id="save_apikey">{'Generate key'|translate}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="retrieves_keyapi">
|
||||
<div class="head-modal">
|
||||
<p class="title-modal">{'Generate API Key'|translate}</p>
|
||||
<p class="subtitle-modal">{'Save your secret Key and ID'|translate}</p>
|
||||
<p class="modal-secret">{'This will not be displayed again. You must copy it to continue.'|translate}
|
||||
<p>
|
||||
</div>
|
||||
|
||||
<div class="modal-input-keys">
|
||||
<p id="api_id_copy_success" class="api-copy api-hide success-message">
|
||||
{"Public key copied."|translate|escape:html}</p>
|
||||
</div>
|
||||
<div class="input-modal input-modal-id row-flex">
|
||||
<i class="gallery-icon-hash"></i>
|
||||
<input type="text" id="api_id_key" />
|
||||
<i class="icon-clone" id="api_id_copy"></i>
|
||||
</div>
|
||||
|
||||
<div class="modal-input-keys">
|
||||
<p id="api_key_copy_success" class="modal-input-key api-copy api-hide success-message">
|
||||
{"Secret key copied. Keep it in a safe place."|translate|escape:html}</p>
|
||||
</div>
|
||||
<div class="input-modal input-modal-key row-flex">
|
||||
<i class="icon-key"></i>
|
||||
<input type="text" id="api_secret_key" />
|
||||
<i class="icon-clone" id="api_secret_copy"></i>
|
||||
</div>
|
||||
|
||||
<div class="save">
|
||||
<button class="btn btn-main" id="done_apikey" disabled>{'Done'|translate}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{* API KEY MODAL EDIT *}
|
||||
<div class="bg-modal" id="api_modal_edit">
|
||||
<div class="body-modal">
|
||||
<a class="icon-cancel close-modal" id="close_api_modal_edit"></a>
|
||||
|
||||
<div>
|
||||
<div class="head-modal">
|
||||
<p class="title-modal">{'Edit API Key'|translate}</p>
|
||||
</div>
|
||||
|
||||
<div class="column-flex first">
|
||||
<label for="api_key_edit">{'API Key name'|translate}</label>
|
||||
<div class="row-flex input-container">
|
||||
<i class="icon-key"></i>
|
||||
<input type="text" id="api_key_edit" />
|
||||
</div>
|
||||
<p id="error_api_key_edit" class="error-message"><i class="gallery-icon-attention-circled"></i>
|
||||
{'must not be empty'|translate}</p>
|
||||
</div>
|
||||
|
||||
<div class="save">
|
||||
<button class="btn btn-main" id="save_api_edit">{'Save'|translate}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{* API KEY MODAL REVOKE *}
|
||||
<div class="bg-modal" id="api_modal_revoke">
|
||||
<div class="body-modal">
|
||||
<a class="icon-cancel close-modal" id="close_api_modal_revoke"></a>
|
||||
|
||||
<div>
|
||||
<div class="head-modal">
|
||||
<p class="title-modal" id="api_modal_revoke_title"></p>
|
||||
</div>
|
||||
|
||||
<div class="save">
|
||||
<button class="btn btn-cancel" id="cancel_api_revoke">{'Cancel'|translate}</button>
|
||||
<button class="btn btn-main btn-revoked" id="revoke_api_key">{'Revoke'|translate}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{if isset($PLUGINS_PROFILE)}
|
||||
{foreach from=$PLUGINS_PROFILE item=plugin_block key=k_block}
|
||||
<section id="{$k_block}-section" class="profile-section">
|
||||
@@ -225,12 +441,12 @@ const preferencesDefaultValues = {
|
||||
<div class="form plugins" id="{$k_block}-display">
|
||||
{include file=$plugin_block.template}
|
||||
{if $plugin_block.standard_show_save}
|
||||
<div class="save">
|
||||
<button class="btn btn-main" id="save_{$k_block}">{'Submit'|translate}</button>
|
||||
</div>
|
||||
{footer_script}
|
||||
<div class="save">
|
||||
<button class="btn btn-main" id="save_{$k_block}">{'Submit'|translate}</button>
|
||||
</div>
|
||||
{footer_script}
|
||||
standardSaveSelector.push('#save_{$k_block}');
|
||||
{/footer_script}
|
||||
{/footer_script}
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
@@ -252,4 +468,5 @@ const preferencesDefaultValues = {
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
{include file='toaster.tpl'}
|
||||
</container>
|
||||
@@ -5,13 +5,14 @@
|
||||
}
|
||||
|
||||
.toaster {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
right: 15px;
|
||||
max-width: 300px;
|
||||
top: 40px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.toast {
|
||||
@@ -29,14 +30,24 @@
|
||||
font-size: 33px;
|
||||
}
|
||||
|
||||
.toast.success {
|
||||
background-color:#4CA530;
|
||||
color:#D6FFCF;
|
||||
.light .toast.success {
|
||||
background-color: #D6FFCF;
|
||||
color: #4CA530;
|
||||
}
|
||||
|
||||
.toast.error {
|
||||
background-color:#BE4949;
|
||||
color:#FFC8C8;
|
||||
.light .toast.error {
|
||||
background-color: #F8D7DC;
|
||||
color: #EB3D33;
|
||||
}
|
||||
|
||||
.dark .toast.success {
|
||||
background-color: #4EA590;
|
||||
color: #AAF6E4;
|
||||
}
|
||||
|
||||
.dark .toast.error {
|
||||
background-color: #BE4949;
|
||||
color: #FFC8C8;
|
||||
}
|
||||
{/html_style}
|
||||
<div class="toaster" id="pwg_toaster">
|
||||
|
||||
+403
-25
@@ -9,10 +9,18 @@ html{
|
||||
|
||||
#theHeader,
|
||||
#copyright,
|
||||
.template-section{
|
||||
#api_custom_date,
|
||||
#retrieves_keyapi,
|
||||
.template-section,
|
||||
.template-api,
|
||||
.api_name_edit {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.api-hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#theIdentificationPage,
|
||||
#theRegisterPage,
|
||||
#thePasswordPage,
|
||||
@@ -95,7 +103,8 @@ h1 i{
|
||||
bottom:0;
|
||||
}
|
||||
|
||||
.input-container{
|
||||
.input-container,
|
||||
.input-modal {
|
||||
border-radius:3px;
|
||||
padding:5px 15px;
|
||||
margin-bottom:25px;
|
||||
@@ -103,6 +112,7 @@ h1 i{
|
||||
}
|
||||
|
||||
.input-container input,
|
||||
.input-modal input,
|
||||
.input-container select,
|
||||
.input-container textarea{
|
||||
background-color:transparent;
|
||||
@@ -129,6 +139,8 @@ input[type='radio'] {
|
||||
}
|
||||
|
||||
.input-container input:focus,
|
||||
.input-modal input:focus,
|
||||
.profile-section .api-tab-line.edit input:focus,
|
||||
.input-container select:focus,
|
||||
.input-container textarea:focus{
|
||||
border:none;
|
||||
@@ -139,11 +151,13 @@ select {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.input-container:focus-within{
|
||||
.input-container:focus-within,
|
||||
.input-modal:focus-within{
|
||||
border:1px solid #ff7700!important;
|
||||
}
|
||||
|
||||
.input-container i {
|
||||
.input-container i,
|
||||
.input-modal i {
|
||||
font-size:15px;
|
||||
margin-right:5px;
|
||||
}
|
||||
@@ -226,11 +240,36 @@ p.form-instructions{
|
||||
color: #3C3C3C!important;
|
||||
}
|
||||
|
||||
.btn-cancel,
|
||||
.btn-link {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
height: fit-content;
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
text-decoration: underline;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
a.btn-main{
|
||||
display:block;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.btn-main:disabled {
|
||||
background-color:#aaaaaa!important;
|
||||
color: #3C3C3C !important;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
#return-to-gallery{
|
||||
margin: 30px auto;
|
||||
display:block;
|
||||
@@ -352,14 +391,19 @@ a.btn-main{
|
||||
.error-message{
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
bottom: 5px;
|
||||
left:0;
|
||||
margin: 0;
|
||||
display:none;
|
||||
}
|
||||
|
||||
#error_api_key_date.error-message {
|
||||
bottom: -20px;
|
||||
}
|
||||
|
||||
.error-message i,
|
||||
p.error-message{
|
||||
p.error-message,
|
||||
.modal-secret {
|
||||
color: #EB3223!important;
|
||||
}
|
||||
|
||||
@@ -417,7 +461,7 @@ p.error-message{
|
||||
margin-top: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.2s ease;
|
||||
transition: max-height 0.6s ease;
|
||||
}
|
||||
|
||||
.profile-section .form.open {
|
||||
@@ -430,13 +474,22 @@ p.error-message{
|
||||
/* gap: 15px; */
|
||||
}
|
||||
|
||||
.profile-section .save {
|
||||
.profile-section .save,
|
||||
.profile-section .new-apikey,
|
||||
.profile-section .modal-input-keys {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.profile-section .modal-input-keys {
|
||||
position: absolute;
|
||||
right: 30px;
|
||||
}
|
||||
|
||||
.profile-section .save .btn-main,
|
||||
.profile-section .new-apikey .btn-main,
|
||||
.profile-section .reset .btn-main {
|
||||
padding: 10px 35px;
|
||||
}
|
||||
@@ -445,7 +498,10 @@ p.error-message{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.gallery-icon-up-open {
|
||||
.gallery-icon-up-open:not(
|
||||
.api-list .gallery-icon-up-open,
|
||||
#api_key_list_expired .gallery-icon-up-open
|
||||
) {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
cursor: pointer;
|
||||
@@ -453,10 +509,23 @@ p.error-message{
|
||||
transition: transform 0.5s ease;
|
||||
}
|
||||
|
||||
.gallery-icon-up-open.close {
|
||||
.gallery-icon-up-open.close,
|
||||
.profile-section .icon-collapse.close {
|
||||
position: relative;
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.profile-section .api-icon-collapse .icon-collapse.close {
|
||||
top: 2px;
|
||||
left: -0.2px;
|
||||
}
|
||||
|
||||
.profile-section .icon-collapse {
|
||||
display: inline-block;
|
||||
transition: transform 0.4s;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.profile-section .username {
|
||||
width: fit-content;
|
||||
cursor: not-allowed;
|
||||
@@ -464,10 +533,17 @@ p.error-message{
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.profile-section .input-container.radio {
|
||||
.profile-section .input-container.radio,
|
||||
.profile-section .section-expiration,
|
||||
.profile-section .api-icon-action {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.profile-section .api-icon-action {
|
||||
padding-right: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.profile-section .input-container.radio label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -487,6 +563,227 @@ p.error-message{
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.profile-section .api-tab {
|
||||
display: grid;
|
||||
grid-template-columns: 60px 2fr 1fr 1fr 1fr 0.5fr;
|
||||
/* grid-template-columns: 60px 200px 100px 100px 100px 30px; */
|
||||
justify-items: start;
|
||||
align-items: center;
|
||||
max-height: 40px;
|
||||
}
|
||||
|
||||
.profile-section .api-list-head {
|
||||
padding: 15px 0;
|
||||
border-radius: 8px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.profile-section .api-expiration {
|
||||
width: fit-content;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.profile-section .api-mail-infos {
|
||||
position: relative;
|
||||
font-size: 12px;
|
||||
padding-top: 20px;
|
||||
margin-bottom: 25px;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.profile-section .api-icon-collapse {
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
.profile-section .api-icon-action i:hover,
|
||||
.close-modal:hover,
|
||||
.profile-section .icon-clone:hover {
|
||||
color: #ff7700;
|
||||
}
|
||||
|
||||
.profile-section .api-tab-line,
|
||||
.profile-section .api-tab-collapse {
|
||||
padding: 10px 0;
|
||||
border-radius: 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.profile-section .api-tab-line.open {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.profile-section .api-tab-collapse.open {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.profile-section .api-tab-line i:not(#api_key_list_expired, .api_expiration .api-skull),
|
||||
.profile-section .icon-clone {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.profile-section div.api-tab-line:nth-child(even) {
|
||||
background-color: #303030;
|
||||
}
|
||||
.profile-section .api-tab-collapse .key {
|
||||
gap: 10px;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.profile-section .api-tab-collapse {
|
||||
padding-bottom: 20px;
|
||||
display: grid;
|
||||
grid-template-columns: 60px auto;
|
||||
}
|
||||
|
||||
.profile-section .api_name,
|
||||
.profile-section .api_creation,
|
||||
.profile-section .api_expiration {
|
||||
text-overflow: ellipsis;
|
||||
max-width: 90%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.profile-section #api_key_list_expired .api_expiration {
|
||||
text-overflow: unset;
|
||||
max-width: unset;
|
||||
}
|
||||
|
||||
.profile-section #api_key_list .border-line {
|
||||
border: 1px solid transparent !important;
|
||||
}
|
||||
|
||||
.profile-section #api_key_list .edit {
|
||||
border: 1px solid #ff7700 !important;
|
||||
}
|
||||
|
||||
.profile-section .api-list-head > p{
|
||||
text-align: start !important;
|
||||
}
|
||||
|
||||
.profile-section .api_last_use {
|
||||
max-width: 98%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.profile-section .api_name_edit {
|
||||
width: max-content;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.profile-section .new-apikey .btn-link{
|
||||
color: #9A9A9A !important;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.profile-section .api-copy {
|
||||
padding: 1px 10px;
|
||||
width: fit-content;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.profile-section #show_expired_list {
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.profile-section #api_key_list_expired {
|
||||
max-height: 0;
|
||||
transition: max-height 0.3s ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.profile-section .api-info {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.profile-section .api_key
|
||||
.profile-section #api_id_key,
|
||||
.profile-section #api_secret_key {
|
||||
font-family: monospace !important;
|
||||
}
|
||||
|
||||
/* Modal */
|
||||
|
||||
.bg-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
}
|
||||
|
||||
.close-modal {
|
||||
position: absolute;
|
||||
right: -40px;
|
||||
top: -40px;
|
||||
font-size: 30px;
|
||||
text-decoration: none !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.body-modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
border-radius: 10px;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -48%);
|
||||
text-align: left;
|
||||
padding: 30px;
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#api_modal_revoke .body-modal {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.body-modal .btn-main {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.title-modal {
|
||||
font-size: 24px !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
.subtitle-modal {
|
||||
font-size: 16px !important;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.head-modal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
#generate_keyapi .head-modal,
|
||||
#api_modal_edit .head-modal,
|
||||
#api_modal_revoke .head-modal {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.input-modal-id {
|
||||
margin-top: 25px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.input-modal-key {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
/* The switch */
|
||||
.switch {
|
||||
position: relative;
|
||||
@@ -547,6 +844,20 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Tooltips */
|
||||
[data-tooltip]:hover::after {
|
||||
position: absolute;
|
||||
content: attr(data-tooltip);
|
||||
animation: fadeIn 100ms cubic-bezier(0.42, 0, 0.62, 1.32) forwards;
|
||||
animation-delay: 100ms;
|
||||
border-radius: 5px;
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
padding: 5px 10px;
|
||||
box-shadow: 0px 10px 33px #3333332e;
|
||||
}
|
||||
|
||||
/* Light */
|
||||
#theIdentificationPage .light,
|
||||
#theRegisterPage .light,
|
||||
@@ -560,16 +871,19 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
.light #password-form,
|
||||
.light #lang-select #other-languages,
|
||||
.light .profile-section,
|
||||
.light .slider:before {
|
||||
.light .slider:before,
|
||||
.light .body-modal,
|
||||
.light [data-tooltip]:hover::after {
|
||||
background-color:#ffffff;
|
||||
}
|
||||
|
||||
#theIdentificationPage .light a,
|
||||
#theRegisterPage .light a,
|
||||
#thePasswordPage .light a,
|
||||
#theProfilePage .light a,
|
||||
#theProfilePage .light a:not(.close-modal),
|
||||
.light h1,
|
||||
.light .input-container input,
|
||||
.light .input-modal input,
|
||||
.light .input-container select,
|
||||
.light .input-container textarea,
|
||||
.light .secondary-links,
|
||||
@@ -579,7 +893,9 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
.light .profile-section i,
|
||||
.light #password-form p,
|
||||
.light .profile-section p,
|
||||
.light #lang-select #other-languages span{
|
||||
.light #lang-select #other-languages span,
|
||||
.light .btn-cancel,
|
||||
.light .btn-link {
|
||||
color:#3C3C3C;
|
||||
}
|
||||
|
||||
@@ -596,7 +912,9 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
color:#ff7700;
|
||||
}
|
||||
|
||||
.light .input-container{
|
||||
.light .input-container,
|
||||
.light .input-modal,
|
||||
.light .api-list-head {
|
||||
background-color:#F0F0F0;
|
||||
border:1px solid #F0F0F0;
|
||||
}
|
||||
@@ -619,7 +937,7 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
|
||||
.light .success-message{
|
||||
background-color: #DBF6D7;
|
||||
color: #6DCE5E;
|
||||
color: #6DCE5E !important;
|
||||
border-left: 4px solid #6DCE5E;
|
||||
}
|
||||
|
||||
@@ -635,6 +953,35 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
background-color: #CCCCCC;
|
||||
}
|
||||
|
||||
.light .api-list-body > div:nth-child(4n+1),
|
||||
.light .api-list-body > div:nth-child(4n+2) {
|
||||
background-color: #F8F8F8;
|
||||
}
|
||||
|
||||
.light .api-tab-line p,
|
||||
.light .api-icon-action i,
|
||||
.light .keys p:not(.api-copy),
|
||||
.light .keys i,
|
||||
.light #api_key_list_expired .api-skull {
|
||||
color: #656565;
|
||||
}
|
||||
|
||||
.light .close-modal {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.light input[type="date"] {
|
||||
color-scheme: light;
|
||||
}
|
||||
|
||||
.light input[type="date"]::-webkit-calendar-picker-indicator {
|
||||
filter: invert(0);
|
||||
}
|
||||
|
||||
.light .btn-revoked {
|
||||
background-color: #EB3223 !important;
|
||||
}
|
||||
|
||||
/* Dark */
|
||||
#theIdentificationPage .dark,
|
||||
#theRegisterPage .dark,
|
||||
@@ -646,16 +993,18 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
.dark #login-form,
|
||||
.dark #register-form,
|
||||
.dark #password-form,
|
||||
.dark .profile-section{
|
||||
.dark .profile-section,
|
||||
.dark .body-modal {
|
||||
background-color:#3C3C3C;
|
||||
}
|
||||
|
||||
#theIdentificationPage .dark a,
|
||||
#theRegisterPage .dark a,
|
||||
#thePasswordPage .dark a,
|
||||
#theProfilePage .dark a,
|
||||
#theProfilePage .dark a:not(.close-modal),
|
||||
.dark h1,
|
||||
.dark .input-container input,
|
||||
.dark .input-modal input,
|
||||
.dark .input-container select,
|
||||
.dark .input-container textarea,
|
||||
.dark .secondary-links,
|
||||
@@ -665,7 +1014,9 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
.dark .profile-section i,
|
||||
.dark #password-form p,
|
||||
.dark .profile-section p,
|
||||
.dark #lang-select #other-languages span{
|
||||
.dark #lang-select #other-languages span,
|
||||
.dark .btn-cancel,
|
||||
.dark .btn-link {
|
||||
color:#D6D6D6;
|
||||
}
|
||||
|
||||
@@ -683,7 +1034,8 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
color:#FFEBD0;
|
||||
}
|
||||
|
||||
.dark .input-container{
|
||||
.dark .input-container,
|
||||
.dark .input-modal {
|
||||
background-color:#303030;
|
||||
border:1px solid #303030;
|
||||
}
|
||||
@@ -712,7 +1064,7 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
|
||||
.dark .success-message{
|
||||
background-color: #4EA590;
|
||||
color: #AAF6E4;
|
||||
color: #AAF6E4 !important;
|
||||
border-left: 4px solid #AAF6E4;
|
||||
}
|
||||
|
||||
@@ -725,14 +1077,40 @@ input:checked + .slider:before, input:checked + .slider::after {
|
||||
background-color: #FFA646;
|
||||
}
|
||||
|
||||
.dark input:focus + .slider {
|
||||
box-shadow: 0 0 1px #FFA646;
|
||||
}
|
||||
|
||||
.dark .slider:before {
|
||||
background-color: #777777;
|
||||
}
|
||||
|
||||
.dark .api-list-head,
|
||||
.dark [data-tooltip]:hover::after{
|
||||
background-color: #2A2A2A;
|
||||
}
|
||||
|
||||
.dark .api-list-body > div:nth-child(4n+1),
|
||||
.dark .api-list-body > div:nth-child(4n+2) {
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
.dark .icon-collapse {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.dark .close-modal {
|
||||
color: #3C3C3C;
|
||||
}
|
||||
|
||||
.dark input[type="date"] {
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
.dark input[type="date"]::-webkit-calendar-picker-indicator {
|
||||
filter: invert(0);
|
||||
}
|
||||
|
||||
.dark .btn-revoked {
|
||||
background-color: #BE4949 !important;
|
||||
}
|
||||
|
||||
/*Responsive display*/
|
||||
@media (max-width: 768px) {
|
||||
#login-form,
|
||||
|
||||
Reference in New Issue
Block a user