mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
plugins page modal working + add a11y utils
* now plugins page has a modal that allow to delete a plugin * add some a11y to modal : force focus on a modal element on open + avoid focus elements outside modal + escape key will close modal * add possibility to set attributs to Text and Popover components in order to add custom logic using attributs (like changing Text content or opening a modal on popover click) * fix some false css properties * enhanced modal elements style
This commit is contained in:
parent
18009189ab
commit
ca09b28065
15 changed files with 503 additions and 84 deletions
|
|
@ -507,7 +507,7 @@ body {
|
|||
}
|
||||
|
||||
.layout-modal {
|
||||
@apply relative min-w-[300px] sm:min-w-[450px] max-w-screen-xl max-h-[80vh] min-h-[200px] transition dark:brightness-110 shadow-md bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border transform duration-300 ease-in-out px-6 py-4 overflow-hidden break-words grid grid-cols-12;
|
||||
@apply relative min-w-[300px] sm:min-w-[450px] max-w-screen-xl max-h-[80vh] transition dark:brightness-110 shadow-md bg-white dark:bg-slate-850 dark:shadow-dark-xl rounded-2xl bg-clip-border transform duration-300 ease-in-out px-6 py-4 overflow-hidden break-words grid grid-cols-12;
|
||||
}
|
||||
|
||||
.layout-modal-button-container {
|
||||
|
|
@ -1016,16 +1016,20 @@ body {
|
|||
/* CONTENT COMPONENT */
|
||||
|
||||
.text-content {
|
||||
@apply mb-0 break-word;
|
||||
@apply col-span-12 mb-0 break-word;
|
||||
}
|
||||
|
||||
.text-modal {
|
||||
@apply col-span-12 mb-2 text-center break-word;
|
||||
}
|
||||
|
||||
.text-unmatch {
|
||||
@apply text-lg mb-0 break-word;
|
||||
@apply col-span-12 text-lg mb-0 break-word;
|
||||
|
||||
}
|
||||
|
||||
.text-stat {
|
||||
@apply my-1 font-bold dark:text-white/90 text-black uppercase break-word;
|
||||
@apply col-span-12 my-1 font-bold dark:text-white/90 text-black uppercase break-word;
|
||||
}
|
||||
/* LIST COMPONENT */
|
||||
|
||||
|
|
@ -1087,6 +1091,14 @@ body {
|
|||
@apply capitalize-first break-word w-full max-w-[80%] sm:max-w-[600px] col-span-12 font-sans text-sm font-semibold leading-normal uppercase dark:text-white/90 text-[#344767];
|
||||
}
|
||||
|
||||
.title-modal {
|
||||
@apply capitalize-first break-word w-full max-w-[80%] sm:max-w-[700px] col-span-12 font-bold dark:text-white/90 transition duration-300 ease-in-out text-xl text-[#344767] tracking-normal;
|
||||
}
|
||||
|
||||
.no-subtitle.title-modal {
|
||||
@apply mb-6;
|
||||
}
|
||||
|
||||
.no-subtitle.title-container {
|
||||
@apply mb-2.5;
|
||||
}
|
||||
|
|
@ -1105,6 +1117,7 @@ body {
|
|||
|
||||
.is-subtitle.title-container,
|
||||
.is-subtitle.title-card,
|
||||
.is-subtitle.title-modal,
|
||||
.is-subtitle.title-stat,
|
||||
.is-subtitle.title-content,
|
||||
.is-subtitle.title-min {
|
||||
|
|
@ -1283,6 +1296,12 @@ body {
|
|||
@apply w-6.5 h-6.5;
|
||||
}
|
||||
|
||||
/* BTN GROUP */
|
||||
|
||||
.btn-group-modal {
|
||||
@apply col-span-12 justify-center items-center mt-4;
|
||||
}
|
||||
|
||||
/* FILE MANAGER */
|
||||
|
||||
.file-manager-breadcrumb {
|
||||
|
|
@ -2554,6 +2573,10 @@ body {
|
|||
|
||||
/* UTILS */
|
||||
|
||||
.bold {
|
||||
@apply font-bold;
|
||||
}
|
||||
|
||||
.-z-0 {
|
||||
@apply -z-[0];
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -4,6 +4,8 @@ import Grid from "@components/Widget/Grid.vue";
|
|||
import GridLayout from "@components/Widget/GridLayout.vue";
|
||||
import ListDetails from "@components/List/Details.vue";
|
||||
import Title from "@components/Widget/Title.vue";
|
||||
import Text from "@components/Widget/Text.vue";
|
||||
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
|
||||
|
||||
/**
|
||||
@name Builder/pLugin.vue
|
||||
|
|
@ -74,6 +76,11 @@ const props = defineProps({
|
|||
v-if="widget.type === 'ListDetails'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Text v-if="widget.type === 'Text'" v-bind="widget.data" />
|
||||
<ButtonGroup
|
||||
v-if="widget.type === 'ButtonGroup'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
</GridLayout>
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ import Button from "@components/Widget/Button.vue";
|
|||
},
|
||||
],
|
||||
}
|
||||
@param {string} [groupClass="justify-center align-center"] - Additional class for the flex container
|
||||
@param {string} [groupClass="justify-center items-center"] - Additional class for the flex container
|
||||
@param {array} buttons - List of buttons to display. Button component is used.
|
||||
*/
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ const props = defineProps({
|
|||
groupClass: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "justify-center align-center",
|
||||
default: "justify-center items-center",
|
||||
},
|
||||
buttons: {
|
||||
type: Array,
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ onMounted(() => {
|
|||
<template>
|
||||
<!-- modal -->
|
||||
<template v-if="props.type === 'modal'">
|
||||
<div class="layout-modal-container" :id="container.id">
|
||||
<div data-modal class="layout-modal-container hidden" :id="container.id">
|
||||
<div class="layout-backdrop"></div>
|
||||
<div class="layout-modal-wrap" :data-hide-el="container.id">
|
||||
<div class="layout-modal">
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ const props = defineProps({
|
|||
<ListPairs :pairs="props.pairs" />
|
||||
<ButtonGroup
|
||||
:buttons="props.buttons"
|
||||
:groupClass="'justify-end align-center'"
|
||||
:groupClass="'justify-end item-center'"
|
||||
/>
|
||||
</Container>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -13,11 +13,13 @@ import Icons from "@components/Widget/Icons.vue";
|
|||
href: "#",
|
||||
iconName: "info",
|
||||
iconColor: "info",
|
||||
attrs: { "data-popover": "test" },
|
||||
}
|
||||
@param {string} text - Content of the popover. Can be a translation key or by default raw text.
|
||||
@param {string} [href="#"] - Link of the anchor. By default it is a # link.
|
||||
@param {string} iconName - Name in lowercase of icons store on /Icons. If falsy value, no icon displayed.
|
||||
@param {string} iconColor - Color of the icon between tailwind colors
|
||||
@param {object} [attrs={}] - List of attributs to add to the text.
|
||||
@param {string} [tag="a"] - By default it is a anchor tag, but we can use other tag like div in case of popover on another anchor
|
||||
@param {string} [popoverClass=""] - Additional class for the popover container
|
||||
@param {string} [svgSize="base"] - Determine svg size between sm, md, base and lg.
|
||||
|
|
@ -160,6 +162,7 @@ onMounted(() => {
|
|||
|
||||
<template>
|
||||
<component
|
||||
v-bind="props.attrs"
|
||||
ref="popoverBtn"
|
||||
:tabindex="props.tabId"
|
||||
:aria-controls="`${popover.id}-popover-text`"
|
||||
|
|
|
|||
|
|
@ -9,11 +9,13 @@ import Flex from "@components/Widget/Flex.vue";
|
|||
{
|
||||
text: "This is a paragraph",
|
||||
textClass: "text-3xl"
|
||||
attrs: { id: "paragraph" },
|
||||
}
|
||||
@param {string} text - The text value. Can be a translation key or by default raw text.
|
||||
@param {string} [textClass="text-content"] - Style of text. Can be replace by any class starting by 'text-' like 'text-stat'.
|
||||
@param {string} [tag="p"] - The tag of the text. Can be p, span, div, h1, h2, h3, h4, h5, h6
|
||||
@param {boolean|object} [icons=false] - The popover to display with the text. Check Popover component for more details.
|
||||
@param {object} [attrs={}] - List of attributs to add to the text.
|
||||
*/
|
||||
|
||||
const props = defineProps({
|
||||
|
|
@ -36,17 +38,31 @@ const props = defineProps({
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
attrs: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: {},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component v-if="!props.icons" :is="props.tag" :class="[props.textClass]">
|
||||
<component
|
||||
v-if="!props.icons"
|
||||
:is="props.tag"
|
||||
v-bind="props.attrs"
|
||||
:class="[props.textClass]"
|
||||
>
|
||||
{{ $t(props.text, props.text) }}
|
||||
</component>
|
||||
|
||||
<Flex :flexClass="'justify-center'" v-if="props.icons">
|
||||
<Icons v-if="props.icons" v-bind="props.icons" />
|
||||
<component :is="props.tag" :class="[props.textClass, 'ml-2']">
|
||||
<component
|
||||
:is="props.tag"
|
||||
v-bind="props.attrs"
|
||||
:class="[props.textClass, 'ml-2']"
|
||||
>
|
||||
{{ $t(props.text, props.text) }}
|
||||
</component>
|
||||
</Flex>
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ const baseClass = computed(() => {
|
|||
if (props.type === "content") return "title-content";
|
||||
if (props.type === "min") return "title-min";
|
||||
if (props.type === "stat") return "title-stat";
|
||||
if (props.type === "modal") return "title-modal";
|
||||
return "title-card";
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -213,5 +213,6 @@
|
|||
"plugins_type": "Plugin type",
|
||||
"plugins_type_desc": "Only show plugins of the chosen type",
|
||||
"plugins_delete_desc": "Delete plugin",
|
||||
"plugins_modal_delete": "Delete plugin"
|
||||
"plugins_modal_delete_title": "Delete plugin",
|
||||
"plugins_modal_delete_confirm": "Are you sure you want to delete the plugin below ?"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { reactive, onBeforeMount, onMounted } from "vue";
|
|||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderPlugins from "@components/Builder/Plugins.vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import { useForm } from "@utils/form.js";
|
||||
|
||||
/**
|
||||
@name Page/PLugins.vue
|
||||
|
|
@ -43,6 +44,7 @@ function redirectPlugin() {
|
|||
function deletePlugin() {
|
||||
const deleteData = {
|
||||
name: "pluginName",
|
||||
id: "pluginId",
|
||||
type: "pluginType",
|
||||
operation: "delete",
|
||||
};
|
||||
|
|
@ -59,14 +61,23 @@ function deletePlugin() {
|
|||
return;
|
||||
// Update data
|
||||
deleteData.name = e.target
|
||||
.closest("[data-plugin-name]")
|
||||
.getAttribute("data-plugin-name");
|
||||
deleteData.id = e.target
|
||||
.closest("[data-plugin-id]")
|
||||
.getAttribute("data-plugin-id");
|
||||
deleteData.type = e.target
|
||||
.closest("[data-plugin-type]")
|
||||
.getAttribute("data-plugin-type");
|
||||
// Attach data to submit button (need to check attributs data-delete-plugin)
|
||||
const submitBtn = document.querySelector("[data-delete-plugin]");
|
||||
submitBtn.setAttribute("data-delete-plugin", JSON.stringify(deleteData));
|
||||
// Attach data to submit button (need to check attributs data-delete-plugin-submit)
|
||||
const submitBtn = document.querySelector("[data-delete-plugin-submit]");
|
||||
submitBtn.setAttribute("data-submit-form", JSON.stringify(deleteData));
|
||||
|
||||
// Prepare and show modal
|
||||
const modal = document.querySelector("#modal-delete-plugin");
|
||||
const modalPluginName = modal.querySelector("[data-modal-plugin-name]");
|
||||
modalPluginName.textContent = deleteData.name;
|
||||
modal.classList.remove("hidden");
|
||||
},
|
||||
true
|
||||
);
|
||||
|
|
@ -85,9 +96,11 @@ onBeforeMount(() => {
|
|||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
useForm();
|
||||
redirectPlugin();
|
||||
deletePlugin();
|
||||
});
|
||||
|
||||
const builder = [
|
||||
{
|
||||
type: "modal",
|
||||
|
|
@ -96,8 +109,53 @@ const builder = [
|
|||
{
|
||||
type: "Title",
|
||||
data: {
|
||||
title: "plugins_modal_delete",
|
||||
type: "card",
|
||||
title: "plugins_modal_delete_title",
|
||||
type: "modal",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "Text",
|
||||
data: {
|
||||
text: "plugins_modal_delete_confirm",
|
||||
textClass: "text-modal",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "Text",
|
||||
data: {
|
||||
text: "",
|
||||
textClass: "text-modal bold",
|
||||
attrs: {
|
||||
"data-modal-plugin-name": "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "ButtonGroup",
|
||||
data: {
|
||||
buttons: [
|
||||
{
|
||||
id: "delete-plugin-btn",
|
||||
text: "action_close",
|
||||
disabled: false,
|
||||
color: "close",
|
||||
size: "normal",
|
||||
attrs: {
|
||||
"data-hide-el": "modal-delete-plugin",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "delete-plugin-btn",
|
||||
text: "action_delete",
|
||||
disabled: false,
|
||||
color: "delete",
|
||||
size: "normal",
|
||||
attrs: {
|
||||
"data-delete-plugin-submit": "",
|
||||
},
|
||||
},
|
||||
],
|
||||
groupClass: "btn-group-modal",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
@ -185,6 +243,8 @@ const builder = [
|
|||
"data-plugin-id": "general",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "pro",
|
||||
"data-plugin-name": "General",
|
||||
},
|
||||
disabled: true,
|
||||
popovers: [
|
||||
|
|
@ -202,6 +262,8 @@ const builder = [
|
|||
"data-plugin-id": "antibot",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Antibot",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -219,6 +281,8 @@ const builder = [
|
|||
"data-plugin-id": "authbasic",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Auth basic",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -230,6 +294,8 @@ const builder = [
|
|||
"data-plugin-id": "backup",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "pro",
|
||||
"data-plugin-name": "Backup",
|
||||
},
|
||||
disabled: true,
|
||||
popovers: [
|
||||
|
|
@ -252,6 +318,8 @@ const builder = [
|
|||
"data-plugin-id": "badbehavior",
|
||||
"data-plugin-delete": "true",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "external",
|
||||
"data-plugin-name": "Bad behavior",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -274,6 +342,8 @@ const builder = [
|
|||
"data-plugin-id": "blacklist",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Blacklist",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -291,6 +361,8 @@ const builder = [
|
|||
"data-plugin-id": "brotli",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Brotli",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -302,6 +374,8 @@ const builder = [
|
|||
"data-plugin-id": "bunkernet",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "BunkerNet",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -319,6 +393,8 @@ const builder = [
|
|||
"data-plugin-id": "cors",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "CORS",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -336,6 +412,8 @@ const builder = [
|
|||
"data-plugin-id": "clientcache",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Client cache",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -347,6 +425,8 @@ const builder = [
|
|||
"data-plugin-id": "country",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Country",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -364,6 +444,8 @@ const builder = [
|
|||
"data-plugin-id": "customcert",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Custom HTTPS certificate",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -375,6 +457,8 @@ const builder = [
|
|||
"data-plugin-id": "db",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "DB",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -386,6 +470,8 @@ const builder = [
|
|||
"data-plugin-id": "dnsbl",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "DNSBL",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -403,6 +489,8 @@ const builder = [
|
|||
"data-plugin-id": "errors",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Errors",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -420,6 +508,8 @@ const builder = [
|
|||
"data-plugin-id": "greylist",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Greylist",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -437,6 +527,8 @@ const builder = [
|
|||
"data-plugin-id": "gzip",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Gzip",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -448,6 +540,8 @@ const builder = [
|
|||
"data-plugin-id": "inject",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "HTML injection",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -459,6 +553,8 @@ const builder = [
|
|||
"data-plugin-id": "headers",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Headers",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -470,6 +566,8 @@ const builder = [
|
|||
"data-plugin-id": "jobs",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Jobs",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -481,6 +579,8 @@ const builder = [
|
|||
"data-plugin-id": "letsencrypt",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Let's Encrypt",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -492,6 +592,8 @@ const builder = [
|
|||
"data-plugin-id": "limit",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Limit",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -509,6 +611,8 @@ const builder = [
|
|||
"data-plugin-id": "metrics",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Metrics",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -520,6 +624,8 @@ const builder = [
|
|||
"data-plugin-id": "misc",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Miscellaneous",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -537,6 +643,8 @@ const builder = [
|
|||
"data-plugin-id": "modsecurity",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "ModSecurity",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -548,6 +656,8 @@ const builder = [
|
|||
"data-plugin-id": "php",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "PHP",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -559,6 +669,8 @@ const builder = [
|
|||
"data-plugin-id": "pro",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Pro",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -570,6 +682,8 @@ const builder = [
|
|||
"data-plugin-id": "realip",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Real IP",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -581,6 +695,8 @@ const builder = [
|
|||
"data-plugin-id": "redirect",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Redirect",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -592,6 +708,8 @@ const builder = [
|
|||
"data-plugin-id": "redis",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Redis",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -609,6 +727,8 @@ const builder = [
|
|||
"data-plugin-id": "reverseproxy",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Reverse proxy",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -620,6 +740,8 @@ const builder = [
|
|||
"data-plugin-id": "reversescan",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Reverse scan",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
@ -637,6 +759,8 @@ const builder = [
|
|||
"data-plugin-id": "selfsigned",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Self-signed certificate",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -648,6 +772,8 @@ const builder = [
|
|||
"data-plugin-id": "sessions",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Sessions",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -659,6 +785,8 @@ const builder = [
|
|||
"data-plugin-id": "ui",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "UI",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [],
|
||||
|
|
@ -670,6 +798,8 @@ const builder = [
|
|||
"data-plugin-id": "whitelist",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Whitelist",
|
||||
},
|
||||
disabled: false,
|
||||
popovers: [
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { v4 as uuidv4 } from "uuid";
|
|||
/**
|
||||
@name useGlobal
|
||||
@description This function is a wrapper that contains all the global utils functions.
|
||||
This function will for example update the aria-expanded attribute of an element in case we have an aria-controls attribute.
|
||||
This function handle global click and keydown events to manage some states like show/hide elements, focus modals, and close modals.
|
||||
*/
|
||||
function useGlobal() {
|
||||
setShowHideElA11y();
|
||||
|
|
@ -19,6 +19,16 @@ function useGlobal() {
|
|||
// Update some states
|
||||
useShowEl(e);
|
||||
useHideEl(e);
|
||||
useFocusModal();
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
window.addEventListener(
|
||||
"keydown",
|
||||
(e) => {
|
||||
if (e.key === "Escape") useCloseModal();
|
||||
if (e.key === "Tab" || e.key === "Shift-Tab") useFocusModal();
|
||||
},
|
||||
true
|
||||
);
|
||||
|
|
@ -45,6 +55,27 @@ function setShowHideElA11y() {
|
|||
}, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
@name useHideEl
|
||||
@description This function will check if an element controls an element visibility and close it if it's the case.
|
||||
The element handler need to have a data-show-el attribute with the id of the target element as value.
|
||||
This function needs to be link to an event listener to work.
|
||||
This function will check if aria-controls and aria-expanded attributes are present, else will create them.
|
||||
@example
|
||||
<button data-close-el="modal">Close modal</button>
|
||||
<div id="modal" class="">Modal content</div>
|
||||
@param {Event} e - The event object.
|
||||
*/
|
||||
function useHideEl(e) {
|
||||
if (!e.target.hasAttribute("data-hide-el")) return;
|
||||
// hide
|
||||
const hideElId = e.target.getAttribute("data-hide-el");
|
||||
document.getElementById(hideElId).classList.add("hidden");
|
||||
// Update a11y attributes
|
||||
e.target.setAttribute("aria-controls", hideElId);
|
||||
e.target.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
|
||||
/**
|
||||
@name useShowEl
|
||||
@description This function will check if an element controls an element visibility and show it if it's the case.
|
||||
|
|
@ -67,24 +98,38 @@ function useShowEl(e) {
|
|||
}
|
||||
|
||||
/**
|
||||
@name useHideEl
|
||||
@description This function will check if an element controls an element visibility and close it if it's the case.
|
||||
The element handler need to have a data-show-el attribute with the id of the target element as value.
|
||||
This function needs to be link to an event listener to work.
|
||||
This function will check if aria-controls and aria-expanded attributes are present, else will create them.
|
||||
@example
|
||||
<button data-close-el="modal">Close modal</button>
|
||||
<div id="modal" class="">Modal content</div>
|
||||
@param {Event} e - The event object.
|
||||
@name useFocusModal
|
||||
@description This function check if a modal is present and a focusable element is present inside it.
|
||||
If it's the case, the function will focus the element.
|
||||
Case there is already a focused element inside the modal, avoid to focus it again.
|
||||
@param {String} modalId - The id of the modal element.
|
||||
*/
|
||||
function useHideEl(e) {
|
||||
if (!e.target.hasAttribute("data-hide-el")) return;
|
||||
// hide
|
||||
const hideElId = e.target.getAttribute("data-hide-el");
|
||||
document.getElementById(hideElId).classList.add("hidden");
|
||||
// Update a11y attributes
|
||||
e.target.setAttribute("aria-controls", hideElId);
|
||||
e.target.setAttribute("aria-expanded", "false");
|
||||
function useFocusModal() {
|
||||
setTimeout(() => {
|
||||
// Check if a data-modal element without hidden class is present
|
||||
const modalEl = document.querySelector("[data-modal]:not(.hidden)");
|
||||
if (!modalEl) return;
|
||||
// Get the current active element
|
||||
const activeEl = document.activeElement;
|
||||
// Check if the active element is inside the modal
|
||||
if (modalEl.contains(activeEl)) return;
|
||||
// Case not, focus first focusable element inside the modal
|
||||
const focusable = modalEl.querySelector("[tabindex]");
|
||||
if (focusable) focusable.focus();
|
||||
}, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@name useCloseModal
|
||||
@description This function check if a modal is present and will close it.
|
||||
This is a shortcut to close a modal when the escape key is pressed, for example.
|
||||
*/
|
||||
function useCloseModal() {
|
||||
// Check if a data-modal element without hidden class is present
|
||||
const modalEl = document.querySelector("[data-modal]:not(.hidden)");
|
||||
if (!modalEl) return;
|
||||
// Close the modal
|
||||
modalEl.classList.add("hidden");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -76,18 +76,18 @@ export default {
|
|||
"sm:justify-start",
|
||||
"md:justify-start",
|
||||
"lg:justify-start",
|
||||
"align-center",
|
||||
"sm:align-center",
|
||||
"md:align-center",
|
||||
"lg:align-center",
|
||||
"align-start",
|
||||
"sm:align-start",
|
||||
"md:align-start",
|
||||
"lg:align-start",
|
||||
"align-end",
|
||||
"sm:align-end",
|
||||
"md:align-end",
|
||||
"lg:align-end",
|
||||
"items-center",
|
||||
"sm:items-center",
|
||||
"md:items-center",
|
||||
"lg:items-center",
|
||||
"items-start",
|
||||
"sm:items-start",
|
||||
"md:items-start",
|
||||
"lg:items-start",
|
||||
"items-end",
|
||||
"sm:items-end",
|
||||
"md:items-end",
|
||||
"lg:items-end",
|
||||
"justify-content-center",
|
||||
"sm:justify-content-center",
|
||||
"md:justify-content-center",
|
||||
|
|
|
|||
|
|
@ -3021,8 +3021,11 @@ def plugins_builder(plugins, data={}):
|
|||
"attrs": {
|
||||
"data-plugin-id": plugin.get("id"),
|
||||
"data-plugin-delete": "true" if can_be_delete else "false",
|
||||
"data-plugin-redirect" : "true" if plugin.get("page", False) else "false",
|
||||
"data-plugin-redirect": (
|
||||
"true" if plugin.get("page", False) else "false"
|
||||
),
|
||||
"data-plugin-type": plugin.get("type", "").lower(),
|
||||
"data-plugin-name": plugin.get("name"),
|
||||
},
|
||||
"disabled": (
|
||||
True
|
||||
|
|
@ -3116,7 +3119,67 @@ def plugins_builder(plugins, data={}):
|
|||
},
|
||||
]
|
||||
|
||||
modal = {
|
||||
"type": "modal",
|
||||
"id": "modal-delete-plugin",
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "plugins_modal_delete_title",
|
||||
"type": "modal",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "plugins_modal_delete_confirm",
|
||||
"textClass": "text-modal",
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "",
|
||||
"textClass": "text-modal bold",
|
||||
"attrs": {
|
||||
"data-modal-plugin-name": "true",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "delete-plugin-btn",
|
||||
"text": "action_close",
|
||||
"disabled": False,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-hide-el": "modal-delete-plugin",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "delete-plugin-btn",
|
||||
"text": "action_delete",
|
||||
"disabled": False,
|
||||
"color": "delete",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-delete-plugin-submit": "",
|
||||
},
|
||||
},
|
||||
],
|
||||
"groupClass": "btn-group-modal",
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
builder = [
|
||||
modal,
|
||||
{
|
||||
"type": "card",
|
||||
"widgets": [
|
||||
|
|
|
|||
|
|
@ -1,4 +1,62 @@
|
|||
[
|
||||
{
|
||||
"type": "modal",
|
||||
"id": "modal-delete-plugin",
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "plugins_modal_delete_title",
|
||||
"type": "modal"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "plugins_modal_delete_confirm",
|
||||
"textClass": "text-modal"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "",
|
||||
"textClass": "text-modal bold",
|
||||
"attrs": {
|
||||
"data-modal-plugin-name": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "delete-plugin-btn",
|
||||
"text": "action_close",
|
||||
"disabled": false,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-hide-el": "modal-delete-plugin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "delete-plugin-btn",
|
||||
"text": "action_delete",
|
||||
"disabled": false,
|
||||
"color": "delete",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-delete-plugin-submit": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"groupClass": "btn-group-modal"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "card",
|
||||
"widgets": [
|
||||
|
|
@ -90,7 +148,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "general",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "pro",
|
||||
"data-plugin-name": "General"
|
||||
},
|
||||
"disabled": true,
|
||||
"popovers": [
|
||||
|
|
@ -107,7 +167,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "antibot",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Antibot"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -124,7 +186,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "authbasic",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Auth basic"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -135,7 +199,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "backup",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "pro",
|
||||
"data-plugin-name": "Backup"
|
||||
},
|
||||
"disabled": true,
|
||||
"popovers": [
|
||||
|
|
@ -157,7 +223,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "badbehavior",
|
||||
"data-plugin-delete": "true",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "external",
|
||||
"data-plugin-name": "Bad behavior"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -179,7 +247,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "blacklist",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Blacklist"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -196,7 +266,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "brotli",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Brotli"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -207,7 +279,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "bunkernet",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "BunkerNet"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -224,7 +298,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "cors",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "CORS"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -241,7 +317,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "clientcache",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Client cache"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -252,7 +330,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "country",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Country"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -269,7 +349,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "customcert",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Custom HTTPS certificate"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -280,7 +362,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "db",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "DB"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -291,7 +375,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "dnsbl",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "DNSBL"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -308,7 +394,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "errors",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Errors"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -325,7 +413,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "greylist",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Greylist"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -342,7 +432,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "gzip",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Gzip"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -353,7 +445,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "inject",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "HTML injection"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -364,7 +458,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "headers",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Headers"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -375,7 +471,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "jobs",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Jobs"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -386,7 +484,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "letsencrypt",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Let's Encrypt"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -397,7 +497,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "limit",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Limit"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -414,7 +516,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "metrics",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Metrics"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -425,7 +529,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "misc",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Miscellaneous"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -442,7 +548,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "modsecurity",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "ModSecurity"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -453,7 +561,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "php",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "PHP"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -464,7 +574,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "pro",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Pro"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -475,7 +587,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "realip",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Real IP"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -486,7 +600,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "redirect",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Redirect"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -497,7 +613,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "redis",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Redis"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -514,7 +632,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "reverseproxy",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Reverse proxy"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -525,7 +645,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "reversescan",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Reverse scan"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
@ -542,7 +664,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "selfsigned",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Self-signed certificate"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -553,7 +677,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "sessions",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Sessions"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -564,7 +690,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "ui",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "false"
|
||||
"data-plugin-redirect": "false",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "UI"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": []
|
||||
|
|
@ -575,7 +703,9 @@
|
|||
"attrs": {
|
||||
"data-plugin-id": "whitelist",
|
||||
"data-plugin-delete": "false",
|
||||
"data-plugin-redirect": "true"
|
||||
"data-plugin-redirect": "true",
|
||||
"data-plugin-type": "core",
|
||||
"data-plugin-name": "Whitelist"
|
||||
},
|
||||
"disabled": false,
|
||||
"popovers": [
|
||||
|
|
|
|||
Loading…
Reference in a new issue