continue filter logic

This commit is contained in:
Jordan Blasenhauer 2024-06-11 09:30:10 +02:00
parent 9f2969d312
commit b645580a37
4 changed files with 317 additions and 22 deletions

View file

@ -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"

View file

@ -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}",

View file

@ -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 };

View file

@ -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) {