diff --git a/.gitignore b/.gitignore index c6ff681e1..77ca0f813 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ src/ui/client/templates src/ui/static src/ui/templates src/ui/builder +src/ui/client/builder/*.json +src/ui/client/builder/*.txt diff --git a/src/ui/client/builder/home.json b/src/ui/client/builder/home.json deleted file mode 100644 index 64b66d96c..000000000 --- a/src/ui/client/builder/home.json +++ /dev/null @@ -1,105 +0,0 @@ -[ - { - "type": "card", - "link": "https://panel.bunkerweb.io/?utm_campaign=self&utm_source=ui#pro", - "containerColumns": { - "pc": 4, - "tablet": 6, - "mobile": 12 - }, - "widgets": [ - { - "type": "Stat", - "data": { - "title": "home_version", - "stat": "home_free", - "subtitle": "home_upgrade_to_pro", - "iconName": "key", - "subtitleColor": "warning" - } - } - ] - }, - { - "type": "card", - "link": "https://github.com/bunkerity/bunkerweb", - "containerColumns": { - "pc": 4, - "tablet": 6, - "mobile": 12 - }, - "widgets": [ - { - "type": "Stat", - "data": { - "title": "home_version_number", - "stat": "1.6.0-beta", - "subtitle": "home_update_available", - "iconName": "wire", - "subtitleColor": "warning" - } - } - ] - }, - { - "type": "card", - "link": "instances", - "containerColumns": { - "pc": 4, - "tablet": 6, - "mobile": 12 - }, - "widgets": [ - { - "type": "Stat", - "data": { - "title": "home_instances", - "stat": 1, - "subtitle": "home_total_number", - "iconName": "box" - } - } - ] - }, - { - "type": "card", - "link": "services", - "containerColumns": { - "pc": 4, - "tablet": 6, - "mobile": 12 - }, - "widgets": [ - { - "type": "Stat", - "data": { - "title": "home_services", - "stat": 2, - "subtitle": "home_all_methods_included", - "iconName": "disk" - } - } - ] - }, - { - "type": "card", - "link": "plugins", - "containerColumns": { - "pc": 4, - "tablet": 6, - "mobile": 12 - }, - "widgets": [ - { - "type": "Stat", - "data": { - "title": "home_plugins", - "stat": 38, - "subtitle": "home_no_error", - "iconName": "puzzle", - "subtitleColor": "success" - } - } - ] - } -] \ No newline at end of file diff --git a/src/ui/client/dashboard/components/Forms/Field/Datepicker.vue b/src/ui/client/dashboard/components/Forms/Field/Datepicker.vue index 2c1c7a4c6..9fe4702a1 100644 --- a/src/ui/client/dashboard/components/Forms/Field/Datepicker.vue +++ b/src/ui/client/dashboard/components/Forms/Field/Datepicker.vue @@ -47,9 +47,9 @@ import "@assets/css/flatpickr.dark.min.css"; * @param {array} popovers - List of popovers to display more information * @param {object} [attrs={}] - Additional attributes to add to the field * @param {string} [inpType="datepicker"] - The type of the field, useful when we have multiple fields in the same container to display the right field - * @param {number} [value=""] - Default date when instantiate - * @param {number} [minDate=""] - Impossible to pick a date before this date. - * @param {number} [maxDate=""] - Impossible to pick a date after this date. + * @param {timestamp} [value=""] - Default date when instantiate + * @param {timestamp} [minDate=""] - Impossible to pick a date before this date. + * @param {timestamp} [maxDate=""] - Impossible to pick a date after this date. * @param {boolean} [isClipboard=true] - allow to copy the timestamp value * @param {boolean} [hideLabel=false] * @param {object} [columns={"pc": "12", "tablet": "12", "mobile": "12"}] - Field has a grid system. This allow to get multiple field in the same row if needed. @@ -174,7 +174,7 @@ let datepicker; function setMonthSelect(calendarEl, id) { // Hide default select and options const defaultSelect = calendarEl.querySelector( - ".flatpickr-monthDropdown-months", + ".flatpickr-monthDropdown-months" ); defaultSelect.classList.add("hidden"); defaultSelect.setAttribute("aria-hidden", "true"); @@ -191,7 +191,7 @@ function setMonthSelect(calendarEl, id) { container.classList.add( "flatpickr-monthDropdown-months", "inline", - "relative", + "relative" ); // Select-like const selectCustom = document.createElement("button"); @@ -220,7 +220,7 @@ function setMonthSelect(calendarEl, id) { "text-white", "py-1", "hover:brightness-125", - "focus:brightness-125", + "focus:brightness-125" ); opt.setAttribute("data-month", option.value); opt.setAttribute("data-value", option.value); @@ -252,7 +252,7 @@ function setMonthSelect(calendarEl, id) { function setPickerAtt(calendarEl, id = false) { // change error non-standard attributes const inps = calendarEl.querySelectorAll( - 'input.numInput[type="number"][maxlength]', + 'input.numInput[type="number"][maxlength]' ); inps.forEach((inp) => { inp.setAttribute("data-maxlength", inp.getAttribute("maxlength")); @@ -313,7 +313,7 @@ function handleEvents(calendarEl, id, datepicker) { ) { // Get update value const selectDefault = calendarEl.querySelector( - "select.flatpickr-monthDropdown-months", + "select.flatpickr-monthDropdown-months" ); let monthValue; @@ -377,7 +377,7 @@ function handleEvents(calendarEl, id, datepicker) { if (e.key === "Tab" && e.shiftKey) { e.preventDefault(); const currActive = calendarEl.querySelector( - '[data-tabindex-active="true"]', + '[data-tabindex-active="true"]' ); if (!currActive) return; @@ -430,7 +430,7 @@ function handleEvents(calendarEl, id, datepicker) { //Focus previous element with a tabindex const currIndex = datepicker.input.getAttribute("tabindex"); const elements = document.querySelectorAll( - `input[tabindex="${currIndex}"]`, + `input[tabindex="${currIndex}"]` ); // Remove disabled elements const filtered = []; @@ -470,7 +470,7 @@ function handleEvents(calendarEl, id, datepicker) { //Focus next element with a tabindex const currIndex = datepicker.input.getAttribute("tabindex"); const elements = document.querySelectorAll( - `input[tabindex="${currIndex}"]`, + `input[tabindex="${currIndex}"]` ); // Remove disabled elements const filtered = []; @@ -515,7 +515,7 @@ function toggleSelect(calendar, id, e) { optCtnr.classList.toggle("hidden"); optCtnr.setAttribute( "aria-hidden", - optCtnr.classList.contains("hidden") ? "true" : "false", + optCtnr.classList.contains("hidden") ? "true" : "false" ); } } @@ -567,7 +567,7 @@ function updateMonth(calendar, id, e, datepicker) { selectCustom.focus(); // Click on default select to update const selectDefault = calendar.querySelector( - "select.flatpickr-monthDropdown-months", + "select.flatpickr-monthDropdown-months" ); selectDefault.querySelectorAll("option").forEach((option) => { if (option.value === e.target.getAttribute("data-month")) { @@ -623,14 +623,14 @@ function setIndex(calendarEl, tabindex) { const prevMonth = calendarEl.querySelector(".flatpickr-prev-month"); const year = calendarEl.querySelector(".cur-year"); const monthSelect = calendarEl.querySelector( - ".flatpickr-monthDropdown-months", + ".flatpickr-monthDropdown-months" ); prevMonth.setAttribute("tabindex", tabindex); nextMonth.setAttribute("tabindex", tabindex); year.setAttribute("tabindex", tabindex); monthSelect.setAttribute("tabindex", tabindex); const months = calendarEl.querySelectorAll( - ".flatpickr-monthDropdown-month", + ".flatpickr-monthDropdown-month" ); months.forEach((month) => { month.setAttribute("tabindex", tabindex); diff --git a/src/ui/client/dashboard/components/Forms/Field/Editor.vue b/src/ui/client/dashboard/components/Forms/Field/Editor.vue index 808f4476a..787ec3b0b 100644 --- a/src/ui/client/dashboard/components/Forms/Field/Editor.vue +++ b/src/ui/client/dashboard/components/Forms/Field/Editor.vue @@ -38,7 +38,7 @@ import "@assets/script/editor/theme-dawn.js"; * }; * @param {string} [id=uuidv4()] - Unique id * @param {string} label - The label of the field. Can be a translation key or by default raw text. - * @param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text.* @param {string} label + * @param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text. * @param {string} value * @param {object} [attrs={}] - Additional attributes to add to the field * @param {array} [popovers] - List of popovers to display more information @@ -177,7 +177,7 @@ class Editor { try { // Get all elements with the same tabindex const elements = document.querySelectorAll( - `[tabindex="${contentIndex}"]`, + `[tabindex="${contentIndex}"]` ); // Get index of the current element const index = Array.from(elements).indexOf(document.activeElement); @@ -185,14 +185,14 @@ class Editor { if (elements[index - 1]) return elements[index - 1].focus(); // Else try to find tabIndex + 1 element const prevElements = document.querySelectorAll( - `[tabindex="${+contentIndex - 1}"]`, + `[tabindex="${+contentIndex - 1}"]` ); // Else find the highest tabindex element in a limit of +20 let maxTabIndex = -10; let currTabIndex = +contentIndex - 1; while (currTabIndex > maxTabIndex) { const minElements = document.querySelectorAll( - `[tabindex="${currTabIndex}"]`, + `[tabindex="${currTabIndex}"]` ); if (minElements[0]) return minElements[0].focus(); currTabIndex++; @@ -211,7 +211,7 @@ class Editor { try { // Get all elements with the same tabindex const elements = document.querySelectorAll( - `[tabindex="${contentIndex}"]`, + `[tabindex="${contentIndex}"]` ); // Get index of the current element const index = Array.from(elements).indexOf(document.activeElement); @@ -222,7 +222,7 @@ class Editor { let currTabIndex = +contentIndex + 1; while (currTabIndex < maxTabIndex) { const maxElements = document.querySelectorAll( - `[tabindex="${currTabIndex}"]`, + `[tabindex="${currTabIndex}"]` ); if (maxElements[0]) return maxElements[0].focus(); currTabIndex++; @@ -286,7 +286,7 @@ function removeErrCSS() { setTimeout(() => { try { const styleEditors = document.querySelectorAll( - '[style*="font-optical-sizing"]', + '[style*="font-optical-sizing"]' ); styleEditors.forEach((editor) => { diff --git a/src/ui/client/dashboard/components/Forms/Field/Input.vue b/src/ui/client/dashboard/components/Forms/Field/Input.vue index 86fbd121d..74ef6ccc6 100644 --- a/src/ui/client/dashboard/components/Forms/Field/Input.vue +++ b/src/ui/client/dashboard/components/Forms/Field/Input.vue @@ -42,7 +42,7 @@ import { useUUID } from "@utils/global.js"; * @param {string} [id=uuidv4()] - Unique id * @param {string} [type="text"] - text, email, password, number, tel, url * @param {string} label - The label of the field. Can be a translation key or by default raw text. - * @param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text.* @param {string} label + * @param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text. * @param {string} value * @param {object} [attrs={}] - Additional attributes to add to the field * @param {array} [popovers] - List of popovers to display more information diff --git a/src/ui/client/dashboard/components/Forms/Group/Multiple.vue b/src/ui/client/dashboard/components/Forms/Group/Multiple.vue index 0fb902453..640e496bc 100644 --- a/src/ui/client/dashboard/components/Forms/Group/Multiple.vue +++ b/src/ui/client/dashboard/components/Forms/Group/Multiple.vue @@ -79,69 +79,7 @@ import Container from "@components/Widget/Container.vue"; * ], * "containerClass": "z-20" * }, - * "REVERSE_PROXY_AUTH_REQUEST": { - * "context": "multisite", - * "default": "", - * "help": "Enable authentication using an external provider (value of auth_request directive).", - * "id": "reverse-proxy-auth-request", - * "label": "Reverse proxy auth request", - * "regex": "^(\\/[\\w\\].~:\\/?#\\[@!$\\&'\\(\\)*+,;=\\-]*|off)?$", - * "type": "text", - * "multiple": "reverse-proxy", - * "pattern": "^(\\/[\\w\\].~:\\/?#\\[@!$\\&'\\(\\)*+,;=\\-]*|off)?$", - * "inpType": "input", - * "name": "Reverse proxy auth request", - * "columns": { - * "pc": 4, - * "tablet": 6, - * "mobile": 12 - * }, - * "disabled": false, - * "value": "", - * "popovers": [ - * { - * "iconName": "disk", - * "text": "inp_popover_multisite" - * }, - * { - * "iconName": "info", - * "text": "Enable authentication using an external provider (value of auth_request directive)." - * } - * ], - * "containerClass": "z-19" - * }, - * "REVERSE_PROXY_AUTH_REQUEST_SIGNIN_URL": { - * "context": "multisite", - * "default": "", - * "help": "Redirect clients to sign-in URL when using REVERSE_PROXY_AUTH_REQUEST (used when auth_request call returned 401).", - * "id": "reverse-proxy-auth-request-signin-url", - * "label": "Auth request signin URL", - * "regex": "^(https?:\\/\\/[\\-\\w@:%.+~#=]+[\\-\\w\\(\\)!@:%+.~#?&\\/=$]*)?$", - * "type": "text", - * "multiple": "reverse-proxy", - * "pattern": "^(https?:\\/\\/[\\-\\w@:%.+~#=]+[\\-\\w\\(\\)!@:%+.~#?&\\/=$]*)?$", - * "inpType": "input", - * "name": "Auth request signin URL", - * "columns": { - * "pc": 4, - * "tablet": 6, - * "mobile": 12 - * }, - * "disabled": false, - * "value": "", - * "popovers": [ - * { - * "iconName": "disk", - * "text": "inp_popover_multisite" - * }, - * { - * "iconName": "info", - * "text": "Redirect clients to sign-in URL when using REVERSE_PROXY_AUTH_REQUEST (used when auth_request call returned 401)." - * } - * ], - * "containerClass": "z-18" - * }, - * }, + * }, * } * } * } diff --git a/src/ui/client/dashboard/components/Widget/Container.vue b/src/ui/client/dashboard/components/Widget/Container.vue index 856cbdd47..e5c469450 100644 --- a/src/ui/client/dashboard/components/Widget/Container.vue +++ b/src/ui/client/dashboard/components/Widget/Container.vue @@ -15,7 +15,7 @@ import { defineProps, watch, computed, reactive } from "vue"; * @param {string} [containerClass=""] - Additional class * @param {object|boolean} [columns=false] - Work with grid system { pc: 12, tablet: 12, mobile: 12} * @param {string} [tag="div"] - The tag for the container - * @param {array} [display=[]] - Array need to be of format ["groupName", "compId"] in order to be displayed using the display store. More info on the display store itslef. + * @param {array} [display=[]] - Array need two values : "groupName" in index 0 and "compId" in index 1 in order to be displayed using the display store. More info on the display store itslef. */ const props = defineProps({ diff --git a/src/ui/client/dashboard/components/Widget/Grid.vue b/src/ui/client/dashboard/components/Widget/Grid.vue index 3da9c92ff..68ac5c210 100644 --- a/src/ui/client/dashboard/components/Widget/Grid.vue +++ b/src/ui/client/dashboard/components/Widget/Grid.vue @@ -13,7 +13,7 @@ import { defineProps, watch, reactive } from "vue"; * gridClass: "items-start" * } * @param {string} [gridClass="items-start"] - Additional class - * @param {array} [display=[]] - Array need to be of format ["groupName", "compId"] in order to be displayed using the display store. More info on the display store itslef. + * @param {array} [display=[]] - Array need two values : "groupName" in index 0 and "compId" in index 1 in order to be displayed using the display store. More info on the display store itslef. */ const props = defineProps({ diff --git a/src/ui/client/dashboard/components/Widget/GridLayout.vue b/src/ui/client/dashboard/components/Widget/GridLayout.vue index f7f9a4645..ae844fc85 100644 --- a/src/ui/client/dashboard/components/Widget/GridLayout.vue +++ b/src/ui/client/dashboard/components/Widget/GridLayout.vue @@ -24,7 +24,7 @@ import { useDisplayStore } from "@store/global.js"; * @param {string} [link=""] - Will transform the container tag from a div to an a tag with the link as href. Useful with card type. * @param {object} [columns={"pc": 12, "tablet": 12, "mobile": 12}] - Work with grid system { pc: 12, tablet: 12, mobile: 12} * @param {string} [gridLayoutClass="items-start"] - Additional class - * @param {array} [display=[]] - Array need to be of format ["groupName", "compId"] in order to be displayed using the display store. More info on the display store itslef. + * @param {array} [display=[]] - Array need two values : "groupName" in index 0 and "compId" in index 1 in order to be displayed using the display store. More info on the display store itslef. * @param {string} [tabId=contentIndex] - Case the container is converted to an anchor with a link, we can define the tabId, by default it is the contentIndex */