UI handle readonly

* add global variable is_readonly
* remove plugin page upload element while readonly
* update services script to force disabled state for settings and actions
* update file manager script to handle readonly
* add jinja logic for static elements to disabled them on readonly
*add disabled style to some buttons missing this style
This commit is contained in:
Jordan Blasenhauer 2024-05-20 17:04:09 +02:00
parent fbef17178f
commit 9bf9058dd5
18 changed files with 123 additions and 48 deletions

View file

@ -402,6 +402,7 @@ def inject_variables():
plugins=app.config["CONFIG"].get_plugins(),
pro_loading=ui_data.get("PRO_LOADING", False),
bw_version=metadata["version"],
is_readonly=False,
)

File diff suppressed because one or more lines are too long

View file

@ -24,6 +24,11 @@ class SettingsService {
this.settingsMultiple,
"services",
);
this.isReadOnly =
document
.querySelector("[data-services-modal]")
.getAttribute("data-readonly") === "true";
this.initSettingsService();
}
@ -96,6 +101,7 @@ class SettingsService {
operation,
] = this.getActionData(e.target);
const forceDisabled = this.isReadOnly ? true : false;
const forceEnabled = action === "new" ? true : false;
const setMethodUI =
action === "new" || action === "clone" ? true : false;
@ -110,6 +116,7 @@ class SettingsService {
setMethodUI,
forceEnabled,
emptyServerName,
forceDisabled,
);
}
} catch (err) {}
@ -121,6 +128,10 @@ class ServiceModal {
constructor() {
//modal elements
this.modal = document.querySelector("[data-services-modal]");
this.isReadOnly =
document
.querySelector("[data-services-modal]")
.getAttribute("data-readonly") === "true";
this.modalTitle = this.modal.querySelector("[data-services-modal-title]");
this.modalTabs = this.modal.querySelector(["[data-services-tabs-select]"]);
this.modalTabsHeader = this.modal.querySelector([
@ -262,7 +273,10 @@ class ServiceModal {
}
this.setIsDraft(isDraft === "yes" ? true : false, method);
this.openModal();
setTimeout(() => {
this.setActionBtns();
this.openModal();
}, 50);
}
resetFilterSettings() {
@ -279,6 +293,20 @@ class ServiceModal {
inpKeyword.dispatchEvent(new Event("input"));
}
setActionBtns() {
if (this.isReadOnly) {
this.modal.querySelectorAll("button[type='submit']").forEach((btn) => {
btn.setAttribute("disabled", "true");
});
}
if (!this.isReadOnly) {
this.modal.querySelectorAll("button[type='submit']").forEach((btn) => {
btn.removeAttribute("disabled");
});
}
}
setIsDraft(isDraft, method) {
const draftVal = isDraft ? "yes" : "no";

View file

@ -5,6 +5,12 @@ class FolderNav {
`[data-${this.prefix}-breadcrumb]`,
);
this.container = document.querySelector(`[data-${this.prefix}-container]`);
this.isReadonly =
document
.querySelector(`[data-${this.prefix}-container]`)
.getAttribute(`data-readonly`) === "true"
? true
: false;
this.listContainer = document.querySelector(
`[data-${this.prefix}-folders]`,
);
@ -95,6 +101,9 @@ class FolderNav {
updateActions(folder) {
// for root
if (!folder) return this.addFileEl.setAttribute("disabled", "");
if (folder && this.isReadonly)
return this.addFileEl.setAttribute("disabled", "");
//check if folder allow add file/folder
const isAddFile = folder.getAttribute("data-can-create-file") || "False";
isAddFile === "True"
@ -326,6 +335,12 @@ class FolderModal {
this.prefix = prefix;
//container
this.container = document.querySelector(`[data-${this.prefix}-container]`);
this.isReadonly =
document
.querySelector(`[data-${this.prefix}-container]`)
.getAttribute(`data-readonly`) === "true"
? true
: false;
//add service/file elements
this.breadContainer = document.querySelector(
`[data-${this.prefix}-breadcrumb]`,
@ -580,28 +595,30 @@ class FolderModal {
if (action === "new") {
this.modalSubmit.textContent = "add";
this.setSubmitBtnType("valid-btn");
return;
}
if (action === "view") {
this.modalSubmit.textContent = "ok";
this.setSubmitBtnType("valid-btn");
return;
}
if (action === "edit") {
this.setSubmitBtnType("edit-btn");
this.modalSubmit.textContent = "edit";
return;
}
if (action === "delete") {
this.setSubmitBtnType("delete-btn");
this.modalSubmit.textContent = "delete";
return;
}
if (action === "download") {
this.setSubmitBtnType("info-btn");
this.modalSubmit.textContent = "download";
return;
}
// readonly logic
if (["new", "edit", "delete"].includes(action) && this.isReadonly) {
this.modalSubmit.setAttribute("disabled", "true");
} else {
this.modalSubmit.removeAttribute("disabled");
}
}

View file

@ -1000,6 +1000,7 @@ class Settings {
this.oldServName = "";
this.setMethodUI = false;
this.forceEnabled = false;
this.forceDisabled = false;
this.emptyServerName = false;
this.currSettings = {};
this.initSettings();
@ -1170,6 +1171,7 @@ class Settings {
setMethodUI,
forceEnabled,
emptyServerName,
forceDisabled,
) {
// Get global needed data
this.currAction = action;
@ -1179,6 +1181,7 @@ class Settings {
this.setMethodUI = setMethodUI;
this.forceEnabled = forceEnabled;
this.emptyServerName = emptyServerName;
this.forceDisabled = forceDisabled;
this.updateOperation();
this.updateOldNameValue();
@ -1282,17 +1285,27 @@ class Settings {
? true
: false;
if (proDisabled) return inp.setAttribute("disabled", "");
let inpDisabledState = inp;
if (inp.tagName === "SELECT")
inpDisabledState = inp.parentElement
.querySelector("[data-select-container]")
.querySelector("button[data-setting-select]");
if (this.forceEnabled) return inp.removeAttribute("disabled");
if (this.forceDisabled)
return inpDisabledState.setAttribute("disabled", "");
if (proDisabled)
return inpDisabledState.setAttribute("disabled", "");
if (this.forceEnabled)
return inpDisabledState.removeAttribute("disabled");
if (method === "ui" || method === "default") {
inp.removeAttribute("disabled");
inpDisabledState.removeAttribute("disabled");
} else {
inp.setAttribute("disabled", "");
inpDisabledState.setAttribute("disabled", "");
}
if (global) inp.removeAttribute("disabled");
if (global) inpDisabledState.removeAttribute("disabled");
});
} catch (err) {}
}
@ -1417,7 +1430,8 @@ class SettingsMultiple extends Settings {
inps.forEach((inp) => {
// case checkbox
if (inp.getAttribute("type") === "checkbox") {
const defaultVal = inp.getAttribute("data-default-value") || "";
const defaultVal =
inp.getAttribute("data-default-value") || "";
if (defaultVal === "yes" && !inp.checked) {
inp.click();
@ -1426,7 +1440,8 @@ class SettingsMultiple extends Settings {
// case regular
if (inp.getAttribute("type") !== "checkbox") {
const defaultVal = inp.getAttribute("data-default-value") || "";
const defaultVal =
inp.getAttribute("data-default-value") || "";
inp.setAttribute("value", defaultVal);
inp.value = defaultVal;
}
@ -1438,7 +1453,8 @@ class SettingsMultiple extends Settings {
"button[data-setting-select]",
);
selects.forEach((select) => {
const defaultVal = select.getAttribute("data-default-value") || "";
const defaultVal =
select.getAttribute("data-default-value") || "";
select
.querySelector("data-setting-select-text")
.setAttribute("data-value", defaultVal);
@ -1467,7 +1483,10 @@ class SettingsMultiple extends Settings {
? true
: false;
return proDisabled;
const isReadOnly = this.forceDisabled;
if (proDisabled || isReadOnly) return true;
return false;
}
removePrevMultiples() {
@ -1958,6 +1977,7 @@ class SettingsAdvanced extends SettingsEditor {
setMethodUI = false,
forceEnabled = false,
emptyServerName = false,
forceDisabled = false,
) {
this.updateData(
action,
@ -1967,6 +1987,7 @@ class SettingsAdvanced extends SettingsEditor {
setMethodUI,
forceEnabled,
emptyServerName,
forceDisabled,
);
this.setSettingsAdvanced();
this.resetServerName();

View file

@ -47,6 +47,9 @@
@apply tracking-wide dark:brightness-90 inline-block px-4 py-2 md:px-5 md:py-2.5 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-sky-500 hover:bg-sky-500/80 focus:bg-sky-500/80 leading-normal ease-in shadow-xs hover:-translate-y-px active:opacity-85 hover:shadow-md disabled:cursor-not-allowed dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400/0 dark:disabled:bg-gray-700 dark:disabled:border-gray-700/0 disabled:hover:translate-y-0 disabled:hover:bg-gray-400 disabled:hover:border-gray-400/0 dark:disabled:hover:translate-y-0 dark:disabled:hover:bg-gray-700 dark:disabled:hover:border-gray-700/0;
}
.btn-disabled-style {
@apply disabled:cursor-not-allowed dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400/0 dark:disabled:bg-gray-700 dark:disabled:border-gray-700/0 disabled:hover:translate-y-0 disabled:hover:bg-gray-400 disabled:hover:border-gray-400/0 dark:disabled:hover:translate-y-0 dark:disabled:hover:bg-gray-700 dark:disabled:hover:border-gray-700/0;
}
/*----------------------------------------------*/
/*---------------SETTINGS_PLUGINS---------------*/
/*----------------------------------------------*/

View file

@ -142,7 +142,7 @@
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full">
<h5 class="input-title">License key</h5>
<label class="sr-only" for="license">License key</label>
<input type="password"
<input {% if is_readonly%}disabled{% endif %} type="password"
id="license"
name="license"
class="col-span-12 regular-input"
@ -173,7 +173,7 @@
</div>
</div>
<div class="col-span-12 flex justify-center mt-6">
<button type="submit"
<button {% if is_readonly%}disabled{% endif %} type="submit"
id="activate-key-button"
name="activate-key-button"
class="valid-btn">SAVE</button>
@ -200,7 +200,7 @@
<div class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full">
<h5 class="input-title">Username</h5>
<label class="sr-only" for="admin_username">New username</label>
<input type="text"
<input {% if is_readonly%}disabled{% endif %} type="text"
id="admin_username"
name="admin_username"
class="col-span-12 regular-input"
@ -216,7 +216,7 @@
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full">
<h5 class="input-title">Password</h5>
<label class="sr-only" for="curr_password">Password</label>
<input type="password"
<input {% if is_readonly%}disabled{% endif %} type="password"
id="curr_password"
name="curr_password"
class="col-span-12 regular-input"
@ -249,7 +249,7 @@
</div>
<!-- end password inpt-->
<div class="col-span-12 flex justify-center mt-6">
<button type="submit"
<button {% if is_readonly%}disabled{% endif %} type="submit"
id="username-button"
name="username-button"
value="username"
@ -277,7 +277,7 @@
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full">
<h5 class="input-title">Password</h5>
<label class="sr-only" for="curr_password">Password</label>
<input type="password"
<input {% if is_readonly%}disabled{% endif %} type="password"
id="curr_password"
name="curr_password"
class="col-span-12 regular-input"
@ -314,7 +314,7 @@
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full">
<h5 class="input-title">New password</h5>
<label class="sr-only" for="admin_password">New password</label>
<input type="password"
<input {% if is_readonly%}disabled{% endif %} type="password"
id="admin_password"
name="admin_password"
class="col-span-12 regular-input"
@ -351,7 +351,7 @@
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full">
<h5 class="input-title">Confirm new password</h5>
<label class="sr-only" for="admin_password_check">Confirm new password</label>
<input type="password"
<input {% if is_readonly%}disabled{% endif %} type="password"
id="admin_password_check"
name="admin_password_check"
class="col-span-12 regular-input"
@ -384,7 +384,7 @@
<strong class="opacity-0 font-normal text-sm text-red-500" data-pw-alert>Value does not match password</strong>
</div>
<div class="col-span-12 flex justify-center">
<button type="submit" id="pw-button" name="pw-button" class="valid-btn">Save</button>
<button {% if is_readonly%}disabled{% endif %} type="submit" id="pw-button" name="pw-button" class="valid-btn">Save</button>
</div>
</form>
<form data-tab-item="totp"
@ -426,7 +426,7 @@
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full">
<h5 class="input-title">Secret token</h5>
<label class="sr-only" for="secret_token">secret token</label>
<input type="password"
<input {% if is_readonly%}disabled{% endif %} type="password"
id="secret_token"
name="secret_token"
class="col-span-12 regular-input"
@ -477,7 +477,7 @@
<div class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full">
<h5 class="input-title">2FA code</h5>
<label class="sr-only" for="totp_token">totp code</label>
<input type="text"
<input {% if is_readonly%}disabled{% endif %} type="text"
id="totp_token"
name="totp_token"
class="col-span-12 regular-input"
@ -492,7 +492,7 @@
class="flex flex-col relative col-span-12 px-4 my-2 md:px-6 md:my-3 lg:px-6 lg:my-3 max-w-[400px] w-full">
<h5 class="input-title">Password</h5>
<label class="sr-only" for="curr_password">Password</label>
<input type="password"
<input {% if is_readonly%}disabled{% endif %} type="password"
id="curr_password"
name="curr_password"
class="col-span-12 regular-input"
@ -525,7 +525,7 @@
</div>
<!-- end password inpt-->
<div class="col-span-12 flex justify-center mt-6">
<button type="submit"
<button {% if is_readonly%}disabled{% endif %} type="submit"
id="totp-button"
name="totp-button"
value="totp"

View file

@ -14,9 +14,9 @@
<!-- actions -->
<div class="col-span-12 relative flex justify-center min-w-0 break-words rounded-2xl bg-clip-border">
<button data-add-ban
<button {% if is_readonly%}disabled{% endif %} data-add-ban
type="button"
class="dark:bg-green-500/90 duration-300 w-80 flex justify-center items-center px-6 py-3 font-bold text-center text-white dark:text-gray-200 uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-base ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
class="disabled:cursor-not-allowed dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400/0 dark:disabled:bg-gray-700 dark:disabled:border-gray-700/0 disabled:hover:translate-y-0 disabled:hover:bg-gray-400 disabled:hover:border-gray-400/0 dark:disabled:hover:translate-y-0 dark:disabled:hover:bg-gray-700 dark:disabled:hover:border-gray-700/0 dark:bg-green-500/90 duration-300 dark:text-gray-100 w-80 flex justify-center items-center px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-base ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
<span class="mr-2">Add ban</span>
<svg xmlns="http://www.w3.org/2000/svg"
fill="none"
@ -139,7 +139,7 @@
data-checkbox-handler="ban-item-{{ loop.index }}"
class="relative mb-7 md:mb-0 z-10 ml-2">
<label class="sr-only" for="ban-item-{{ loop.index }}">Ban ip {{ loop.index }}</label>
<input id="ban-item-{{ loop.index }}"
<input {% if is_readonly%}disabled{% endif %} id="ban-item-{{ loop.index }}"
name="ban-item-{{ loop.index }}"
data-default-method="ui"
data-default-value="no"
@ -182,7 +182,7 @@
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="operation" value="unban">
<input data-unban-inp type="hidden" name="data" value="">
<button data-unban-btn
<button {% if is_readonly%}disabled{% endif %} data-unban-btn
disabled
type="submit"
class="valid-btn mr-3 text-base">UNBAN</button>

View file

@ -1,6 +1,6 @@
{% set current_endpoint = url_for(request.endpoint)[1:].split("/")[-1].strip().replace('_', '-') %}
<!-- main container -->
<div data-{{ current_endpoint }}-container class="min-h-[400px] flex flex-col justify-between dark:brightness-110 md:min-h-50-screen col-span-12 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<div data-readonly="{% if is_readonly %}true{% else %}false{% endif %}" data-{{ current_endpoint }}-container class="min-h-[400px] flex flex-col justify-between dark:brightness-110 md:min-h-50-screen col-span-12 p-4 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
<div class="mb-4 px-3">
<div class="w-full grid-cols-12 grid">
<div class="col-span-12 md:col-span-8">

View file

@ -64,7 +64,7 @@
<!-- end plugin item -->
<!-- submit -->
<div class="flex w-full justify-center mt-8 mb-2">
<button type="submit" class="valid-btn">SAVE</button>
<button {% if is_readonly%}disabled{% endif %} type="submit" class="valid-btn">SAVE</button>
</div>
<!-- end submit -->
</form>

View file

@ -40,7 +40,7 @@
<!-- button list-->
<div class="relative w-full flex justify-center sm:justify-end">
{% if instance._type == "local" and instance.health %}
<button type="submit"
<button {% if is_readonly%}disabled{% endif %} type="submit"
name="operation"
value="restart"
class="edit-btn mx-1 text-xs">Restart</button>
@ -50,18 +50,18 @@
class="delete-btn mx-1 text-xs">Stop</button>
{% endif %}
{% if not instance._type == "local" and instance.health %}
<button type="submit"
<button {% if is_readonly%}disabled{% endif %} type="submit"
name="operation"
value="reload"
class="edit-btn mx-1 text-xs">Reload</button>
<button type="submit"
<button {% if is_readonly%}disabled{% endif %} type="submit"
name="operation"
value="stop"
class="delete-btn mx-1 text-xs">Stop</button>
{% endif %}
{% if instance._type == "local" and not instance.health or not
instance._type == "local" and not instance.health %}
<button type="submit"
<button {% if is_readonly%}disabled{% endif %} type="submit"
name="operation"
value="start"
class="valid-btn mx-1 text-xs">Start</button>

View file

@ -147,7 +147,7 @@
<div class="{{ data['custom_class'] }} relative dark:text-gray-400 text-sm m-0 my-1 mr-1"
data-{{attribute_name}}-files>
{% if value['cache'] %}
<button data-{{attribute_name}}-setting-select="{{ job_name }}"
<button {% if is_readonly%}disabled{% endif %} data-{{attribute_name}}-setting-select="{{ job_name }}"
class="py-1 text-sm disabled:opacity-75 dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400 dark:disabled:bg-gray-800 dark:disabled:border-gray-800 duration-300 ease-in-out dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 focus:border-green-500 flex justify-between align-middle items-center text-left leading-6 ease w-full rounded-lg border border-solid border-gray-300 bg-white bg-clip-padding px-1.5 md:px-3 font-normal text-gray-700 transition-all placeholder:text-gray-500">
<span id="jobs-{{ job_name }}"
data-name="jobs-{{ job_name }}"

View file

@ -13,6 +13,7 @@
] %}
{% include "card_info.html" %}
{% if not is_readonly %}
<!-- upload layout -->
<div data-{{attribute_name}}-upload
class="p-4 col-span-12 md:col-span-7 2xl:col-span-4 grid grid-cols-12 relative min-w-0 break-words bg-white shadow-xl dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border">
@ -49,6 +50,8 @@
</div>
</div>
<!-- end upload layout -->
{% endif %}
<!-- filter -->
{% set filters = [
{
@ -104,7 +107,7 @@
</a>
{% endif %}
{% if plugin['type'] == "external" %}
<button data-{{attribute_name}}-action="delete"
<button {% if is_readonly%}disabled{% endif %} data-{{attribute_name}}-action="delete"
name="{{ plugin['id'] }}"
aria-label="delete plugin"
class="plugins-list-items-delete">

View file

@ -31,13 +31,13 @@
class="col-span-12 relative flex justify-center min-w-0 break-words rounded-2xl bg-clip-border">
<div data-is-draft class="hidden" data-value="no"></div>
<div data-service-method class="hidden" data-value="ui"></div>
<button data-{{attribute_name}}-action="new"
<button {% if is_readonly%}disabled{% endif %} data-{{attribute_name}}-action="new"
data-{{attribute_name}}-name="service"
data-old-name
data-value="new"
data-settings="{}"
type="button"
class="dark:bg-green-500/90 duration-300 dark:text-gray-100 w-80 flex justify-center items-center px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-base ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
class="disabled:cursor-not-allowed dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400/0 dark:disabled:bg-gray-700 dark:disabled:border-gray-700/0 disabled:hover:translate-y-0 disabled:hover:bg-gray-400 disabled:hover:border-gray-400/0 dark:disabled:hover:translate-y-0 dark:disabled:hover:bg-gray-700 dark:disabled:hover:border-gray-700/0 dark:bg-green-500/90 duration-300 dark:text-gray-100 w-80 flex justify-center items-center px-6 py-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer bg-green-500 hover:bg-green-500/80 focus:bg-green-500/80 leading-normal text-base ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 hover:-translate-y-px active:opacity-85 hover:shadow-md">
<span class="mr-2">new service</span>
<svg xmlns="http://www.w3.org/2000/svg"
fill="none"
@ -284,8 +284,10 @@
{% endif %}
{% for button in action_buttons %}
<button
{% if button['name'] == "clone" and is_readonly%}disabled{% endif %}
{% if button['name'] == "clone" or button['name'] == "edit"%}
data-settings="{{ service['settings'] }}"
{% endif %}
{% if button['name'] == "new"%}
data-settings="{}"
@ -293,7 +295,7 @@
data-{{attribute_name}}-action="{{ button['name'] }}"
aria-label="{{ button['label'] }}"
data-{{attribute_name}}-name="{{ service['SERVER_NAME']['value'] }}"
class="dark:brightness-90 z-20 mx-1 bg-{{ button['color'] }} hover:bg-{{ button['color'] }}/80 focus:bg-{{ button['color'] }}/80 inline-block p-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer leading-normal text-xs ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 active:opacity-85 hover:shadow-md">
class="disabled:cursor-not-allowed dark:disabled:text-gray-300 disabled:text-gray-700 disabled:bg-gray-400 disabled:border-gray-400/0 dark:disabled:bg-gray-700 dark:disabled:border-gray-700/0 disabled:hover:translate-y-0 disabled:hover:bg-gray-400 disabled:hover:border-gray-400/0 dark:disabled:hover:translate-y-0 dark:disabled:hover:bg-gray-700 dark:disabled:hover:border-gray-700/0 dark:brightness-90 z-20 mx-1 bg-{{ button['color'] }} hover:bg-{{ button['color'] }}/80 focus:bg-{{ button['color'] }}/80 inline-block p-3 font-bold text-center text-white uppercase align-middle transition-all rounded-lg cursor-pointer leading-normal text-xs ease-in tracking-tight-rem shadow-xs bg-150 bg-x-25 active:opacity-85 hover:shadow-md">
{% if button['name'] == "clone" %}
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"

View file

@ -1,5 +1,5 @@
<!-- modal -->
<div data-services-plugins-container
<div data-readonly="{% if is_readonly %}true{% else %}false{% endif %}" data-services-plugins-container
data-services-modal
class="dark:brightness-110 hidden w-screen h-screen fixed bg-gray-600/50 z-[1001] top-0 left-0 justify-center items-center">
<div data-services-modal-card

View file

@ -13,7 +13,7 @@
<div data-checkbox-handler="{{ inp_id }}"
class="relative mb-7 md:mb-0 z-10 ">
<label class="sr-only" for="{{ inp_name_mult }}">{{ inp_name }}</label>
<input id="{{ inp_name_mult }}"
<input {% if is_readonly%}disabled{% endif %} id="{{ inp_name_mult }}"
name="{{ inp_name_mult }}"
data-default-method="{% if inp_name in ['AUTOCONF_MODE', 'SWARM_MODE', 'KUBERNETES_MODE'] %}mode{% else %}{{ global_config_method }}{% endif %}"
data-default-value="{{ global_config[inp_name]['value'] }}"

View file

@ -13,7 +13,7 @@
<div class="relative flex items-center">
<label class="sr-only" for="{{ inp_name_mult }}">{{ inp_name }}</label>
<input {% if inp_name == "SERVER_NAME" %}required{% endif %}
<input {% if is_readonly%}disabled{% endif %} {% if inp_name == "SERVER_NAME" %}required{% endif %}
data-default-value="{{ global_config_value }}"
data-default-method="{{ global_config_method }}"
data-setting-input

View file

@ -33,7 +33,7 @@
<!-- end default hidden-->
<!--custom-->
<div data-select-container class="relative">
<button {% if global_config_method != 'ui' and global_config_method != 'default' or is_read_only %}disabled{% endif %}
<button {% if is_readonly%}disabled{% endif %} {% if global_config_method != 'ui' and global_config_method != 'default' or is_read_only %}disabled{% endif %}
data-setting-select="{{ inp_id }}"
data-default-value="{{ global_config_value }}"
data-default-method="{{ global_config_method }}"