mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
refactor utils and update modal component
* add utils to check widget type * remove useless utils and move others to modal component
This commit is contained in:
parent
ff0493aa10
commit
27f55edf3c
27 changed files with 659 additions and 372 deletions
|
|
@ -7,6 +7,7 @@ import Subtitle from "@components/Widget/Subtitle.vue";
|
|||
import Table from "@components/Widget/Table.vue";
|
||||
import ListPairs from "@components/List/Pairs.vue";
|
||||
import MessageUnmatch from "@components/Message/Unmatch.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/Bans.vue
|
||||
|
|
@ -47,23 +48,17 @@ const props = defineProps({
|
|||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in container.widgets" :key="index">
|
||||
<MessageUnmatch
|
||||
v-if="widget.type.toLowerCase() === 'messageunmatch'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title
|
||||
v-if="widget.type.toLowerCase() === 'title'"
|
||||
v-if="useEqualStr(widget.type, 'MessageUnmatch')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title v-if="useEqualStr(widget.type, 'Title')" v-bind="widget.data" />
|
||||
<Subtitle
|
||||
v-if="widget.type.toLowerCase() === 'subtitle'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Table
|
||||
v-if="widget.type.toLowerCase() === 'table'"
|
||||
v-if="useEqualStr(widget.type, 'Subtitle')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Table v-if="useEqualStr(widget.type, 'Table')" v-bind="widget.data" />
|
||||
<ListPairs
|
||||
v-if="widget.type.toLowerCase() === 'listpairs'"
|
||||
v-if="useEqualStr(widget.type, 'ListPairs')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import GridLayout from "@components/Widget/GridLayout.vue";
|
|||
import Title from "@components/Widget/Title.vue";
|
||||
import Subtitle from "@components/Widget/Subtitle.vue";
|
||||
import Templates from "@components/Form/Templates.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/GlobalConfig.vue
|
||||
|
|
@ -62,16 +63,13 @@ const props = defineProps({
|
|||
<Grid>
|
||||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in container.widgets" :key="index">
|
||||
<Title
|
||||
v-if="widget.type.toLowerCase() === 'title'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title v-if="useEqualStr(widget.type, 'Title')" v-bind="widget.data" />
|
||||
<Subtitle
|
||||
v-if="widget.type.toLowerCase() === 'subtitle'"
|
||||
v-if="useEqualStr(widget.type, 'Subtitle')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Templates
|
||||
v-if="widget.type.toLowerCase() === 'templates'"
|
||||
v-if="useEqualStr(widget.type, 'Templates')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import Grid from "@components/Widget/Grid.vue";
|
||||
import GridLayout from "@components/Widget/GridLayout.vue";
|
||||
import Stat from "@components/Widget/Stat.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/Home.vue
|
||||
|
|
@ -54,10 +55,7 @@ const props = defineProps({
|
|||
<Grid>
|
||||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in container.widgets" :key="index">
|
||||
<Stat
|
||||
v-if="widget.type.toLowerCase() === 'stat'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Stat v-if="useEqualStr(widget.type, 'Stat')" v-bind="widget.data" />
|
||||
</template>
|
||||
</Grid>
|
||||
</GridLayout>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import Grid from "@components/Widget/Grid.vue";
|
||||
import GridLayout from "@components/Widget/GridLayout.vue";
|
||||
import Instance from "@components/Widget/Instance.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/Instances.vue
|
||||
|
|
@ -58,7 +59,7 @@ const props = defineProps({
|
|||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in container.widgets" :key="index">
|
||||
<Instance
|
||||
v-if="widget.type.toLowerCase() === 'instance'"
|
||||
v-if="useEqualStr(widget.type, 'Instance')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import Grid from "@components/Widget/Grid.vue";
|
|||
import GridLayout from "@components/Widget/GridLayout.vue";
|
||||
import Table from "@components/Widget/Table.vue";
|
||||
import Title from "@components/Widget/Title.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/Jobs.vue
|
||||
|
|
@ -84,14 +85,8 @@ const props = defineProps({
|
|||
<Grid>
|
||||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in container.widgets" :key="index">
|
||||
<Table
|
||||
v-if="widget.type.toLowerCase() === 'table'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title
|
||||
v-if="widget.type.toLowerCase() === 'title'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Table v-if="useEqualStr(widget.type, 'Table')" v-bind="widget.data" />
|
||||
<Title v-if="useEqualStr(widget.type, 'Title')" v-bind="widget.data" />
|
||||
</template>
|
||||
</Grid>
|
||||
</GridLayout>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ 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";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/PLugin.vue
|
||||
|
|
@ -69,20 +70,14 @@ const props = defineProps({
|
|||
<Grid>
|
||||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in container.widgets" :key="index">
|
||||
<Title
|
||||
v-if="widget.type.toLowerCase() === 'title'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title v-if="useEqualStr(widget.type, 'Title')" v-bind="widget.data" />
|
||||
<ListDetails
|
||||
v-if="widget.type.toLowerCase() === 'listdetails'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Text
|
||||
v-if="widget.type.toLowerCase() === 'text'"
|
||||
v-if="useEqualStr(widget.type, 'ListDetails')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Text v-if="useEqualStr(widget.type, 'Text')" v-bind="widget.data" />
|
||||
<ButtonGroup
|
||||
v-if="widget.type.toLowerCase() === 'buttongroup'"
|
||||
v-if="useEqualStr(widget.type, 'ButtonGroup')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import Subtitle from "@components/Widget/Subtitle.vue";
|
|||
import Table from "@components/Widget/Table.vue";
|
||||
import ListPairs from "@components/List/Pairs.vue";
|
||||
import MessageUnmatch from "@components/Message/Unmatch.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/Reports.vue
|
||||
|
|
@ -47,23 +48,17 @@ const props = defineProps({
|
|||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in container.widgets" :key="index">
|
||||
<MessageUnmatch
|
||||
v-if="widget.type.toLowerCase() === 'messageunmatch'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title
|
||||
v-if="widget.type.toLowerCase() === 'title'"
|
||||
v-if="useEqualStr(widget.type, 'messageunmatch')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title v-if="useEqualStr(widget.type, 'title')" v-bind="widget.data" />
|
||||
<Subtitle
|
||||
v-if="widget.type.toLowerCase() === 'subtitle'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Table
|
||||
v-if="widget.type.toLowerCase() === 'table'"
|
||||
v-if="useEqualStr(widget.type, 'subtitle')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Table v-if="useEqualStr(widget.type, 'table')" v-bind="widget.data" />
|
||||
<ListPairs
|
||||
v-if="widget.type.toLowerCase() === 'listpairs'"
|
||||
v-if="useEqualStr(widget.type, 'listpairs')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import Grid from "@components/Widget/Grid.vue";
|
|||
import GridLayout from "@components/Widget/GridLayout.vue";
|
||||
import Table from "@components/Widget/Table.vue";
|
||||
import Title from "@components/Widget/Title.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/Services.vue
|
||||
|
|
@ -314,14 +315,8 @@ const props = defineProps({
|
|||
<Grid>
|
||||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in container.widgets" :key="index">
|
||||
<Table
|
||||
v-if="widget.type.toLowerCase() === 'table'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title
|
||||
v-if="widget.type.toLowerCase() === 'title'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Table v-if="useEqualStr(widget.type, 'table')" v-bind="widget.data" />
|
||||
<Title v-if="useEqualStr(widget.type, 'title')" v-bind="widget.data" />
|
||||
</template>
|
||||
</Grid>
|
||||
</GridLayout>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Containers
|
||||
import Grid from "@components/Widget/Grid.vue";
|
||||
import GridLayout from "@components/Widget/GridLayout.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/Setup.vue
|
||||
|
|
|
|||
|
|
@ -1,11 +1,19 @@
|
|||
<script setup>
|
||||
import { computed, ref, reactive, onBeforeMount } from "vue";
|
||||
import {
|
||||
computed,
|
||||
ref,
|
||||
reactive,
|
||||
onBeforeMount,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
watch,
|
||||
} from "vue";
|
||||
import Modal from "@components/Widget/Modal.vue";
|
||||
import { contentIndex } from "@utils/tabindex.js";
|
||||
import Container from "@components/Widget/Container.vue";
|
||||
import Icons from "@components/Widget/Icons.vue";
|
||||
import { useUUID } from "@utils/global.js";
|
||||
|
||||
import { useForm } from "@utils/form.js";
|
||||
/**
|
||||
@name Widget/Button.vue
|
||||
@description This component is a standard button.
|
||||
|
|
@ -125,11 +133,33 @@ const buttonClass = computed(() => {
|
|||
onBeforeMount(() => {
|
||||
btn.id = useUUID(props.id);
|
||||
// Case modal, add accessibility data
|
||||
if (props.modal) {
|
||||
btnEl.value.setAttribute("data-target", `#${btn.modalId}`);
|
||||
btnEl.value.setAttribute("aria-expanded", btn.openModal ? "true" : "false");
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener("click", useForm);
|
||||
// Case modal, add accessibility data
|
||||
if (typeof props.modal === "object") {
|
||||
btnEl.value.setAttribute("aria-controls", btn.modalId);
|
||||
btnEl.value.setAttribute(
|
||||
"aria-expanded",
|
||||
props.openModal ? "true" : "false"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// watch openModal to add accessibility data
|
||||
watch(
|
||||
() => btn.openModal,
|
||||
(value) => {
|
||||
if (typeof props.modal === "object") {
|
||||
btnEl.value.setAttribute("aria-expanded", value ? "true" : "false");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("click", useForm);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -146,7 +176,7 @@ onBeforeMount(() => {
|
|||
@click="
|
||||
(e) => {
|
||||
if (e.target.getAttribute('type') !== 'submit') e.preventDefault();
|
||||
if (props.modal) {
|
||||
if (typeof props.modal === 'object') {
|
||||
btn.openModal = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -173,12 +203,12 @@ onBeforeMount(() => {
|
|||
:disabled="props.disabled || false"
|
||||
/>
|
||||
</button>
|
||||
|
||||
<Modal
|
||||
:id="`${btn.id}-modal`"
|
||||
v-if="btn.openModal"
|
||||
:widgets="props.modal.widgets"
|
||||
:isOpen="btn.openModal"
|
||||
/>
|
||||
</Container>
|
||||
<Modal
|
||||
:aria-hidden="btn.openModal ? 'false' : 'true'"
|
||||
:id="`${btn.id}-modal`"
|
||||
v-if="btn.openModal"
|
||||
:isOpen="btn.openModal"
|
||||
@close="() => (btn.openModal = false)"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import Icons from "@components/Widget/Icons.vue";
|
|||
import Fields from "@components/Form/Fields.vue";
|
||||
import Button from "@components/Widget/Button.vue";
|
||||
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
@name Builder/Cell.vue
|
||||
|
|
@ -43,9 +44,12 @@ const cell = reactive({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<Text v-if="cell.name === 'text'" v-bind="props.data" />
|
||||
<Icons v-if="cell.name === 'icons'" v-bind="props.data" />
|
||||
<Fields v-if="cell.name === 'fields'" v-bind="props.data" />
|
||||
<Button v-if="cell.name === 'button'" v-bind="props.data" />
|
||||
<ButtonGroup v-if="cell.name === 'buttongroup'" v-bind="props.data" />
|
||||
<Text v-if="useEqualStr(cell.name, 'Text')" v-bind="props.data" />
|
||||
<Icons v-if="useEqualStr(cell.name, 'Icons')" v-bind="props.data" />
|
||||
<Fields v-if="useEqualStr(cell.name, 'Fields')" v-bind="props.data" />
|
||||
<Button v-if="useEqualStr(cell.name, 'Button')" v-bind="props.data" />
|
||||
<ButtonGroup
|
||||
v-if="useEqualStr(cell.name, 'ButtonGroup')"
|
||||
v-bind="props.data"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,14 @@
|
|||
<script setup>
|
||||
import { defineProps, defineEmits } from "vue";
|
||||
import {
|
||||
defineProps,
|
||||
defineEmits,
|
||||
Teleport,
|
||||
ref,
|
||||
watch,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
} from "vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
// Containers
|
||||
import Grid from "@components/Widget/Grid.vue";
|
||||
import Title from "@components/Widget/Title.vue";
|
||||
|
|
@ -80,7 +89,7 @@ const props = defineProps({
|
|||
default: "",
|
||||
},
|
||||
widgets: {
|
||||
type: Array,
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isOpen: {
|
||||
|
|
@ -90,60 +99,117 @@ const props = defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
const modalEl = ref();
|
||||
|
||||
function useCloseModal() {
|
||||
emits("close");
|
||||
}
|
||||
|
||||
/**
|
||||
@name useFocusModal
|
||||
@description Check if the 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.
|
||||
@returns {void}
|
||||
*/
|
||||
function useFocusModal() {
|
||||
setTimeout(() => {
|
||||
if (!modalEl.value) return;
|
||||
// Get the current active element
|
||||
const activeEl = document.activeElement;
|
||||
// Check if the active element is inside the modal
|
||||
if (modalEl.value.contains(activeEl)) return;
|
||||
// Case not, focus first focusable element inside the modal
|
||||
const focusable = modalEl.value.querySelector("[tabindex]");
|
||||
if (focusable) focusable.focus();
|
||||
}, 1);
|
||||
}
|
||||
|
||||
function modalKeyboardEvents(e) {
|
||||
if (e.key === "Escape") useCloseModal();
|
||||
if (e.key === "Tab" || e.key === "Shift-Tab") useFocusModal();
|
||||
}
|
||||
|
||||
function modalClickEvents(e) {
|
||||
if (e.target.closest("[data-modal]") !== modalEl.value && modalEl.value)
|
||||
return;
|
||||
if (e.target.hasAttribute("data-close-modal")) useCloseModal();
|
||||
}
|
||||
|
||||
function setEvents() {
|
||||
window.addEventListener("keydown", modalKeyboardEvents, true);
|
||||
window.addEventListener("click", modalClickEvents);
|
||||
}
|
||||
|
||||
function unsetEvents() {
|
||||
window.removeEventListener("keydown", modalKeyboardEvents, true);
|
||||
window.removeEventListener("click", modalClickEvents);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setEvents();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
unsetEvents();
|
||||
});
|
||||
|
||||
const emits = defineEmits(["close"]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:data-is="'modal'"
|
||||
data-modal
|
||||
:class="['layout-modal-container', props.isOpen ? '' : 'hidden']"
|
||||
class="layout-modal-container hidden"
|
||||
:id="props.id"
|
||||
>
|
||||
<div class="layout-backdrop"></div>
|
||||
<div class="layout-modal-wrap" :data-hide-el="props.id">
|
||||
<div class="layout-modal">
|
||||
<div class="layout-modal-button-container">
|
||||
<Button
|
||||
@click="$emit('close')"
|
||||
:attrs="{ 'data-hide-el': props.id }"
|
||||
:text="'action_close_modal'"
|
||||
:hideText="true"
|
||||
:iconName="'close'"
|
||||
:color="'transparent'"
|
||||
/>
|
||||
</div>
|
||||
<Grid>
|
||||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in props.widgets" :key="index">
|
||||
<MessageUnmatch
|
||||
v-if="widget.type.toLowerCase() === 'messageunmatch'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title
|
||||
v-if="widget.type.toLowerCase() === 'title'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Text
|
||||
v-if="widget.type.toLowerCase() === 'text'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Subtitle
|
||||
v-if="widget.type.toLowerCase() === 'subtitle'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Teleport to="#app">
|
||||
<div
|
||||
ref="modalEl"
|
||||
:data-is="'modal'"
|
||||
data-modal
|
||||
:class="['layout-modal-container', props.isOpen ? '' : 'hidden']"
|
||||
:id="props.id"
|
||||
>
|
||||
<div data-close-modal class="layout-backdrop"></div>
|
||||
<div class="layout-modal-wrap">
|
||||
<div class="layout-modal">
|
||||
<div class="layout-modal-button-container">
|
||||
<Button
|
||||
v-if="widget.type.toLowerCase() === 'button'"
|
||||
v-bind="widget.data"
|
||||
data-close-modal
|
||||
:text="'action_close_modal'"
|
||||
:hideText="true"
|
||||
:iconName="'close'"
|
||||
:color="'transparent'"
|
||||
/>
|
||||
<ButtonGroup
|
||||
v-if="widget.type.toLowerCase() === 'buttongroup'"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
<Grid>
|
||||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in props.widgets">
|
||||
<MessageUnmatch
|
||||
v-if="useEqualStr(widget.type, 'MessageUnmatch')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Title
|
||||
v-if="useEqualStr(widget.type, 'Title')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Text
|
||||
v-if="useEqualStr(widget.type, 'Text')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Subtitle
|
||||
v-if="useEqualStr(widget.type, 'Subtitle')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Button
|
||||
v-if="useEqualStr(widget.type, 'Button')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<ButtonGroup
|
||||
v-if="useEqualStr(widget.type, 'ButtonGroup')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
</template>
|
||||
</Grid>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
<script setup>
|
||||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import { reactive, onBeforeMount } from "vue";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderBans from "@components/Builder/Bans.vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import { useForm } from "@utils/form.js";
|
||||
|
||||
/**
|
||||
@name Page/Bans.vue
|
||||
|
|
@ -26,11 +24,6 @@ onBeforeMount(() => {
|
|||
bans.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
useForm();
|
||||
});
|
||||
|
||||
const builder = [
|
||||
{
|
||||
type: "void",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script setup>
|
||||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderGlobalConfig from "@components/Builder/GlobalConfig.vue";
|
||||
|
||||
|
|
@ -24,10 +23,6 @@ onBeforeMount(() => {
|
|||
: {};
|
||||
globalConfig.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script setup>
|
||||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderHome from "@components/Builder/Home.vue";
|
||||
|
||||
|
|
@ -25,10 +24,6 @@ onBeforeMount(() => {
|
|||
home.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
});
|
||||
|
||||
// const data = [
|
||||
// {
|
||||
// type: "card",
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderInstances from "@components/Builder/Instances.vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import { useForm } from "@utils/form.js";
|
||||
|
||||
/**
|
||||
@name Page/Instances.vue
|
||||
|
|
@ -26,11 +24,6 @@ onBeforeMount(() => {
|
|||
instances.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
useForm();
|
||||
});
|
||||
|
||||
// const data = [
|
||||
// {
|
||||
// type: "Instance",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script setup>
|
||||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderJobs from "@components/Builder/Jobs.vue";
|
||||
|
||||
|
|
@ -88,7 +87,6 @@ function downloadCacheEvent() {
|
|||
}
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
downloadCacheEvent();
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
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";
|
||||
|
||||
/**
|
||||
|
|
@ -98,8 +97,6 @@ onBeforeMount(() => {
|
|||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
useForm();
|
||||
redirectPlugin();
|
||||
deletePlugin();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderReports from "@components/Builder/Reports.vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import { useForm } from "@utils/form.js";
|
||||
|
||||
/**
|
||||
@name Page/Reports.vue
|
||||
|
|
@ -26,11 +24,6 @@ onBeforeMount(() => {
|
|||
reports.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
useForm();
|
||||
});
|
||||
|
||||
const builder = [
|
||||
{
|
||||
type: "card",
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -2,8 +2,6 @@
|
|||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderServices from "@components/Builder/Services.vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import { useForm } from "@utils/form.js";
|
||||
|
||||
/**
|
||||
@name Page/Services.vue
|
||||
|
|
@ -25,11 +23,6 @@ onBeforeMount(() => {
|
|||
: {};
|
||||
services.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
useForm();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -6,20 +6,18 @@
|
|||
|
||||
/**
|
||||
@name useForm
|
||||
@description This function is a composable wrapper that contains all the form utils functions.
|
||||
This function will for example look for JSON-type in the data-submit-form attribute of an element and submit the form with the data object.
|
||||
@description This function needs to be attach to an event like a click event.
|
||||
This will check if the target element contains a data-submit-form attribute and try to parse it to submit the form.
|
||||
@returns {void}
|
||||
*/
|
||||
function useForm() {
|
||||
window.addEventListener("click", (e) => {
|
||||
if (!e.target.hasAttribute("data-submit-form")) return;
|
||||
try {
|
||||
const data = JSON.parse(e.target.getAttribute("data-submit-form"));
|
||||
useSubmitForm(data);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
function useForm(e) {
|
||||
if (!e.target.hasAttribute("data-submit-form")) return;
|
||||
try {
|
||||
const data = JSON.parse(e.target.getAttribute("data-submit-form"));
|
||||
useSubmitForm(data);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -6,167 +6,13 @@ import { v4 as uuidv4 } from "uuid";
|
|||
This file contains functions related to accessibilities, cookies, and other global utils.
|
||||
*/
|
||||
|
||||
/**
|
||||
@name useGlobal
|
||||
@description This function is a wrapper that contains all the global utils functions.
|
||||
This function handle global click and keydown events to manage some states like show/hide elements, focus modals, and close modals.
|
||||
@returns {void}
|
||||
*/
|
||||
function useGlobal() {
|
||||
setShowHideElA11y();
|
||||
window.addEventListener(
|
||||
"click",
|
||||
(e) => {
|
||||
// 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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@name setShowHideElA11y
|
||||
@description This function will check if aria-controls and aria-expanded attributes are present on elements that controls an element visibility.
|
||||
Case they are not present, the function will create them.
|
||||
@returns {void}
|
||||
*/
|
||||
function setShowHideElA11y() {
|
||||
// Wait that elements are mounted and ids are set
|
||||
setTimeout(() => {
|
||||
const els = document.querySelectorAll("[data-show-el], [data-hide-el]");
|
||||
els.forEach((el) => {
|
||||
const id =
|
||||
el.getAttribute("data-show-el") || el.getAttribute("data-hide-el");
|
||||
// Check current state of the element target
|
||||
const targetEl = document.getElementById(id);
|
||||
if (!targetEl) return;
|
||||
el.setAttribute("aria-controls", id);
|
||||
el.setAttribute("aria-expanded", isElHidden(targetEl) ? "false" : "true");
|
||||
});
|
||||
}, 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.
|
||||
@returns {void}
|
||||
*/
|
||||
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.
|
||||
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-show-el="modal">Open modal</button>
|
||||
<div id="modal" class="hidden">Modal content</div>
|
||||
@param {Event} e - The event object.
|
||||
@returns {void}
|
||||
*/
|
||||
function useShowEl(e) {
|
||||
if (!e.target.hasAttribute("data-show-el")) return;
|
||||
// show
|
||||
const showElId = e.target.getAttribute("data-show-el");
|
||||
document.getElementById(showElId).classList.remove("hidden");
|
||||
// Update a11y attributes
|
||||
e.target.setAttribute("aria-controls", showElId);
|
||||
e.target.setAttribute("aria-expanded", "true");
|
||||
}
|
||||
|
||||
/**
|
||||
@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.
|
||||
@returns {void}
|
||||
*/
|
||||
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.
|
||||
@returns {void}
|
||||
*/
|
||||
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");
|
||||
}
|
||||
|
||||
/**
|
||||
@name isElHidden
|
||||
@description This function is a util that checks if an element is hidden.
|
||||
This will check for multiple ways to hide an element like aria-hidden, hidden class, display none, visibility hidden, and !hidden class.
|
||||
@returns {boolean} - True if the element is hidden, false if not.
|
||||
*/
|
||||
function isElHidden(el) {
|
||||
return el.hasAttribute("aria-hidden")
|
||||
? el.getAttribute("aria-hidden") === "true"
|
||||
? true
|
||||
: false
|
||||
: el.classList.contains("hidden")
|
||||
? true
|
||||
: el.style.display === "none"
|
||||
? true
|
||||
: el.style.visibility === "hidden"
|
||||
? true
|
||||
: el.classList.contains("!hidden")
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
@name useUUID
|
||||
@description This function return a unique identifier using uuidv4 and a random number.
|
||||
Adding random number to avoid duplicate uuids when some components are rendered at the same time.
|
||||
We can pass a possible existing id, the function will only generate one if the id is empty.
|
||||
@param {String} [id=""] - Possible existing id, check if it's empty to generate a new one.
|
||||
@retrurns {String} - The unique identifier.
|
||||
@param {string} [id=""] - Possible existing id, check if it's empty to generate a new one.
|
||||
@returns {string} - The unique identifier.
|
||||
*/
|
||||
function useUUID(id = "") {
|
||||
if (id) return id;
|
||||
|
|
@ -176,4 +22,21 @@ function useUUID(id = "") {
|
|||
return uuidv4() + random;
|
||||
}
|
||||
|
||||
export { useGlobal, useUUID };
|
||||
/**
|
||||
@name useEqualStr
|
||||
@description Get the type of a widget and format it to lowercase if possible. Else return an empty string.
|
||||
@param {any} type - Try to convert the type to a string in lowercase to compare it with wanted value.
|
||||
@param {string} compare - The value to compare with, in general the component name.
|
||||
@returns {boolean} - True if matching, false if not.
|
||||
*/
|
||||
function useEqualStr(type, compare) {
|
||||
// Check if valid string or can be converted to string
|
||||
try {
|
||||
return String(type).toLowerCase() === compare.toLowerCase() ? true : false;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export { useUUID, useEqualStr };
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
<script setup>
|
||||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
import BuilderSetup from "@components/Builder/Setup.vue";
|
||||
|
||||
/**
|
||||
|
|
@ -23,10 +22,6 @@ onBeforeMount(() => {
|
|||
: {};
|
||||
setup.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,34 @@
|
|||
"color": "info",
|
||||
"size": "normal",
|
||||
"iconName": "settings",
|
||||
"iconColor": "white"
|
||||
"iconColor": "white",
|
||||
"modal": {
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "services_settings_title"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "close-service-btn-app1.example.com",
|
||||
"text": "action_close",
|
||||
"disabled": false,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-close-modal": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
|
|
@ -67,7 +94,74 @@
|
|||
"color": "success",
|
||||
"size": "normal",
|
||||
"iconName": "gear",
|
||||
"iconColor": "white"
|
||||
"iconColor": "white",
|
||||
"modal": {
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "services_manage_title"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "manage-service-btn-app1.example.com",
|
||||
"text": "services_easy",
|
||||
"disabled": false,
|
||||
"color": "green",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"role": "link",
|
||||
"data-link": "services/easy/app1.example.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "manage-service-btn-app1.example.com",
|
||||
"text": "services_advanced",
|
||||
"disabled": false,
|
||||
"color": "green",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"role": "link",
|
||||
"data-link": "services/advanced/app1.example.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "manage-service-btn-app1.example.com",
|
||||
"text": "services_raw",
|
||||
"disabled": false,
|
||||
"color": "green",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"role": "link",
|
||||
"data-link": "services/raw/app1.example.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "close-service-btn-app1.example.com",
|
||||
"text": "action_close",
|
||||
"disabled": false,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-close-modal": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
|
|
@ -80,7 +174,57 @@
|
|||
"color": "cyan",
|
||||
"size": "normal",
|
||||
"iconName": "globe",
|
||||
"iconColor": "white"
|
||||
"iconColor": "white",
|
||||
"modal": {
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "services_edit_title"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "services_edit_subtitle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "app1.example.com",
|
||||
"bold": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "close-service-btn-app1.example.com",
|
||||
"text": "action_close",
|
||||
"disabled": false,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-close-modal": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "edit-service-btn-app1.example.com",
|
||||
"text": "action_edit",
|
||||
"disabled": false,
|
||||
"color": "cyan",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-submit-form": "{\"SERVER_NAME\" : app1.example.com, \"OLD_SERVER_NAME\" : app1.example.com, \"operation\" : \"edit\", \"IS_DRAFT\" : no }"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
|
|
@ -93,7 +237,57 @@
|
|||
"color": "red",
|
||||
"size": "normal",
|
||||
"iconName": "trash",
|
||||
"iconColor": "white"
|
||||
"iconColor": "white",
|
||||
"modal": {
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "services_delete_title"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "services_delete_subtitle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "app1.example.com",
|
||||
"bold": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "close-service-btn-app1.example.com",
|
||||
"text": "action_close",
|
||||
"disabled": false,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-close-modal": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "delete-service-btn-app1.example.com",
|
||||
"text": "action_delete",
|
||||
"disabled": false,
|
||||
"color": "delete",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-submit-form": "{\"SERVER_NAME\" : app1.example.com, \"operation\" : \"delete\" }"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -125,7 +319,34 @@
|
|||
"color": "info",
|
||||
"size": "normal",
|
||||
"iconName": "settings",
|
||||
"iconColor": "white"
|
||||
"iconColor": "white",
|
||||
"modal": {
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "services_settings_title"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "close-service-btn-www.example.com",
|
||||
"text": "action_close",
|
||||
"disabled": false,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-close-modal": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
|
|
@ -137,7 +358,74 @@
|
|||
"color": "success",
|
||||
"size": "normal",
|
||||
"iconName": "gear",
|
||||
"iconColor": "white"
|
||||
"iconColor": "white",
|
||||
"modal": {
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "services_manage_title"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "manage-service-btn-www.example.com",
|
||||
"text": "services_easy",
|
||||
"disabled": false,
|
||||
"color": "green",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"role": "link",
|
||||
"data-link": "services/easy/www.example.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "manage-service-btn-www.example.com",
|
||||
"text": "services_advanced",
|
||||
"disabled": false,
|
||||
"color": "green",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"role": "link",
|
||||
"data-link": "services/advanced/www.example.com"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "manage-service-btn-www.example.com",
|
||||
"text": "services_raw",
|
||||
"disabled": false,
|
||||
"color": "green",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"role": "link",
|
||||
"data-link": "services/raw/www.example.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "close-service-btn-www.example.com",
|
||||
"text": "action_close",
|
||||
"disabled": false,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-close-modal": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
|
|
@ -150,7 +438,57 @@
|
|||
"color": "cyan",
|
||||
"size": "normal",
|
||||
"iconName": "globe",
|
||||
"iconColor": "white"
|
||||
"iconColor": "white",
|
||||
"modal": {
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "services_edit_title"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "services_edit_subtitle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "www.example.com",
|
||||
"bold": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "close-service-btn-www.example.com",
|
||||
"text": "action_close",
|
||||
"disabled": false,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-close-modal": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "edit-service-btn-www.example.com",
|
||||
"text": "action_edit",
|
||||
"disabled": false,
|
||||
"color": "cyan",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-submit-form": "{\"SERVER_NAME\" : www.example.com, \"OLD_SERVER_NAME\" : www.example.com, \"operation\" : \"edit\", \"IS_DRAFT\" : no }"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
|
|
@ -163,7 +501,57 @@
|
|||
"color": "red",
|
||||
"size": "normal",
|
||||
"iconName": "trash",
|
||||
"iconColor": "white"
|
||||
"iconColor": "white",
|
||||
"modal": {
|
||||
"widgets": [
|
||||
{
|
||||
"type": "Title",
|
||||
"data": {
|
||||
"title": "services_delete_title"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "services_delete_subtitle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Text",
|
||||
"data": {
|
||||
"text": "www.example.com",
|
||||
"bold": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": [
|
||||
{
|
||||
"id": "close-service-btn-www.example.com",
|
||||
"text": "action_close",
|
||||
"disabled": false,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-close-modal": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "delete-service-btn-www.example.com",
|
||||
"text": "action_delete",
|
||||
"disabled": false,
|
||||
"color": "delete",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"data-submit-form": "{\"SERVER_NAME\" : www.example.com, \"operation\" : \"delete\" }"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ def services_action(server_name: str = "", operation: str = "", title: str = "",
|
|||
"disabled": False,
|
||||
"color": "close",
|
||||
"size": "normal",
|
||||
"attrs": {"data-close-modal": ""},
|
||||
},
|
||||
]
|
||||
|
||||
|
|
@ -101,7 +102,6 @@ def services_action(server_name: str = "", operation: str = "", title: str = "",
|
|||
"type": "Title",
|
||||
"data": {
|
||||
"title": title,
|
||||
"type": "modal",
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
@ -128,26 +128,29 @@ def services_action(server_name: str = "", operation: str = "", title: str = "",
|
|||
|
||||
if operation == "manage":
|
||||
modes = ("easy", "advanced", "raw")
|
||||
mode_buttons = []
|
||||
for mode in modes:
|
||||
content.append(
|
||||
mode_buttons.append(
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {
|
||||
"buttons": {
|
||||
"id": f"{operation}-service-btn-{server_name}",
|
||||
"text": f"services_{mode}",
|
||||
"disabled": False,
|
||||
"color": "green",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"role": "link",
|
||||
"data-link": f"services/{mode}/{server_name}",
|
||||
},
|
||||
},
|
||||
"id": f"{operation}-service-btn-{server_name}",
|
||||
"text": f"services_{mode}",
|
||||
"disabled": False,
|
||||
"color": "green",
|
||||
"size": "normal",
|
||||
"attrs": {
|
||||
"role": "link",
|
||||
"data-link": f"services/{mode}/{server_name}",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
content.append(
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
"data": {"buttons": mode_buttons},
|
||||
}
|
||||
)
|
||||
|
||||
content.append(
|
||||
{
|
||||
"type": "ButtonGroup",
|
||||
|
|
@ -156,8 +159,6 @@ def services_action(server_name: str = "", operation: str = "", title: str = "",
|
|||
)
|
||||
|
||||
modal = {
|
||||
"type": "modal",
|
||||
"id": f"modal-{operation}-{server_name}",
|
||||
"widgets": content,
|
||||
}
|
||||
|
||||
|
|
@ -189,6 +190,9 @@ def get_services_list(services):
|
|||
"size": "normal",
|
||||
"iconName": "settings",
|
||||
"iconColor": "white",
|
||||
"modal": services_action(
|
||||
server_name=server_name, operation="settings", title="services_settings_title", subtitle="services_settings_subtitle"
|
||||
),
|
||||
},
|
||||
{
|
||||
"attrs": {"data-server-name": server_name},
|
||||
|
|
@ -199,6 +203,9 @@ def get_services_list(services):
|
|||
"size": "normal",
|
||||
"iconName": "gear",
|
||||
"iconColor": "white",
|
||||
"modal": services_action(
|
||||
server_name=server_name, operation="manage", title="services_manage_title", subtitle="services_manage_subtitle"
|
||||
),
|
||||
},
|
||||
{
|
||||
"attrs": {"data-server-name": server_name, "data-is-draft": "yes" if is_draft else "no"},
|
||||
|
|
@ -209,6 +216,9 @@ def get_services_list(services):
|
|||
"size": "normal",
|
||||
"iconName": "pen" if is_draft else "globe",
|
||||
"iconColor": "white",
|
||||
"modal": services_action(
|
||||
server_name=server_name, operation="edit", title="services_edit_title", subtitle="services_edit_subtitle", is_draft=is_draft
|
||||
),
|
||||
},
|
||||
{
|
||||
"attrs": {"data-server-name": server_name},
|
||||
|
|
@ -220,6 +230,9 @@ def get_services_list(services):
|
|||
"size": "normal",
|
||||
"iconName": "trash",
|
||||
"iconColor": "white",
|
||||
"modal": services_action(
|
||||
server_name=server_name, operation="delete", title="services_delete_title", subtitle="services_delete_subtitle"
|
||||
),
|
||||
},
|
||||
]
|
||||
},
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue