mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
continue filter logic
This commit is contained in:
parent
9f2969d312
commit
b645580a37
4 changed files with 317 additions and 22 deletions
|
|
@ -10,6 +10,7 @@ import Select from "@components/Forms/Field/Select.vue";
|
|||
import Button from "@components/Widget/Button.vue";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { plugin_types } from "@utils/variables";
|
||||
import { useFilterPluginsAdvanced } from "@utils/form.js";
|
||||
/**
|
||||
@name Form/Advanced.vue
|
||||
@description This component is used to create a complete advanced form with plugin selection.
|
||||
|
|
@ -65,23 +66,57 @@ const props = defineProps({
|
|||
|
||||
const data = reactive({
|
||||
currPlugin: "",
|
||||
plugins: [],
|
||||
keyword: "",
|
||||
type: "all",
|
||||
context: "all",
|
||||
filtered: computed(() => {
|
||||
console.log(props.template);
|
||||
const filters = [
|
||||
{
|
||||
type: "keyword",
|
||||
value: data.keyword,
|
||||
keys: ["id", "label", "name", "description", "help", "value"],
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
value: data.type,
|
||||
keys: ["type"],
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
value: data.context,
|
||||
keys: ["context"],
|
||||
},
|
||||
];
|
||||
// deep copy
|
||||
const template = JSON.parse(JSON.stringify(props.template));
|
||||
const filterData = useFilterPluginsAdvanced(template, filters);
|
||||
data.plugins = getPluginNames(filterData);
|
||||
data.currPlugin = getFirstPlugin(filterData);
|
||||
return filterData;
|
||||
}),
|
||||
});
|
||||
|
||||
function getFirstPlugin(form) {
|
||||
return form[0]["name"];
|
||||
function getFirstPlugin(template) {
|
||||
try {
|
||||
return template[0]["name"];
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function getPluginNames(form) {
|
||||
const pluginNames = [];
|
||||
// Loop on each dict from form list
|
||||
for (const plugin of form) {
|
||||
// Return the first plugin
|
||||
pluginNames.push(plugin.name);
|
||||
function getPluginNames(template) {
|
||||
try {
|
||||
const pluginNames = [];
|
||||
// Loop on each dict from template list
|
||||
for (const plugin of template) {
|
||||
// Return the first plugin
|
||||
pluginNames.push(plugin.name);
|
||||
}
|
||||
return pluginNames;
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
return pluginNames;
|
||||
}
|
||||
|
||||
const comboboxPlugin = {
|
||||
|
|
@ -123,7 +158,6 @@ const selectType = {
|
|||
value: "all",
|
||||
// add 'all' as first value
|
||||
values: ["all"].concat(plugin_types),
|
||||
type: "text",
|
||||
name: uuidv4(),
|
||||
label: "inp_select_plugin_type",
|
||||
popovers: [
|
||||
|
|
@ -136,6 +170,23 @@ const selectType = {
|
|||
columns: { pc: 3, tablet: 4, mobile: 12 },
|
||||
};
|
||||
|
||||
const selectContext = {
|
||||
id: uuidv4(),
|
||||
value: "all",
|
||||
// add 'all' as first value
|
||||
values: ["all", "multisite", "global"],
|
||||
name: uuidv4(),
|
||||
label: "inp_select_plugin_context",
|
||||
popovers: [
|
||||
{
|
||||
text: "inp_select_plugin_context_desc",
|
||||
iconName: "info",
|
||||
iconColor: "info",
|
||||
},
|
||||
],
|
||||
columns: { pc: 3, tablet: 4, mobile: 12 },
|
||||
};
|
||||
|
||||
const buttonSave = {
|
||||
id: uuidv4(),
|
||||
text: "action_save",
|
||||
|
|
@ -149,11 +200,11 @@ const buttonSave = {
|
|||
onMounted(() => {
|
||||
// Get first props.forms template name
|
||||
data.currPlugin = getFirstPlugin(props.template);
|
||||
data.plugins = getPluginNames(props.template);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
{{ data.filtered }}
|
||||
<Container
|
||||
:tag="'form'"
|
||||
method="POST"
|
||||
|
|
@ -163,14 +214,15 @@ onMounted(() => {
|
|||
<Container :containerClass="`grid grid-cols-12 col-span-12 w-full`">
|
||||
<Combobox
|
||||
v-bind="comboboxPlugin"
|
||||
:value="getFirstPlugin(props.template)"
|
||||
:values="getPluginNames(props.template)"
|
||||
:value="data.currPlugin"
|
||||
:values="data.plugins"
|
||||
@inp="data.currPlugin = $event"
|
||||
/>
|
||||
<Input v-bind="inpKeyword" />
|
||||
<Select v-bind="selectType" />
|
||||
<Input @inp="(v) => (data.keyword = v)" v-bind="inpKeyword" />
|
||||
<Select @inp="(v) => (data.type = v)" v-bind="selectType" />
|
||||
<Select @inp="(v) => (data.context = v)" v-bind="selectContext" />
|
||||
</Container>
|
||||
<template v-for="plugin in props.template">
|
||||
<template v-for="plugin in data.filtered">
|
||||
<Container
|
||||
v-show="plugin.name === data.currPlugin"
|
||||
class="col-span-12 w-full"
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@
|
|||
"inp_combobox_advanced_desc": "Switch between available plugins.",
|
||||
"inp_select_plugin_type": "plugin type",
|
||||
"inp_select_plugin_type_desc": "Only show plugins of the chosen type",
|
||||
"inp_select_plugin_context": "plugin context",
|
||||
"inp_select_plugin_context_desc": "Only show plugins of the chosen context.",
|
||||
"action_send": "send {name}",
|
||||
"action_start": "start {name}",
|
||||
"action_disable": "disable {name}",
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ function useSubmitForm(data) {
|
|||
|
||||
/**
|
||||
@name useGetFormDataAttr
|
||||
@description /Get the form data store on attributes of the element.
|
||||
@description Get the form data store on attributes of the element.
|
||||
Format is data-form-<key>="<value>"
|
||||
@example document.querySelector("[data-submit-form]")
|
||||
@param {DOMElement} el - Element to get the data attributes.
|
||||
|
|
@ -73,4 +73,248 @@ function useGetFormDataAttr(el) {
|
|||
return data;
|
||||
}
|
||||
|
||||
export { useForm };
|
||||
/**
|
||||
@name useFilterSettingsAdvanced
|
||||
@description Filter advanced settings templates based on filters object.
|
||||
@example
|
||||
const filters = [
|
||||
{
|
||||
type: "keyword",
|
||||
value: "whitelist_ip",
|
||||
keys: ["id", "label", "name", "description", "help", "value"],
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
value: "core",
|
||||
keys: ["type"],
|
||||
},
|
||||
];
|
||||
|
||||
const plugins = [
|
||||
{
|
||||
id: "clientcache",
|
||||
stream: "no",
|
||||
name: "Client cache",
|
||||
description: "Manage caching for clients.",
|
||||
version: "1.0",
|
||||
type: "core",
|
||||
method: "manual",
|
||||
page: false,
|
||||
settings: {
|
||||
USE_CLIENT_CACHE: {
|
||||
context: "multisite",
|
||||
default: "no",
|
||||
help: "Tell client to store locally static files.",
|
||||
id: "use-client-cache-default",
|
||||
label: "Use client cache",
|
||||
regex: "^(yes|no)$",
|
||||
type: "check",
|
||||
containerClass: "z-3",
|
||||
pattern: "^(yes|no)$",
|
||||
inpType: "checkbox",
|
||||
name: "Use client cache",
|
||||
columns: {
|
||||
pc: 4,
|
||||
tablet: 6,
|
||||
mobile: 12,
|
||||
},
|
||||
disabled: true,
|
||||
value: "yes",
|
||||
popovers: [
|
||||
{
|
||||
iconColor: "info",
|
||||
iconName: "info",
|
||||
text: "Tell client to store locally static files.",
|
||||
},
|
||||
{
|
||||
iconColor: "orange",
|
||||
iconName: "disk",
|
||||
text: "inp_popover_multisite",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
checksum: null,
|
||||
},
|
||||
];
|
||||
@param {object} plugins - Object with the plugins data.
|
||||
@param {object} filters - Object with the filters data.
|
||||
*/
|
||||
function useFilterPluginsAdvanced(plugins, filters) {
|
||||
// loop on filters to determine types
|
||||
filters = removeDefaultFilters(filters);
|
||||
|
||||
// Case no filters, return plugins
|
||||
if (filters.length === 0) return plugins;
|
||||
|
||||
const filterTypes = [];
|
||||
filters.forEach((filter) => {
|
||||
if (!filterTypes.includes(filter.type)) filterTypes.push(filter.type);
|
||||
});
|
||||
|
||||
// Deepcopy
|
||||
const data = JSON.parse(JSON.stringify(plugins));
|
||||
const filterData = [];
|
||||
// Loop on data
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
// Prepare data
|
||||
const items = [];
|
||||
const plugin = JSON.parse(JSON.stringify(data[i]));
|
||||
// Get SETTING_NAME as id
|
||||
const settings = plugin.settings;
|
||||
for (const key in settings) {
|
||||
items.push({ id: key });
|
||||
items.push(settings[key]);
|
||||
}
|
||||
// Get settings and remove settings from plugin to avoid duplicate
|
||||
delete plugin["settings"];
|
||||
items.push(plugin);
|
||||
|
||||
// Check if one filter of type "select" in filters
|
||||
if (filterTypes.includes("select") && !isMatchingSelect(filters, items))
|
||||
continue;
|
||||
|
||||
if (filterTypes.includes("keyword") && !isMatchingKeyword(filters, items))
|
||||
continue;
|
||||
|
||||
filterData.push(data[i]);
|
||||
}
|
||||
return filterData;
|
||||
}
|
||||
|
||||
/**
|
||||
@name removeDefaultFilters
|
||||
@description Remove default filters from filters array for each filter type.
|
||||
@example
|
||||
const filters = [
|
||||
{
|
||||
type: "keyword",
|
||||
value: "",
|
||||
keys: ["id", "label", "name", "description", "help", "value"],
|
||||
},
|
||||
{
|
||||
type: "select",
|
||||
value: "all",
|
||||
keys: ["all", "core"],
|
||||
},
|
||||
];
|
||||
@param filters - Array of filters to remove default filters
|
||||
*/
|
||||
function removeDefaultFilters(filters) {
|
||||
// Remove filters with type "select" and "all" as value
|
||||
filters = filters.filter((filter) => {
|
||||
return filter.type !== "select" || filter.value !== "all";
|
||||
});
|
||||
// Remove filters with type "keyword" and empty value
|
||||
filters = filters.filter((filter) => {
|
||||
return filter.type !== "keyword" || filter.value !== "";
|
||||
});
|
||||
return filters;
|
||||
}
|
||||
|
||||
/**
|
||||
@name isMatchingKeyword
|
||||
@description Check all items keys if at least one match with the filter value.
|
||||
@example
|
||||
const filters = [
|
||||
{
|
||||
type: "keyword",
|
||||
value: "whitelist_ip",
|
||||
keys: ["id", "label", "name", "description", "help", "value"],
|
||||
},
|
||||
];
|
||||
const items = {
|
||||
id : "test",
|
||||
label : "Test",
|
||||
name : "test",
|
||||
}
|
||||
@param filters - Array of filters
|
||||
@param items - Array of items
|
||||
*/
|
||||
function isMatchingKeyword(filters, items) {
|
||||
// Match if at least one match
|
||||
let atLeastOneMatch = false;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
for (let j = 0; j < filters.length; j++) {
|
||||
const filter = filters[j];
|
||||
// Avoid filter cases
|
||||
const filterValue = filter.value;
|
||||
const filterType = filter.type;
|
||||
if (filterType !== "keyword") continue;
|
||||
|
||||
for (let k = 0; k < filter.keys.length; k++) {
|
||||
const key = filter.keys[k];
|
||||
// Avoid if key not found in item
|
||||
if (!item[key]) continue;
|
||||
const value = item[key].replaceAll("_", " ").toLowerCase();
|
||||
// Avoid non-primitive value
|
||||
if (typeof value !== "string" && typeof value !== "number") continue;
|
||||
// Check if value contains filter value
|
||||
|
||||
if (
|
||||
value &&
|
||||
value
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(filterValue.replaceAll("_", " ").toLowerCase())
|
||||
) {
|
||||
atLeastOneMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return atLeastOneMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
@name isMatchingSelect
|
||||
@description Check all items keys if at least one match exactly the filter value.
|
||||
@example
|
||||
const filters = [
|
||||
{
|
||||
type: "select",
|
||||
value: "core",
|
||||
keys: ["type"],
|
||||
},
|
||||
];
|
||||
const items = {
|
||||
id : "test",
|
||||
label : "Test",
|
||||
name : "test",
|
||||
}
|
||||
@param filters - Array of filters
|
||||
@param items - Array of items
|
||||
*/
|
||||
function isMatchingSelect(filters, items) {
|
||||
let atLeastOneMatch = false;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
for (let j = 0; j < filters.length; j++) {
|
||||
const filter = filters[j];
|
||||
// Avoid filter cases
|
||||
const filterValue = filter.value;
|
||||
const filterType = filter.type;
|
||||
if (filterType !== "select") continue;
|
||||
|
||||
for (let k = 0; k < filter.keys.length; k++) {
|
||||
const key = filter.keys[k];
|
||||
// Avoid if key not found in item
|
||||
if (!item[key]) continue;
|
||||
const value = item[key];
|
||||
// Avoid non-primitive value
|
||||
if (typeof value !== "string" && typeof value !== "number") continue;
|
||||
// Value need to match exactly filter value
|
||||
if (value.toString().toLowerCase() === filterValue.toLowerCase()) {
|
||||
atLeastOneMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return atLeastOneMatch;
|
||||
}
|
||||
|
||||
export { useForm, useFilterPluginsAdvanced };
|
||||
|
|
|
|||
|
|
@ -6042,8 +6042,6 @@ function useFilterSettings(plugins, filters) {
|
|||
if (!filterTypes.includes(filter.type)) filterTypes.push(filter.type);
|
||||
});
|
||||
|
||||
console.log("filters type", filterTypes);
|
||||
|
||||
// Deepcopy
|
||||
const data = JSON.parse(JSON.stringify(plugins));
|
||||
const filterData = [];
|
||||
|
|
@ -6071,7 +6069,6 @@ function useFilterSettings(plugins, filters) {
|
|||
|
||||
filterData.push(data[i]);
|
||||
}
|
||||
console.log(filterData);
|
||||
}
|
||||
|
||||
function isMatchingKeyword(filters, items) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue