enhance perf and components, configs done

* switch from v-show to v-if with display to gain perf + fix tabulator crashing with this directive updating options
* update unmatch component name in others files
* modal component now handle tabulator
* base configs page format done (need to do ListCheck component)
This commit is contained in:
Jordan Blasenhauer 2024-08-15 17:03:03 +02:00
parent 98793612d1
commit d04e9a1af3
25 changed files with 274 additions and 176 deletions

View file

@ -20,7 +20,7 @@ This component is lightweight builder containing only the necessary components t
type: "card",
gridLayoutClass: "transparent",
widgets: [
{ type: "MessageUnmatch",
{ type: "Unmatch",
data: { text: "bans_not_found" }
},
],
@ -331,7 +331,7 @@ This component is lightweight builder containing only the necessary components t
gridLayoutClass: "transparent",
widgets: [
{
type: "MessageUnmatch",
type: "Unmatch",
data: { text: "reports_not_found" }
}
],

View file

@ -243,9 +243,7 @@ def bans_builder(bans):
builder.append(
{
"type": "void",
"widgets": [
{"type": "MessageUnmatch", "data": {"text": "bans_not_found"}}
],
"widgets": [{"type": "Unmatch", "data": {"text": "bans_not_found"}}],
}
)
return builder

View file

@ -20,12 +20,9 @@ from typing import Optional
columns = [
add_column(title="Name", field="name", formatter="text"),
add_column(title="Type", field="type", formatter="text"),
add_column(title="global", field="global", formatter="icons"),
add_column(title="global", field="is_global", formatter="icons", maxWidth=160),
add_column(
title="services", field="services", formatter="buttonGroup"
), # We will display a button with a modal that show all services apply. Case global, show all services.
add_column(
title="actions", field="actions", formatter="buttonGroup"
title="actions", field="actions", formatter="buttongroup"
), # edit button that will switch to the form using display store + delete with modal to confirm
]
@ -54,7 +51,7 @@ def configs_filter(config_types: Optional[list] = None) -> list: # healths = "u
},
{
"type": "=",
"fields": ["global"],
"fields": ["is_global"],
"setting": {
"id": "select-global",
"name": "select-global",
@ -75,7 +72,7 @@ def configs_filter(config_types: Optional[list] = None) -> list: # healths = "u
},
]
if types is not None and len(types) >= 2:
if config_types is not None and len(config_types) >= 2:
filters.append(
{
"type": "=",
@ -85,7 +82,7 @@ def configs_filter(config_types: Optional[list] = None) -> list: # healths = "u
"name": "select-type",
"label": "configs_select_type", # keep it (a18n)
"value": "all", # keep "all"
"values": ["all"] + types,
"values": ["all"] + config_types,
"inpType": "select",
"onlyDown": True,
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
@ -136,8 +133,8 @@ def configs_item(
iconColor="white",
modal={
"widgets": [
title_widget(title="user_management_delete_title"), # keep it (a18n)
text_widget(text="user_management_delete_global_subtitle" if is_global else "user_management_delete_no_global_subtitle"), # keep it (a18n)
title_widget(title="configs_delete_title"), # keep it (a18n)
text_widget(text="configs_delete_global_subtitle" if is_global else "configs_delete_no_global_subtitle"), # keep it (a18n)
text_widget(bold=True, text=filename),
button_group_widget(
buttons=[
@ -167,6 +164,7 @@ def configs_item(
),
]
services_columns = [{"title": "id", "field": "id", "formatter": "text", "maxWidth": 100}, {"title": "Name", "field": "name", "formatter": "text"}]
services_items = []
# get id
for index, service in enumerate(config_services):
@ -177,68 +175,76 @@ def configs_item(
}
)
services_detail = (
button_group_widget(
buttons=[
button_widget(
id=f"services-btn-{filename}-{global_text}",
type="button",
iconName="disk",
iconColor="white",
text="configs_show_services", # keep it (a18n)
color="orange",
size="normal",
modal={
"widgets": [
title_widget(title="configs_services_title"), # keep it (a18n)
text_widget(text="configs_services_subtitle"), # keep it (a18n)
tabulator_widget(
id=f"table-services-{filename}-{global_text}",
columns=[{"title": "id", "field": "id", "formatter": "text"}, {"title": "Name", "field": "name", "formatter": "text"}],
# Add every services that apply to the conf. All if global.
items=services_items,
filters=[
{
"type": "like",
"fields": ["name"],
"setting": {
"id": f"input-search-service-{filename}-{global_text}",
"name": f"input-search-service-{filename}-{global_text}",
"label": "configs_search_service", # keep it (a18n)
"value": "",
"inpType": "input",
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
},
},
],
services_filter = [
{
"type": "like",
"fields": ["name"],
"setting": {
"id": f"input-search-service-{filename}-{global_text}",
"name": f"input-search-service-{filename}-{global_text}",
"label": "configs_search_service", # keep it (a18n)
"value": "",
"columns": {"pc": 3, "tablet": 4, "mobile": 12},
"fieldSize": "sm",
"placeholder": "configs_search_service_placeholder", # keep it (a18n)
"inpType": "input",
"popovers": [
{
"iconName": "info",
"text": "configs_search_service_desc",
}
],
},
},
]
services_detail = [
button_widget(
id=f"services-btn-{filename}-{global_text}",
type="button",
iconName="disk",
hideText=True,
iconColor="white",
text="configs_show_services", # keep it (a18n)
color="orange",
size="normal",
modal={
"widgets": [
title_widget(title="configs_services_title"), # keep it (a18n)
tabulator_widget(
id=f"table-services-{filename}-{global_text}",
layout="fitColumns",
columns=services_columns,
# Add every services that apply to the conf. All if global.
items=services_items,
filters=services_filter,
paginationSize=5,
paginationSizeSelector=[5, 10],
),
button_group_widget(
buttons=[
button_widget(
id=f"close-services-btn-{filename}-{global_text}",
text="action_close", # keep it (a18n)
color="close",
size="normal",
attrs={"data-close-modal": ""}, # a11y
),
button_group_widget(
buttons=[
button_widget(
id=f"close-services-btn-{filename}-{global_text}",
text="action_close", # keep it (a18n)
color="close",
size="normal",
attrs={"data-close-modal": ""}, # a11y
)["data"],
]
),
],
},
)["data"]
]
),
)
]
),
],
},
)
]
return {
"name": text_widget(text=filename)["data"],
"type": text_widget(text=config_type)["data"],
"is_global": icons_widget(
iconName="check" if is_global == "up" else "cross" if is_global == "down" else "search",
value=global_text,
iconName="check" if is_global else "cross",
value="yes" if is_global else "no",
)["data"],
"services": services_detail,
"actions": {"buttons": actions},
"actions": {"buttons": services_detail + actions},
}
@ -258,6 +264,8 @@ def config_form(
config_services = [] if is_global else config_services
global_text = "yes" if is_global else "no"
filename = "new" if is_new else filename
title = "configs_create_title" if is_new else "configs_edit_title"
subtitle = "configs_create_subtitle" if is_new else "configs_edit_subtitle"
return {
"type": "card",
@ -265,13 +273,12 @@ def config_form(
"display": ["main", display_index],
"widgets": [
title_widget(
title="configs_create_title", # keep it (a18n)
title=title, # keep it (a18n)
),
subtitle_widget(
subtitle="configs_create_subtitle", # keep it (a18n)
subtitle=subtitle, # keep it (a18n)
),
regular_widget(
maxWidthScreen="xs",
endpoint="/add",
fields=[
get_fields_from_field(
@ -282,17 +289,17 @@ def config_form(
value="",
required=True,
pattern="", # add your pattern if needed
columns={"pc": 12, "tablet": 12, "mobile": 12},
placeholder="configs_filename_add_placeholder", # keep it (a18n)
columns={"pc": 6, "tablet": 6, "mobile": 12},
placeholder="configs_filename_placeholder", # keep it (a18n)
disabled=enabled_value_field_only,
popovers=[
{
"iconName": "yellow-darker",
"text": "configs_filename_add_warning_desc", # can't add a service with same name and same type of existing one, will not be save.
"text": "configs_filename_warning_desc", # can't add a service with same name and same type of existing one, will not be save.
},
{
"iconName": "info",
"text": "configs_filename_add_desc",
"text": "configs_filename_desc",
},
],
)
@ -306,7 +313,7 @@ def config_form(
values=config_types,
required=True,
requiredValues=config_types,
columns={"pc": 12, "tablet": 12, "mobile": 12},
columns={"pc": 6, "tablet": 6, "mobile": 12},
disabled=enabled_value_field_only,
popovers=[
{
@ -316,41 +323,26 @@ def config_form(
],
)
),
get_fields_from_field(
checkbox_widget(
id=f"configs-global-{filename}-{global_text}",
name="global",
label="configs_global", # keep it (a18n)
value=is_global,
disabled=enabled_value_field_only,
pattern="", # add your pattern if needed
columns={"pc": 12, "tablet": 12, "mobile": 12},
placeholder="configs_global_placeholder", # keep it (a18n)
popovers=[
{
"iconName": "yellow-darker",
"text": "configs_global_warning_desc", # if check, will apply to all services even if services are selected.
},
{
"iconName": "info",
"text": "configs_global_desc",
},
],
)
),
get_fields_from_field(
select_widget(
id=f"configs-services-{filename}-{global_text}",
name="services",
label="configs_services", # keep it (a18n)
value=config_services,
value="",
values=services,
columns={"pc": 12, "tablet": 12, "mobile": 12},
required=True,
requiredValues=services,
columns={"pc": 6, "tablet": 6, "mobile": 12},
disabled=enabled_value_field_only,
popovers=[
{
"iconName": "exclamation",
"color": "yellow-darker",
"text": "configs_services_warning_desc", # if check, will apply to all services even if services are selected.
},
{
"iconName": "info",
"text": "config_services_desc",
"text": "configs_services_desc",
},
],
)
@ -361,10 +353,7 @@ def config_form(
name="value",
label="configs_value", # keep it (a18n)
value=config_value,
pattern="", # add your pattern if needed
columns={"pc": 12, "tablet": 12, "mobile": 12},
placeholder="configs_value_placeholder", # keep it (a18n)
disabled=enabled_value_field_only,
popovers=[
{
"iconName": "yellow-darker",
@ -379,6 +368,18 @@ def config_form(
),
],
buttons=[
button_widget(
id=f"back-from-create-user-{filename}-{global_text}",
text="action_back",
color="back",
iconName="back",
size="normal",
type="button",
attrs={
"data-display-index": 0,
"data-display-group": "main",
},
),
button_widget(
id=f"configs-submit-{filename}-{global_text}",
text="action_create" if is_new else "action_edit", # keep it (a18n)
@ -387,7 +388,7 @@ def config_form(
color="success" if is_new else "edit",
size="normal",
type="submit",
)
),
],
),
],
@ -422,10 +423,11 @@ def configs_tabs():
}
def fallback_message(msg: str):
def fallback_message(msg: str, display: Optional[list] = None) -> dict:
return {
"type": "void",
"gridLayoutClass": "transparent",
"display": display if display else [],
"widgets": [
unmatch_widget(text=msg),
],
@ -457,11 +459,11 @@ def configs_builder(configs: Optional[list] = None, config_types: Optional[list]
)
)
if config is None or len(configs) == 0:
if configs is None or len(configs) == 0:
return [
# Tabs is button group with display value and a size tab inside a tabs container
configs_tabs(),
fallback_message("user_management_users_not_found"),
fallback_message(msg="configs_not_found", display=["main", 0]),
] + configs_form
# Start adding the new config form
@ -474,9 +476,6 @@ def configs_builder(configs: Optional[list] = None, config_types: Optional[list]
filename=config.get("filename", ""),
config_services=config.get("config_services", ""),
config_type=config.get("config_type", ""),
health=config.get("health", ""),
creation_date=config.get("creation_date", ""),
last_seen=config.get("last_seen", ""),
display_index=display_index,
)
)
@ -488,7 +487,7 @@ def configs_builder(configs: Optional[list] = None, config_types: Optional[list]
filename=config.get("filename", ""),
config_type=config.get("type", ""),
config_value=config.get("value", ""),
config_services=config.get("config_services", []),
config_services=config.get("configs_services", []),
display_index=display_index,
)
)
@ -498,11 +497,11 @@ def configs_builder(configs: Optional[list] = None, config_types: Optional[list]
configs_tabs(),
{
"type": "card",
"maxWidthScreen": "3xl",
"maxWidthScreen": "xl",
"display": ["main", 0],
"widgets": [
title_widget(title="user_management_list_title"), # keep it (a18n)
subtitle_widget(subtitle="user_management_list_subtitle"), # keep it (a18n)
title_widget(title="configs_list_title"), # keep it (a18n)
subtitle_widget(subtitle="configs_list_subtitle"), # keep it (a18n)
tabulator_widget(
id="table-configs",
columns=columns,

View file

@ -7,7 +7,7 @@ def logs_builder(files: list[str] = [], current_file: str = "", raw_data: str =
builder = [
{
"type": "void",
"widgets": [{"type": "MessageUnmatch", "data": {"text": "logs_no_files_found"}}],
"widgets": [{"type": "Unmatch", "data": {"text": "logs_no_files_found"}}],
}
]
return builder
@ -47,7 +47,7 @@ def logs_builder(files: list[str] = [], current_file: str = "", raw_data: str =
{
"type": "card",
"containerColumns": {"pc": 12, "tablet": 12, "mobile": 12},
"widgets": [title_widget("logs_title"), file_select, {"type": "MessageUnmatch", "data": {"text": "logs_not_selected_or_not_found"}}],
"widgets": [title_widget("logs_title"), file_select, {"type": "Unmatch", "data": {"text": "logs_not_selected_or_not_found"}}],
}
]
return builder
@ -67,7 +67,7 @@ def logs_builder(files: list[str] = [], current_file: str = "", raw_data: str =
"tablet": 12,
"mobile": 12,
},
"editorClass" : "min-h-[500px]",
"editorClass": "min-h-[500px]",
}
},
}

View file

@ -6,26 +6,38 @@ from pages.configs import configs_builder
configs = [
{
"filename": "my-config-1",
"type": "http",
"is_global": "no",
"services": ["service1"],
"config_type": "http",
"is_global": False,
"config_services": ["service1"],
},
{
"filename": "my-config-1",
"type": "http",
"is_global": "yes",
"services": ["service1", "service2"],
"config_type": "http",
"is_global": True,
"config_services": [
"service1",
"service2",
"service3",
"service4",
"service5",
"service6",
"services7",
"service8",
"service9",
"service10",
"services11",
],
},
{
"filename": "my-config-2",
"type": "https",
"is_global": "no",
"services": ["service2"],
"config_type": "https",
"is_global": False,
"config_services": ["service2"],
},
]
config_types = ["http", "https", "socks4", "socks5"]
builder = configs_builder(configs, config_types)
services = ["service1", "service2"]
builder = configs_builder(configs=configs, config_types=config_types, services=services)
save_builder(page_name="configs", output=builder, script_name="configs")

View file

@ -20,7 +20,7 @@ import { useEqualStr } from "@utils/global.js";
* type: "card",
* gridLayoutClass: "transparent",
* widgets: [
* { type: "MessageUnmatch",
* { type: "Unmatch",
* data: { text: "bans_not_found" }
* },
* ],

View file

@ -20,7 +20,7 @@ import { useEqualStr } from "@utils/global.js";
* type: "card",
* gridLayoutClass: "transparent",
* widgets: [
* { type: "MessageUnmatch",
* { type: "Unmatch",
* data: { text: "bans_not_found" }
* },
* ],

View file

@ -18,7 +18,7 @@ import { useEqualStr } from "@utils/global.js";
* gridLayoutClass: "transparent",
* widgets: [
* {
* type: "MessageUnmatch",
* type: "Unmatch",
* data: { text: "reports_not_found" }
* }
* ],

View file

@ -20,7 +20,7 @@ import { useEqualStr } from "@utils/global.js";
* type: "card",
* gridLayoutClass: "transparent",
* widgets: [
* { type: "MessageUnmatch",
* { type: "Unmatch",
* data: { text: "bans_not_found" }
* },
* ],

View file

@ -335,7 +335,7 @@ onUnmounted(() => {
@inp="data.currPlugin = $event"
/>
</Filter>
<MessageUnmatch v-if="!Object.keys(advancedForm.templateUIFormat).length" />
<Unmatch v-if="!Object.keys(advancedForm.templateUIFormat).length" />
<template v-for="(plugin, pluginId) in advancedForm.templateUIFormat">
<Container
data-is="content"

View file

@ -211,7 +211,7 @@ onUnmounted(() => {
>
<Title type="card" :title="'dashboard_easy_mode'" />
<Subtitle type="card" :subtitle="'dashboard_easy_mode_subtitle'" />
<MessageUnmatch
<Unmatch
v-if="easyForm.templateUIFormat.length <= 0"
:text="'services_no_easy_mode'"
/>

View file

@ -95,7 +95,7 @@ function indexPending(id) {
:data="data.base"
:filters="props.filters"
/>
<MessageUnmatch v-if="!data.format.length" />
<Unmatch v-if="!data.format.length" />
<ul
data-is="list-details"
v-if="data.format.length"

View file

@ -79,7 +79,7 @@ const gridClass = computed(() => {
<template>
<component
v-show="container.isDisplay"
v-if="container.isDisplay"
:aria-hidden="container.isDisplay ? 'false' : 'true'"
:is="props.tag"
data-container

View file

@ -61,7 +61,7 @@ if (props.display.length) {
<template>
<div
v-show="container.isDisplay"
v-if="container.isDisplay"
:aria-hidden="container.isDisplay ? 'false' : 'true'"
data-grid
:class="[props.gridClass, 'layout-grid']"

View file

@ -141,7 +141,7 @@ onMounted(() => {
<template>
<component
v-show="container.isDisplay"
v-if="container.isDisplay"
:aria-hidden="container.isDisplay ? 'false' : 'true'"
ref="flowEl"
:id="container.id"
@ -156,5 +156,4 @@ onMounted(() => {
>
<slot></slot>
</component>
<!-- end card or elements on the document flow -->
</template>

View file

@ -18,6 +18,7 @@ import Button from "@components/Widget/Button.vue";
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
import Unmatch from "@components/Message/Unmatch.vue";
import Table from "@components/Widget/Table.vue";
import Tabulator from "@components/Widget/Tabulator.vue";
/**
* @name Builder/Modal.vue
@ -186,8 +187,12 @@ const emits = defineEmits(["close"]);
<Grid>
<!-- widget element -->
<template v-for="(widget, index) in props.widgets">
<MessageUnmatch
v-if="useEqualStr(widget.type, 'MessageUnmatch')"
<Unmatch
v-if="useEqualStr(widget.type, 'Unmatch')"
v-bind="widget.data"
/>
<Tabulator
v-if="useEqualStr(widget.type, 'Tabulator')"
v-bind="widget.data"
/>
<Title

View file

@ -95,7 +95,8 @@ function showPopover() {
popoverContainer.value.style.transform = `translateX(-${
popoverContainerRect.width / 2 -
(popoverBtnRect.width * popoverGroupNums) / 2 -
popoverBtnRect.width * (popoverIndex - popoverGroupNums)
popoverBtnRect.width * (popoverIndex - popoverGroupNums) +
16
}px) translateY(${
popoverContainerRect.height / 2 - popoverBtnRect.height / 2 + 4
}px)`;

View file

@ -252,7 +252,7 @@ onMounted(() => {
:aria-hidden="table.itemsFormat.length ? 'true' : 'false'"
class="table-unmatch"
>
<MessageUnmatch
<Unmatch
v-if="!table.itemsFormat.length"
:style="{ maxWidth: unmatchWidth }"
ref="unmatchEl"

View file

@ -56,6 +56,7 @@ const tableStore = useTableStore();
* @param {Number} [itemsBeforePagination=10] - Hide pagination unless number is reach.
* @param {Number} [paginationSize=10] - Number of items per page
* @param {Number} [paginationInitialPage=1] - Initial page
* @param {Number} [paginationButtonCount=3] - Available pagination buttons
* @param {Array} [paginationSizeSelector=[10, 25, 50, 100]] - Select number of items per page
* @returns {Void}
*/
@ -137,12 +138,18 @@ const props = defineProps({
required: false,
default: [10, 25, 50, 100],
},
paginationButtonCount: {
type: Number,
required: false,
default: 3,
},
});
const tableEl = ref(null); //reference to your table element
const table = reactive({
instance: null,
class: "layout-table",
filters: {},
columns: props.columns,
items: props.items,
@ -150,7 +157,7 @@ const table = reactive({
options: computed(() => {
const opts = {
data: table.items, //link data to table
reactiveData: true, //enable data reactivity
reactiveData: false, //enable data reactivity
autoResize: true, // prevent auto resizing of table
resizableRows: true, // this option takes a boolean value (default = false)
resizableColumnFit: true, //maintain the fit of columns when resizing
@ -168,7 +175,7 @@ const table = reactive({
opts.pagination = props.isPagination;
opts.paginationSize = props.paginationSize;
opts.paginationInitialPage = props.paginationInitialPage;
opts.paginationButtonCount = 2;
opts.paginationButtonCount = props.paginationButtonCount;
opts.paginationSizeSelector = props.paginationSizeSelector.concat([true]);
opts.paginationCounter = "rows";
@ -258,14 +265,15 @@ function togglePagination() {
if (!props.isPagination || !props.itemsBeforePagination) return;
function toggle(currItems, itemsToShow) {
const isPagination = currItems.length >= itemsToShow ? true : false;
try {
const isPagination = currItems.length >= itemsToShow ? true : false;
const footer = tableEl.value.querySelector(".tabulator-footer");
isPagination
? footer.classList.remove("hidden")
: footer.classList.add("hidden");
const footer = tableEl.value.querySelector(".tabulator-footer");
isPagination
? footer.classList.remove("hidden")
: footer.classList.add("hidden");
} catch (e) {}
}
toggle(props.items, props.itemsBeforePagination);
table.instance.on("dataChanged", (data) => {
@ -274,18 +282,35 @@ function togglePagination() {
}
onMounted(() => {
extendTabulator();
table.instance = new Tabulator(tableEl.value, table.options);
table.instance.on("tableBuilt", () => {
togglePagination();
try {
extendTabulator();
table.instance = new Tabulator(tableEl.value, table.options);
table.instance.on("tableBuilt", () => {
if (!table.instance) return;
togglePagination();
a11yTable(table.instance);
// Add table instance to store in order to use it in other components
tableStore.setTable(props.id, table.instance);
setTimeout(() => {
if (!table.instance) return;
table.instance.redraw();
}, 100);
});
} catch (e) {}
a11yTable(table.instance);
// Add table instance to store in order to use it in other components
tableStore.setTable(props.id, table.instance);
setTimeout(() => {
table.instance.redraw();
}, 100);
});
// Update style base on the container
// get the closest data-is with a value not table
table.class += tableEl?.value?.closest("[data-is]:not([data-is='table'])")
? tableEl?.value
?.closest("[data-is]:not([data-is='table'])")
.getAttribute("data-is")
: "";
});
onUnmounted(() => {
if (!tableStore.isTable(props.id)) return;
const table = tableStore.getTableById(props.id);
table.destroy();
});
</script>

View file

@ -374,5 +374,44 @@
"user_management_list_title": "Users",
"user_management_list_subtitle": "Manage your team members.",
"user_management_users_not_found": "No users found",
"user_management_missing_roles": "Impossible to retrieve roles"
"user_management_missing_roles": "Impossible to retrieve roles",
"configs_search_name": "Search name",
"configs_search_name_desc": "Search within config name",
"configs_search_name_placeholder": "redirect-conf",
"configs_select_global": "Select global",
"configs_select_global_desc": "Global config apply to all services, else it is apply to define services.",
"configs_select_type": "Select type",
"configs_select_type_desc": "The type of the config will determine the config's context execution.",
"configs_delete_title": "Delete config",
"configs_delete_global_subtitle": "Are you sure you want to delete the global config below ?",
"configs_delete_no_global_subtitle": "Are you sure you want to delete the config below ?",
"configs_delete_subtitle": "Are you sure you want to delete the config below ?",
"configs_search_service": "Search service",
"configs_search_service_desc": "Search within services that are applying the config",
"configs_search_service_placeholder": "service-name",
"configs_show_services": "Show services applying to this config",
"configs_services_title": "Services",
"configs_create_title": "Create config",
"configs_create_subtitle": "Add a new config to your list.",
"configs_edit_title": "Edit config",
"configs_edit_subtitle": "Update config value.",
"configs_filename": "Config name",
"configs_filename_placeholder": "my-conf",
"configs_filename_warning_desc": "Config name matching another config name with the same type will not be created. Edit the existing one instead.",
"configs_filename_desc": "The name of the config.",
"configs_type": "Config type",
"configs_type_desc": "The type of the config will determine the config's context execution.",
"configs_services": "Services",
"configs_services_desc": "The services that are applying the config.",
"configs_services_warning_desc": "Case global value is check, will apply to every services. Case global uncheck and no services check, form will be ignored.",
"configs_value": "Configuration value",
"configs_value_desc": "The config script to apply.",
"configs_value_warning_desc": "Must be a valid config script. Case it is not, the config will not be saved/updated.",
"configs_tab_list": "Configs",
"configs_list_title": "Configs",
"configs_list_subtitle": "Current list of configs.",
"configs_tab_add": "Add config",
"configs_missing_types": "Impossible to retrieve config types",
"configs_missing_services": "Impossible to retrieve services",
"configs_not_found": "No configs found"
}

File diff suppressed because one or more lines are too long

View file

@ -19,7 +19,7 @@ const tableStore = useTableStore();
* type: "card",
* gridLayoutClass: "transparent",
* widgets: [
* { type: "MessageUnmatch",
* { type: "Unmatch",
* data: { text: "bans_not_found" }
* },
* ],

View file

@ -93,5 +93,13 @@ export const useTableStore = defineStore("table", () => {
return tables.value;
}
return { setTable, getTableById, getTables };
function removeTable(id) {
delete tables.value[id];
}
function isTable(id) {
return !!(id in tables.value);
}
return { setTable, getTableById, getTables, removeTable, isTable };
});

View file

@ -308,12 +308,12 @@ body {
.select-dropdown-btn.normal,
.list-dropdown-btn.normal {
@apply my-0 px-2 py-1.5 text-sm leading-normal;
@apply my-0 px-2 py-2 text-sm leading-normal;
}
.select-dropdown-btn.sm,
.list-dropdown-btn.sm {
@apply my-0 px-2 py-1 text-xs leading-normal;
@apply my-0 px-2 py-1.5 text-xs leading-normal;
}
.active.select-dropdown-btn {
@ -564,7 +564,19 @@ body {
}
.layout-table {
@apply py-4 col-span-12 grid grid-cols-12 w-full relative;
@apply col-span-12 grid grid-cols-12 w-full relative;
}
.layout-table.card {
@apply py-4;
}
.layout-table.default {
@apply py-4;
}
.layout-table.modal {
@apply py-0;
}
.layout-card {
@ -663,7 +675,7 @@ body {
}
.popover-text {
@apply whitespace-normal pointer-events-none text-center transition duration-300 ease-in-out font-semibold text-sm text-white dark:text-white m-0;
@apply [word-break:break-word] whitespace-normal pointer-events-none text-center transition duration-300 ease-in-out font-semibold text-sm text-white dark:text-white m-0;
}
.icon-container {
@ -1188,7 +1200,7 @@ body {
}
.text-table-content {
@apply col-span-12 mb-0 dark:text-gray-300 break-word;
@apply col-span-12 mb-0 dark:text-gray-300 break-word whitespace-break-spaces;
}
.text-form-error {

File diff suppressed because one or more lines are too long