mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
cache page done + build all base pages
This commit is contained in:
parent
955f2a4cea
commit
8ce44bc0fc
16 changed files with 714 additions and 130 deletions
|
|
@ -65,6 +65,8 @@ def create_dir(directory: Path):
|
|||
def create_base_dirs():
|
||||
"""Create the base directories we will need to build front end and add them to flask app"""
|
||||
create_dir(opt_dir_dashboard)
|
||||
create_dir(ui_dir_static)
|
||||
create_dir(ui_dir_templates)
|
||||
|
||||
|
||||
def move_template(folder: Path, target_folder: Path):
|
||||
|
|
@ -168,7 +170,8 @@ def build():
|
|||
"""All steps to build the front end and set it to the flask app"""
|
||||
reset()
|
||||
create_base_dirs()
|
||||
add_legacy()
|
||||
# add_legacy()
|
||||
|
||||
# Only install packages if not already installed
|
||||
if not current_directory.joinpath("node_modules").exists():
|
||||
if run_command(["/usr/bin/npm", "install"], current_directory):
|
||||
|
|
|
|||
32
src/ui/client/builder/pages/cache.py
Normal file
32
src/ui/client/builder/pages/cache.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
from .utils.widgets import file_manager_widget, title_widget, subtitle_widget, unmatch_widget
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def fallback_message(msg: str, display: Optional[list] = None) -> dict:
|
||||
|
||||
return {
|
||||
"type": "void",
|
||||
"display": display if display else [],
|
||||
"widgets": [
|
||||
unmatch_widget(text=msg),
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def cache_builder(file_manager: Optional[dict] = None) -> str:
|
||||
|
||||
if file_manager is None or (isinstance(file_manager, dict) and len(file_manager) == 0):
|
||||
return [fallback_message("cache_not_found")]
|
||||
|
||||
return [
|
||||
{
|
||||
"type": "card",
|
||||
"widgets": [
|
||||
title_widget("cache_title"), # keep it (a18n)
|
||||
subtitle_widget("cache_subtitle"), # keep it (a18n)
|
||||
file_manager_widget(
|
||||
data=file_manager,
|
||||
),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
|
@ -875,6 +875,47 @@ def fields_widget(
|
|||
return { "type" : "Fields", "data" : data }
|
||||
|
||||
|
||||
def file_manager_widget(
|
||||
data: dict,
|
||||
baseFolder: str = "base",
|
||||
columns: dict = {"pc":"12","tablet":"12","mobile":"12"},
|
||||
containerClass: str = ""
|
||||
):
|
||||
"""
|
||||
File manager component. Useful with cache page.
|
||||
|
||||
PARAMETERS
|
||||
|
||||
- `data` **Object** Can be a translation key or by default raw text.
|
||||
- `baseFolder` **String** The base folder to display by default (optional, default `"base"`)
|
||||
- `columns` **Object** Work with grid system { pc: 12, tablet: 12, mobile: 12} (optional, default `{"pc":"12","tablet":"12","mobile":"12"}`)
|
||||
- `containerClass` **String** Additional class (optional, default `""`)
|
||||
|
||||
EXAMPLE
|
||||
|
||||
{
|
||||
title: "Total Users",
|
||||
type: "card",
|
||||
titleClass: "text-lg",
|
||||
color : "info",
|
||||
tag: "h2"
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
data = {
|
||||
"data" : data,
|
||||
}
|
||||
|
||||
|
||||
# List of params that will be add only if not default value
|
||||
list_params = [("baseFolder", baseFolder, "base"),("columns", columns, {"pc":"12","tablet":"12","mobile":"12"}),("containerClass", containerClass, "")]
|
||||
for param in list_params:
|
||||
add_key_value(data, param[0], param[1], param[2])
|
||||
|
||||
return { "type" : "Filemanager", "data" : data }
|
||||
|
||||
|
||||
def filter_widget(
|
||||
filters: Optional[list] = None,
|
||||
data: Union[dict, list] = {},
|
||||
|
|
|
|||
21
src/ui/client/builder/test_cache.py
Normal file
21
src/ui/client/builder/test_cache.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
from utils import save_builder
|
||||
from pages.cache import cache_builder
|
||||
|
||||
# parents is parent folders
|
||||
# children can be either files or folders
|
||||
file_manager = {
|
||||
# always need a root, this is the first folder display
|
||||
"base": {"parents": [], "children": ["certificates", "configs", "test"], "type": "folder"},
|
||||
"certificates": {"parents": ["base"], "children": ["cert-1"], "type": "folder"},
|
||||
"cert-1": {"parents": ["base", "certificates"], "children": [], "type": "file", "downloadEndpoint": "/download/cert-1"},
|
||||
"configs": {"parents": ["base"], "children": ["config-1"], "type": "folder"},
|
||||
"config-1": {"parents": ["base", "configs"], "children": [], "type": "file", "downloadEndpoint": "/download/cert-1"},
|
||||
"test": {"parents": ["base"], "children": ["test-1"], "type": "folder"},
|
||||
"test-1": {"parents": ["base", "test"], "children": ["test-2"], "type": "folder", "downloadEndpoint": "/download/cert-1"},
|
||||
"test-2": {"parents": ["base", "test", "test-1"], "children": [], "type": "file", "downloadEndpoint": "/download/cert-1"},
|
||||
}
|
||||
|
||||
|
||||
builder = cache_builder(file_manager=file_manager)
|
||||
|
||||
save_builder(page_name="cache", output=builder, script_name="cache")
|
||||
70
src/ui/client/dashboard/components/Builder/Cache.vue
Normal file
70
src/ui/client/dashboard/components/Builder/Cache.vue
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<script setup>
|
||||
// Containers
|
||||
import Grid from "@components/Widget/Grid.vue";
|
||||
import GridLayout from "@components/Widget/GridLayout.vue";
|
||||
import Button from "@components/Widget/Button.vue";
|
||||
import ButtonGroup from "@components/Widget/ButtonGroup.vue";
|
||||
import Title from "@components/Widget/Title.vue";
|
||||
import Subtitle from "@components/Widget/Subtitle.vue";
|
||||
import FileManager from "@components/Widget/FileManager.vue";
|
||||
import Unmatch from "@components/Message/Unmatch.vue";
|
||||
import { useEqualStr } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
* @name Builder/Cache.vue
|
||||
* @description This component is lightweight builder containing only the necessary components to create the cache page.
|
||||
* @param {array} builder - Array of containers and widgets
|
||||
*/
|
||||
|
||||
const props = defineProps({
|
||||
builder: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- top level grid (layout) -->
|
||||
<GridLayout
|
||||
v-for="(container, index) in props.builder"
|
||||
:key="index"
|
||||
:gridLayoutClass="container.containerClass"
|
||||
:maxWidthScreen="container.maxWidthScreen"
|
||||
:type="container.type"
|
||||
:title="container.title"
|
||||
:link="container.link"
|
||||
:columns="container.containerColumns"
|
||||
:id="container.id"
|
||||
:display="container.display"
|
||||
>
|
||||
<!-- widget grid -->
|
||||
<Grid>
|
||||
<!-- widget element -->
|
||||
<template v-for="(widget, index) in container.widgets" :key="index">
|
||||
<Title v-if="useEqualStr(widget.type, 'Title')" v-bind="widget.data" />
|
||||
<Subtitle
|
||||
v-if="useEqualStr(widget.type, 'Subtitle')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<Unmatch
|
||||
v-if="useEqualStr(widget.type, 'Unmatch')"
|
||||
v-bind="widget.data"
|
||||
/>
|
||||
<FileManager
|
||||
v-if="useEqualStr(widget.type, 'FileManager')"
|
||||
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>
|
||||
</GridLayout>
|
||||
</template>
|
||||
56
src/ui/client/dashboard/components/Icons/Folder.vue
Normal file
56
src/ui/client/dashboard/components/Icons/Folder.vue
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<script setup>
|
||||
import { defineProps, reactive } from "vue";
|
||||
/**
|
||||
* @name Icons/Folder.vue
|
||||
* @description This component is a svg icon representing folder.
|
||||
* @example
|
||||
* {
|
||||
* color: 'info',
|
||||
* }
|
||||
* @param {String} [iconClass="icon-default"] - The class of the icon.
|
||||
* @param {Any} [value=""] - Attach a value to icon. Useful on some cases like table filtering using icons.
|
||||
* @param {String} [color="dark"] - The color of the icon between some tailwind css available colors (purple, green, red, orange, blue, yellow, gray, dark, amber, emerald, teal, indigo, cyan, sky, pink...). Darker colors are also available using the base color and adding '-darker' (e.g. 'red-darker').
|
||||
* @param {Boolean} [disabled=false] - If true, the icon will be disabled.
|
||||
*/
|
||||
|
||||
const props = defineProps({
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "icon-default",
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
required: false,
|
||||
default: "",
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "dark",
|
||||
},
|
||||
disabled: { type: Boolean, required: false, default: false },
|
||||
});
|
||||
|
||||
const icon = reactive({
|
||||
color: props.color || "dark",
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<svg
|
||||
:data-color="icon.color"
|
||||
:data-value="props.value"
|
||||
:aria-disabled="props.disabled ? 'true' : 'false'"
|
||||
data-svg="back"
|
||||
role="img"
|
||||
aria-hidden="true"
|
||||
:class="[props.iconClass, icon.color, 'fill']"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
d="M19.5 21a3 3 0 0 0 3-3v-4.5a3 3 0 0 0-3-3h-15a3 3 0 0 0-3 3V18a3 3 0 0 0 3 3h15ZM1.5 10.146V6a3 3 0 0 1 3-3h5.379a2.25 2.25 0 0 1 1.59.659l2.122 2.121c.14.141.331.22.53.22H19.5a3 3 0 0 1 3 3v1.146A4.483 4.483 0 0 0 19.5 9h-15a4.483 4.483 0 0 0-3 1.146Z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
126
src/ui/client/dashboard/components/Widget/FileManager.vue
Normal file
126
src/ui/client/dashboard/components/Widget/FileManager.vue
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
<script setup>
|
||||
import Icons from "@components/Widget/Icons.vue";
|
||||
import Container from "@components/Widget/Container.vue";
|
||||
import Text from "@components/Widget/Text.vue";
|
||||
import { reactive } from "vue";
|
||||
|
||||
/**
|
||||
* @name Widget/FileManager.vue
|
||||
* @description File manager component. Useful with cache page.
|
||||
* @example
|
||||
* {
|
||||
* title: "Total Users",
|
||||
* type: "card",
|
||||
* titleClass: "text-lg",
|
||||
* color : "info",
|
||||
* tag: "h2"
|
||||
* }
|
||||
* @param {Object} data - Can be a translation key or by default raw text.
|
||||
* @param {String} [baseFolder="base"] - The base folder to display by default
|
||||
* @param {Object} [columns={"pc": "12", "tablet": "12", "mobile": "12"}] - Work with grid system { pc: 12, tablet: 12, mobile: 12}
|
||||
* @param {String} [containerClass=""] - Additional class
|
||||
*/
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
baseFolder: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "base",
|
||||
},
|
||||
columns: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: { pc: "12", tablet: "12", mobile: "12" },
|
||||
},
|
||||
containerClass: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const manager = reactive({
|
||||
currFolder: "base", // by default, base
|
||||
});
|
||||
|
||||
/**
|
||||
* @name changeFolder
|
||||
* @description Change current folder to the selected one if it is a folder.
|
||||
* @param {String} name - The name of the folder or file
|
||||
* @param {String} type - The type of element clicked, can be a folder or a file.
|
||||
* @returns {void}
|
||||
*/
|
||||
function changeFolder(name, type) {
|
||||
if (type !== "folder") return;
|
||||
manager.currFolder = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @name downloadCache
|
||||
* @description Download the cache file.
|
||||
* @param {String} fileName - The cache filename to download
|
||||
* @returns {void}
|
||||
*/
|
||||
function downloadCache(fileName) {
|
||||
const url = `${location.href}${fileName}`;
|
||||
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Container
|
||||
data-is="file-manager"
|
||||
:containerClass="`${props.containerClass}layout-file-manager`"
|
||||
:columns="props.columns"
|
||||
>
|
||||
<div class="file-manager-breadcrumb">
|
||||
<span class="file-manager-breadcrumb-base">/</span>
|
||||
<button
|
||||
class="file-manager-breadcrumb-btn"
|
||||
@click="changeFolder(parent, 'folder')"
|
||||
v-for="parent in props.data[manager.currFolder].parents"
|
||||
>
|
||||
{{ parent }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="file-manager-content">
|
||||
<template v-for="child in props.data[manager.currFolder].children">
|
||||
<button
|
||||
@click="changeFolder(child, props.data[child].type)"
|
||||
:class="[
|
||||
props.data[child].type === 'file'
|
||||
? 'cursor-default'
|
||||
: 'cursor-pointer',
|
||||
'file-manager-btn',
|
||||
]"
|
||||
>
|
||||
<div class="flex justify-center items-end">
|
||||
<Icons
|
||||
:iconName="
|
||||
props.data[child].type === 'file' ? 'document' : 'folder'
|
||||
"
|
||||
color="dark-darker"
|
||||
/>
|
||||
<button
|
||||
class="hover:brightness-90"
|
||||
v-if="props.data[child]?.downloadEndpoint"
|
||||
@click="downloadCache(props.data[child]?.downloadEndpoint)"
|
||||
>
|
||||
<Icons iconName="download" color="info" />
|
||||
</button>
|
||||
</div>
|
||||
<Text :text="child" />
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</Container>
|
||||
</template>
|
||||
|
|
@ -42,6 +42,7 @@ import Back from "@components/Icons/Back.vue";
|
|||
import Refresh from "@components/Icons/Refresh.vue";
|
||||
import Download from "@components/Icons/Download.vue";
|
||||
import Clone from "@components/Icons/Clone.vue";
|
||||
import Folder from "@components/Icons/Folder.vue";
|
||||
|
||||
/**
|
||||
* @name Widget/Icons.vue
|
||||
|
|
@ -114,6 +115,7 @@ onMounted(() => {
|
|||
v-if="useEqualStr(props.iconName, 'exclamation')"
|
||||
v-bind="icon"
|
||||
/>
|
||||
<Folder v-if="useEqualStr(props.iconName, 'folder')" v-bind="icon" />
|
||||
<Clone v-if="useEqualStr(props.iconName, 'clone')" v-bind="icon" />
|
||||
<Download v-if="useEqualStr(props.iconName, 'download')" v-bind="icon" />
|
||||
<Refresh v-if="useEqualStr(props.iconName, 'refresh')" v-bind="icon" />
|
||||
|
|
|
|||
|
|
@ -103,6 +103,11 @@ const props = defineProps({
|
|||
|
||||
const modalEl = ref();
|
||||
|
||||
/**
|
||||
* @name useCloseModal
|
||||
* @description Emits the close event to close the modal.
|
||||
* @returns {void}
|
||||
*/
|
||||
function useCloseModal() {
|
||||
emits("close");
|
||||
}
|
||||
|
|
@ -128,11 +133,23 @@ function useFocusModal() {
|
|||
}, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name modalKeyboardEvents
|
||||
* @description Handle the keyboard events for the modal.
|
||||
* @param {Event} e - The event object.
|
||||
* @returns {void}
|
||||
*/
|
||||
function modalKeyboardEvents(e) {
|
||||
if (e.key === "Escape") useCloseModal();
|
||||
if (e.key === "Tab" || e.key === "Shift-Tab") useFocusModal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @name modalClickEvents
|
||||
* @description Handle the click events for the modal.
|
||||
* @param {Event} e - The event object.
|
||||
* @returns {void}
|
||||
*/
|
||||
function modalClickEvents(e) {
|
||||
if (
|
||||
(e.target.closest("[data-modal]") !== modalEl.value && modalEl.value) ||
|
||||
|
|
@ -142,11 +159,21 @@ function modalClickEvents(e) {
|
|||
if (e.target.hasAttribute("data-close-modal")) useCloseModal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @name setEvents
|
||||
* @description Set the events for the modal when he is mounted.
|
||||
* @returns {void}
|
||||
*/
|
||||
function setEvents() {
|
||||
window.addEventListener("keydown", modalKeyboardEvents, true);
|
||||
window.addEventListener("click", modalClickEvents);
|
||||
}
|
||||
|
||||
/**
|
||||
* @name unsetEvents
|
||||
* @description Unset the events for the modal when he is unmounted.
|
||||
* @returns {void}
|
||||
*/
|
||||
function unsetEvents() {
|
||||
window.removeEventListener("keydown", modalKeyboardEvents, true);
|
||||
window.removeEventListener("click", modalClickEvents);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
"dashboard_cache": "cache",
|
||||
"dashboard_logs": "logs",
|
||||
"dashboard_raw": "raw mode",
|
||||
"dashboard_usermanagement": "user management",
|
||||
"dashboard_feedback_toggle_sidebar": "Toggle feedback sidebar.",
|
||||
"dashboard_feedback_close_sidebar": "Close feedback sidebar.",
|
||||
"dashboard_feedback_alert_close": "Close feedback alert",
|
||||
|
|
@ -102,6 +103,8 @@
|
|||
"dashboard_no_match": "No match found",
|
||||
"dashboard_no_match_filter": "No match found with filter",
|
||||
"dashboard_something_wrong": "Something is wrong",
|
||||
"dashboard_draft": "Select draft",
|
||||
"dashboard_draft_desc": "Draft will not apply the configuration. Else the service will be online and apply the configuration.",
|
||||
"inp_input_valid": "input valid",
|
||||
"inp_input_error_no_match": "No match found",
|
||||
"inp_input_error_required": "input is required",
|
||||
|
|
@ -143,6 +146,8 @@
|
|||
"icons_linkedin_desc": "Linkedin icon representing a link to a Linkedin profile.",
|
||||
"icons_twitter_desc": "Twitter icon representing a link to a Twitter account.",
|
||||
"action_switch": "switch {name}",
|
||||
"action_manage": "manage {name}",
|
||||
"action_clone": "clone {name}",
|
||||
"action_send": "send {name}",
|
||||
"action_start": "start {name}",
|
||||
"action_disable": "disable {name}",
|
||||
|
|
@ -164,9 +169,15 @@
|
|||
"action_restart": "restart {name}",
|
||||
"action_upload": "upload {name}",
|
||||
"action_delete_all": "delete all {name}",
|
||||
"action_select_all": "select all {name}",
|
||||
"action_unselect_all": "unselect all {name}",
|
||||
"action_previous": "previous",
|
||||
"action_next": "next",
|
||||
"action_toggle": "toggle {name}",
|
||||
"action_unban": "unban {name}",
|
||||
"action_entry": "entry {name}",
|
||||
"action_update": "update {name}",
|
||||
"action_back": "back",
|
||||
"home_version": "version",
|
||||
"home_all_features_available": "all features are available",
|
||||
"home_awaiting_compliance": "awaiting compliance",
|
||||
|
|
@ -191,16 +202,38 @@
|
|||
"home_errors_found": "errors found",
|
||||
"instances_name": "name",
|
||||
"instances_hostname": "hostname",
|
||||
"instances_search": "search",
|
||||
"instances_search_placeholder": "(host)name",
|
||||
"instances_search_popover": "Search by hostname or name keyword.",
|
||||
"instances_type": "type",
|
||||
"instances_status": "status",
|
||||
"instances_active": "active",
|
||||
"instances_inactive": "inactive",
|
||||
"instances_creation_date": "creation date",
|
||||
"instances_last_seen": "last seen",
|
||||
"instances_type_popover": "Select the instance type.",
|
||||
"instances_method": "method",
|
||||
"instances_method_popover": "Select the instance method.",
|
||||
"instances_health": "health",
|
||||
"instances_health_popover": "Select the instance health. Health is based on the last seen date.",
|
||||
"instances_reload_title": "Reload instance",
|
||||
"instances_reload_subtitle": "Are you sure to reload the following instance ?",
|
||||
"instances_ping_title": "Ping instance",
|
||||
"instances_ping_subtitle": "Ping will check instance health of the following instance.",
|
||||
"instances_delete_title": "Delete instance",
|
||||
"instances_delete_subtitle": "Are you sure to delete the following instance ?",
|
||||
"instances_create_title": "Create instance",
|
||||
"instances_create_subtitle": "Add a new instance to your list.",
|
||||
"instances_hostname_placeholder": "http://random",
|
||||
"instances_hostname_desc": "The adress of the server used for the instance.",
|
||||
"instances_hostname_warning_desc": "Port and server name will be set by scheduler.",
|
||||
"instances_name_placeholder": "awesome-instance",
|
||||
"instances_name_desc": "The name of the instance.",
|
||||
"instances_tab_list": "Instances",
|
||||
"instances_tab_add": "Add instance",
|
||||
"instances_list_title": "Instances",
|
||||
"instances_list_subtitle": "List of instances related to BunkerWeb.",
|
||||
"instances_not_found": "No instances found",
|
||||
"global_config_title": "Global configuration",
|
||||
"global_config_subtitle": "Manage your global settings.",
|
||||
"jobs_title": "Jobs list",
|
||||
"jobs_download_cache_file": "download cache files",
|
||||
"jobs_no_cache_file": "no cache files",
|
||||
"jobs_search": "search jobs",
|
||||
"jobs_search_desc": "Search within job name, plugin id or last run.",
|
||||
"jobs_interval": "Interval",
|
||||
|
|
@ -212,6 +245,7 @@
|
|||
"jobs_table_title": "Jobs list with plugin id, name, last run, interval and success state.",
|
||||
"jobs_table_name": "Name",
|
||||
"jobs_table_plugin_id": "Plugin id",
|
||||
"jobs_history_title": "Job history",
|
||||
"jobs_table_interval": "Interval",
|
||||
"jobs_table_reload": "Reload",
|
||||
"jobs_table_history": "History",
|
||||
|
|
@ -221,57 +255,54 @@
|
|||
"jobs_table_cache_downloadable": "Cache (downloadable)",
|
||||
"jobs_history_subtitle": "Job history details.",
|
||||
"jobs_history_table_title": "Job history list with start run date, end run date and success state.",
|
||||
"plugins_pro_plugin_desc": "Pro plugin",
|
||||
"plugins_core_plugin_desc": "Core plugin",
|
||||
"plugins_external_plugin_desc": "External plugin",
|
||||
"plugins_redirect_page_desc": "Redirect to plugin page",
|
||||
"plugins_upload_title": "Upload plugin",
|
||||
"plugins_upload_subtitle": "Extend BunkerWeb features.",
|
||||
"plugins_list_tab": "Plugins",
|
||||
"plugins_upload_tab": "Upload",
|
||||
"plugins_search": "Search plugin",
|
||||
"plugins_search_desc": "Search the plugin by his name",
|
||||
"plugins_type": "Plugin type",
|
||||
"plugins_type_desc": "Only show plugins of the chosen type",
|
||||
"plugins_delete_desc": "Delete plugin",
|
||||
"plugins_modal_delete_title": "Delete plugin",
|
||||
"plugins_modal_delete_confirm": "Are you sure you want to delete the plugin below ?",
|
||||
"reports_not_found": "No reports found",
|
||||
"reports_search": "Search reports",
|
||||
"reports_search_desc": "Search within report date, ip, url, user agent or data.",
|
||||
"reports_country": "Country",
|
||||
"reports_country_desc": "Country are alpha-2 country code based.",
|
||||
"reports_method": "Method",
|
||||
"reports_method_desc": "Methods are HTTP methods.",
|
||||
"reports_status": "Status",
|
||||
"reports_status_desc": "Status are HTTP status codes.",
|
||||
"reports_reason": "Reason",
|
||||
"reports_reason_desc": "Reason is the plugin name that triggered the report.",
|
||||
"plugins_delete_title": "Delete plugin",
|
||||
"plugins_delete_subtitle": "Are you sure you want to delete the plugin below ?",
|
||||
"plugins_not_found": "No plugins found",
|
||||
"plugins_list_title": "Plugins",
|
||||
"plugins_list_subtitle": "Get details and manage your plugins.",
|
||||
"reports_title": "Reports",
|
||||
"reports_table_title": "Reports list with date, ip, country, method, url, status code, user agent, reason and data.",
|
||||
"reports_table_date": "Date",
|
||||
"reports_table_ip": "IP",
|
||||
"reports_table_country": "Country",
|
||||
"reports_table_method": "Method",
|
||||
"reports_table_url": "URL",
|
||||
"reports_table_status_code": "Status code",
|
||||
"reports_table_cache_user_agent": "User agent",
|
||||
"reports_table_reason": "Reason",
|
||||
"reports_table_data": "Data",
|
||||
"reports_total": "Total reports",
|
||||
"reports_top_status": "Top status code",
|
||||
"reports_top_reason": "Top reason",
|
||||
"bans_search": "Search bans",
|
||||
"bans_search_desc": "Search within ban ip, ban start / end date",
|
||||
"bans_reason": "Reason",
|
||||
"bans_reason_desc": "Reason is the method that triggered the ban.",
|
||||
"bans_terms": "Term",
|
||||
"bans_terms_desc": "Order of magnitude before unban.",
|
||||
"bans_title": "Bans",
|
||||
"bans_table_title": "Bans list with ip, start date, end date, reason and terms.",
|
||||
"bans_table_ip": "IP",
|
||||
"bans_table_ban_start": "Ban start",
|
||||
"bans_table_ban_end": "Ban end",
|
||||
"bans_table_reason": "Reason",
|
||||
"bans_table_remain": "Remain",
|
||||
"bans_table_term": "Term",
|
||||
"bans_table_select": "Select",
|
||||
"reports_subtitle": "List of reports catch by BunkerWeb.",
|
||||
"reports_not_found": "No reports found",
|
||||
"reports_search_misc": "Search misc",
|
||||
"reports_search_misc_placeholder": "/admin",
|
||||
"reports_search_misc_desc": "Misc will search within ip, url, user agent or data.",
|
||||
"reports_select_reason": "Select reason",
|
||||
"reports_select_reason_desc": "Reason is the plugin that triggered the report.",
|
||||
"reports_select_method": "Select method",
|
||||
"reports_select_method_desc": "Method is the http method of the request.",
|
||||
"reports_select_code": "Select code",
|
||||
"reports_select_code_desc": "Code is the http status code returned by the request.",
|
||||
"bans_not_found": "No bans found",
|
||||
"bans_list_title": "Bans",
|
||||
"bans_list_subtitle": "List of bans catch by BunkerWeb.",
|
||||
"bans_unban_title": "Unban",
|
||||
"bans_unban_subtitle": "Are you sure to unban selected IP(s) ?",
|
||||
"bans_add_ban_ip": "Ip address to ban",
|
||||
"bans_add_end_date": "Define unban date",
|
||||
"bans_tab_list": "Bans",
|
||||
"bans_add_title": "Add ban",
|
||||
"bans_add_subtitle": "Manually add a ban.",
|
||||
"bans_tab_add": "Add ban",
|
||||
"bans_ban_check": "select ban",
|
||||
"bans_ban_start_date": "Ban date.",
|
||||
"bans_ban_end_date": "Unban date.",
|
||||
"bans_search_ip": "Search ip",
|
||||
"bans_search_ip_desc": "Search within ip address matching keyword.",
|
||||
"bans_search_ip_placeholder": "127.0.0.1",
|
||||
"bans_select_reason": "Select reason",
|
||||
"bans_select_reason_desc": "Reason is the plugin that triggered the ban.",
|
||||
"bans_select_remain": "Select remain",
|
||||
"bans_select_remain_desc": "Scale of remaining time before unban.",
|
||||
"services_select_methods": "Select methods",
|
||||
"services_select_draft": "Select draft",
|
||||
"services_new": "new service",
|
||||
"services_title": "Services",
|
||||
"services_table_name": "Name",
|
||||
|
|
@ -306,11 +337,143 @@
|
|||
"services_mode_subtitle": "Manage your service settings.",
|
||||
"services_manage_subtitle": "Manage your service settings.",
|
||||
"services_no_easy_mode": "No easy mode for this template",
|
||||
"services_clone_title": "Clone service",
|
||||
"services_clone_subtitle": "Choose a mode to clone service",
|
||||
"services_switch_mode": "Switch mode",
|
||||
"services_switch_mode_title": "Switch mode",
|
||||
"services_switch_mode_subtitle": "Choose a mode to switch",
|
||||
"logs_title": "Logs",
|
||||
"logs_not_found": "No logs found",
|
||||
"logs_no_files_found": "No log files found",
|
||||
"logs_select_file": "Select a log file",
|
||||
"logs_select_file": "Select a file",
|
||||
"logs_select_file_info": "Log files are retrieve using syslog under the hood.",
|
||||
"logs_log_file": "Log files",
|
||||
"logs_not_selected_or_not_found": "No log file selected or content not found",
|
||||
"logs_file_content": "Log content"
|
||||
"logs_file_content": "Log content",
|
||||
"user_management_search": "Search user",
|
||||
"user_management_search_placeholder": "john.doe{'@'}gmail.com",
|
||||
"user_management_search_desc": "Search within user name or email",
|
||||
"user_management_select_role": "Search role",
|
||||
"user_management_select_role_desc": "Search within user role",
|
||||
"user_management_select_is_totp": "Search TOTP",
|
||||
"user_management_select_is_totp_desc": "Search within user TOTP status",
|
||||
"user_management_delete_title": "Delete user",
|
||||
"user_management_delete_subtitle": "Are you sure you want to delete this user ?",
|
||||
"user_management_creation_date": "Creation date",
|
||||
"user_management_last_login_date": "Last login date",
|
||||
"user_management_last_update_date": "Last update date",
|
||||
"user_management_create_title": "Create user",
|
||||
"user_management_create_subtitle": "Add a member to your team.",
|
||||
"user_management_edit_title": "Edit user",
|
||||
"user_management_edit_subtitle": "Update user information.",
|
||||
"user_management_form_username": "Username",
|
||||
"user_management_form_username_placeholder": "john.doe",
|
||||
"user_management_form_username_desc": "Username is unique and required. It can't be changed.",
|
||||
"user_management_form_email": "Email",
|
||||
"user_management_form_email_desc": "Email is optional but recommended for password recovery.",
|
||||
"user_management_form_role": "Role",
|
||||
"user_management_form_role_desc": "Role is required and define user permissions.",
|
||||
"user_management_form_password": "Password",
|
||||
"user_management_form_password_desc": "Define the password for your new user.",
|
||||
"user_management_form_password_placeholder": "P{'@'}ssw0rd",
|
||||
"user_management_form_edit_password": "Edit password ?",
|
||||
"user_management_form_edit_password_desc": "Edit password is optional. Leave empty with confirm password to unchanged.",
|
||||
"user_management_form_edit_password_placeholder": "empty to unchanged",
|
||||
"user_management_form_password_confirm": "Confirm password",
|
||||
"user_management_form_password_confirm_desc": "Ensure the user will get the right password.",
|
||||
"user_management_form_password_confirm_placeholder": "P{'@'}ssw0rd",
|
||||
"user_management_form_edit_password_confirm": "Edit password confirm ?",
|
||||
"user_management_form_edit_password_confirm_desc": "Leave empty with confirm password to unchanged.",
|
||||
"user_management_form_edit_password_confirm_placeholder": "empty to unchanged",
|
||||
"user_management_tab_list": "Users",
|
||||
"user_management_tab_add": "Add user",
|
||||
"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",
|
||||
"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_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",
|
||||
"profile_info_not_found": "Impossible to retrieve profile information",
|
||||
"profile_info_title": "Information",
|
||||
"profile_info_subtitle": "Details about your account.",
|
||||
"profile_account_title": "Account",
|
||||
"profile_account_subtitle": "Manage some settings.",
|
||||
"profile_email": "Email",
|
||||
"profile_email_placeholder": "john.doe{'@'}gmail.com",
|
||||
"profile_email_desc": "Email is optional but recommended for password recovery or others features.",
|
||||
"profile_new_password": "New password",
|
||||
"profile_new_password_placeholder": "P{'@'}ssw0rd",
|
||||
"profile_new_password_desc": "Optional. Leave empty with confirm password to unchanged.",
|
||||
"profile_new_password_confirm": "New password confirm",
|
||||
"profile_new_password_confirm_placeholder": "P{'@'}ssw0rd",
|
||||
"profile_new_password_confirm_desc": "Optional. Leave empty with new password to unchanged.",
|
||||
"profile_current_password": "Current password",
|
||||
"profile_current_password_placeholder": "P{'@'}ssw0rd",
|
||||
"profile_current_password_desc": "This ensure you are the owner of the account.",
|
||||
"profile_recovery_codes_refresh_but_not_found": "Refresh done but no recovery codes found",
|
||||
"profile_refresh_recovery_codes": "Refresh recovery codes",
|
||||
"profile_totp_title": "TOTP",
|
||||
"profile_totp_subtitle": "Two-factor authentication.",
|
||||
"profile_totp_enable_state": "TOTP is currently enabled.",
|
||||
"profile_totp_disable_form_title": "Disable TOTP",
|
||||
"profile_totp_code": "TOTP code",
|
||||
"profile_totp_code_placeholder": "123456",
|
||||
"profile_totp_code_desc": "TOTP code is given by your authenticator app.",
|
||||
"profile_totp_disable_state": "TOTP is currently disabled.",
|
||||
"profile_totp_qr_code": "QR code to scan with your authenticator app.",
|
||||
"profile_totp_secret": "Secret key",
|
||||
"profile_totp_secret_placeholder": "secret",
|
||||
"profile_totp_secret_desc": "Another way to add TOTP to your authenticator app.",
|
||||
"profile_tab_profile": "Profile",
|
||||
"profile_tab_account": "Account",
|
||||
"profile_tab_totp": "TOTP",
|
||||
"profile_user_not_found": "Impossible to retrieve user information",
|
||||
"profile_totp_data_missing": "Impossible to retrieve TOTP data",
|
||||
"profile_username": "Username",
|
||||
"profile_created_method": "Created method",
|
||||
"profile_role": "Role",
|
||||
"profile_permissions": "Permissions",
|
||||
"profile_creation_date": "Creation date",
|
||||
"profile_last_update": "Last update",
|
||||
"profile_totp_enable_form_title": "Enable TOTP",
|
||||
"profile_account_tab_email": "Email",
|
||||
"profile_account_tab_password": "Password",
|
||||
"profile_account_form_email_title": "Update email",
|
||||
"profile_account_form_password_title": "Update password",
|
||||
"profile_no_recovery_codes": "No recovery codes remaining, please refresh them."
|
||||
}
|
||||
|
|
|
|||
37
src/ui/client/dashboard/pages/cache/Cache.vue
vendored
Normal file
37
src/ui/client/dashboard/pages/cache/Cache.vue
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<script setup>
|
||||
import { reactive, onBeforeMount, onMounted } from "vue";
|
||||
import DashboardLayout from "@components/Dashboard/Layout.vue";
|
||||
import BuilderCache from "@components/Builder/Cache.vue";
|
||||
import { useGlobal } from "@utils/global.js";
|
||||
|
||||
/**
|
||||
* @name Page/Cache.vue
|
||||
* @description This component is the cache page.
|
||||
This page displays global information about cache, and allow to download a cache file.
|
||||
*/
|
||||
|
||||
const cache = reactive({
|
||||
builder: "",
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
// Get builder data
|
||||
const dataAtt = "data-server-builder";
|
||||
const dataEl = document.querySelector(`[${dataAtt}]`);
|
||||
const data =
|
||||
dataEl && !dataEl.getAttribute(dataAtt).includes(dataAtt)
|
||||
? JSON.parse(atob(dataEl.getAttribute(dataAtt)))
|
||||
: {};
|
||||
cache.builder = data;
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
useGlobal();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DashboardLayout>
|
||||
<BuilderCache v-if="cache.builder" :builder="cache.builder" />
|
||||
</DashboardLayout>
|
||||
</template>
|
||||
11
src/ui/client/dashboard/pages/cache/cache.js
vendored
Normal file
11
src/ui/client/dashboard/pages/cache/cache.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
import { getI18n } from "@utils/lang.js";
|
||||
import Cache from "./Cache.vue";
|
||||
|
||||
const pinia = createPinia();
|
||||
|
||||
createApp(Cache)
|
||||
.use(pinia)
|
||||
.use(getI18n(["dashboard", "action", "inp", "icons", "cache"]))
|
||||
.mount("#app");
|
||||
28
src/ui/client/dashboard/pages/cache/index.html
vendored
Normal file
28
src/ui/client/dashboard/pages/cache/index.html
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/x-icon" href="/img/favicon.ico" />
|
||||
<link rel="stylesheet" href="/css/style.css" />
|
||||
<link rel="stylesheet" href="/css/flag-icons.min.css" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>BunkerWeb | Cache</title>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
class="hidden"
|
||||
data-server-global='{"username" : "admin", "plugins_page": [{"id" : "antibot", "name": "Antibot"}, {"id": "backup", "name" : "backup"} ]}'
|
||||
></div>
|
||||
<div
|
||||
class="hidden"
|
||||
data-server-flash='[{"type" : "success", "title" : "title", "message" : "Success feedback"}, {"type" : "error", "title" : "title", "message" : "Error feedback"}, {"type" : "warning", "title" : "title", "message" : "Warning feedback"}, {"type" : "info", "title" : "title", "message" : "Info feedback"}]'
|
||||
></div>
|
||||
<div
|
||||
class="hidden"
|
||||
data-server-builder='W3sidHlwZSI6ICJjYXJkIiwgIndpZGdldHMiOiBbeyJ0eXBlIjogIlRpdGxlIiwgImRhdGEiOiB7InRpdGxlIjogImNhY2hlX3RpdGxlIn19LCB7InR5cGUiOiAiU3VidGl0bGUiLCAiZGF0YSI6IHsic3VidGl0bGUiOiAiY2FjaGVfc3VidGl0bGUifX0sIHsidHlwZSI6ICJGaWxlbWFuYWdlciIsICJkYXRhIjogeyJkYXRhIjogeyJiYXNlIjogeyJwYXJlbnRzIjogW10sICJjaGlsZHJlbiI6IFsiY2VydGlmaWNhdGVzIiwgImNvbmZpZ3MiLCAidGVzdCJdLCAidHlwZSI6ICJmb2xkZXIifSwgImNlcnRpZmljYXRlcyI6IHsicGFyZW50cyI6IFsiYmFzZSJdLCAiY2hpbGRyZW4iOiBbImNlcnQtMSJdLCAidHlwZSI6ICJmb2xkZXIifSwgImNlcnQtMSI6IHsicGFyZW50cyI6IFsiYmFzZSIsICJjZXJ0aWZpY2F0ZXMiXSwgImNoaWxkcmVuIjogW10sICJ0eXBlIjogImZpbGUiLCAiZG93bmxvYWRFbmRwb2ludCI6ICIvZG93bmxvYWQvY2VydC0xIn0sICJjb25maWdzIjogeyJwYXJlbnRzIjogWyJiYXNlIl0sICJjaGlsZHJlbiI6IFsiY29uZmlnLTEiXSwgInR5cGUiOiAiZm9sZGVyIn0sICJjb25maWctMSI6IHsicGFyZW50cyI6IFsiYmFzZSIsICJjb25maWdzIl0sICJjaGlsZHJlbiI6IFtdLCAidHlwZSI6ICJmaWxlIiwgImRvd25sb2FkRW5kcG9pbnQiOiAiL2Rvd25sb2FkL2NlcnQtMSJ9LCAidGVzdCI6IHsicGFyZW50cyI6IFsiYmFzZSJdLCAiY2hpbGRyZW4iOiBbInRlc3QtMSJdLCAidHlwZSI6ICJmb2xkZXIifSwgInRlc3QtMSI6IHsicGFyZW50cyI6IFsiYmFzZSIsICJ0ZXN0Il0sICJjaGlsZHJlbiI6IFsidGVzdC0yIl0sICJ0eXBlIjogImZvbGRlciIsICJkb3dubG9hZEVuZHBvaW50IjogIi9kb3dubG9hZC9jZXJ0LTEifSwgInRlc3QtMiI6IHsicGFyZW50cyI6IFsiYmFzZSIsICJ0ZXN0IiwgInRlc3QtMSJdLCAiY2hpbGRyZW4iOiBbXSwgInR5cGUiOiAiZmlsZSIsICJkb3dubG9hZEVuZHBvaW50IjogIi9kb3dubG9hZC9jZXJ0LTEifX19fV19XQ=='
|
||||
></div>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="cache.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -648,6 +648,9 @@ body {
|
|||
.layout-settings-multiple-group {
|
||||
@apply mt-4 rounded border border-gray-500/50 dark:border-gray-500 p-4 sm:gap-x-8 gap-y-8 col-span-12 grid grid-cols-12 w-full relative bg-gray-200/50 dark:bg-gray-900/10;
|
||||
}
|
||||
.layout-file-manager {
|
||||
@apply w-full pt-6 pb-4;
|
||||
}
|
||||
|
||||
/* MESSAGE */
|
||||
.msg-container {
|
||||
|
|
@ -678,6 +681,28 @@ body {
|
|||
@apply fixed col-span-12 flex mx-2 my-8 w-full;
|
||||
}
|
||||
|
||||
/* FILE MANAGER */
|
||||
|
||||
.file-manager-btn {
|
||||
@apply h-fit col-span-12 md:col-span-6 lg:col-span-4 m-2 py-2 px-4 flex justify-between items-center bg-gray-100 dark:bg-slate-700 rounded-xl hover:brightness-90;
|
||||
}
|
||||
|
||||
.file-manager-breadcrumb {
|
||||
@apply flex justify-start items-center mx-2 mb-2;
|
||||
}
|
||||
|
||||
.file-manager-breadcrumb-base {
|
||||
@apply dark:text-gray-300 text-gray-600 text-sm mr-3;
|
||||
}
|
||||
|
||||
.file-manager-breadcrumb-btn {
|
||||
@apply dark:text-gray-300 text-gray-600 after:float-right after:pl-2 after:text-gray-600 dark:after:text-gray-300 after:content-['/'] text-sm mr-3 hover:brightness-90;
|
||||
}
|
||||
|
||||
.file-manager-content {
|
||||
@apply grid grid-cols-12 w-full min-h-60;
|
||||
}
|
||||
|
||||
/* POPOVER */
|
||||
|
||||
.popover-btn {
|
||||
|
|
@ -760,6 +785,10 @@ body {
|
|||
@apply h-6.5 w-6.5 relative pointer-events-none;
|
||||
}
|
||||
|
||||
.icon-file-manager {
|
||||
@apply h-6.5 w-6.5 relative pointer-events-none mr-1.5;
|
||||
}
|
||||
|
||||
.icon-list-details {
|
||||
@apply ml-2 h-6.5 w-6.5 relative pointer-events-none;
|
||||
}
|
||||
|
|
@ -1245,6 +1274,10 @@ body {
|
|||
@apply w-full col-span-12 mb-0 text-gray-700 dark:text-gray-300 break-word;
|
||||
}
|
||||
|
||||
.text-file-manager {
|
||||
@apply w-full col-span-12 flex justify-end items-center mb-0 text-gray-700 dark:text-gray-300 break-word;
|
||||
}
|
||||
|
||||
/* BTN GROUP */
|
||||
|
||||
.button-group-card {
|
||||
|
|
@ -1575,79 +1608,7 @@ body {
|
|||
@apply col-span-12 justify-center items-center mt-4;
|
||||
}
|
||||
|
||||
/* FILE MANAGER */
|
||||
|
||||
.file-manager-breadcrumb {
|
||||
@apply flex flex-wrap bg-transparent rounded-lg md:mb-8 w-full;
|
||||
}
|
||||
|
||||
.file-manager-breadcrumb-back-btn {
|
||||
@apply mr-3 text-sm capitalize leading-normal dark:text-gray-500 text-gray-600 hover:brightness-75;
|
||||
}
|
||||
|
||||
.file-manager-breadcrumb-back-svg {
|
||||
@apply pointer-events-none w-4.5 h-4.5;
|
||||
}
|
||||
|
||||
.file-manager-breadcrumb-item {
|
||||
@apply leading-normal text-sm;
|
||||
}
|
||||
|
||||
.file-manager-breadcrumb-item-btn {
|
||||
@apply text-base mr-2 dark:text-gray-500 text-gray-600 after:float-right after:pl-2 after:text-gray-600 dark:after:text-gray-500 after:content-['/'] after:hover:brightness-125 hover:brightness-75;
|
||||
}
|
||||
|
||||
.file-manager-item-container {
|
||||
@apply relative w-full min-h-20 h-full transition rounded bg-gray-100 hover:bg-gray-300 dark:bg-slate-700 dark:hover:bg-slate-800;
|
||||
}
|
||||
|
||||
.file-manager-item-nav {
|
||||
@apply overflow-hidden w-full cursor-pointer relative min-h-20 max-h-20 py-0.5 sm:py-1 pl-12 sm:pl-16 pr-12 sm:pr-16 text-center break-words;
|
||||
}
|
||||
|
||||
.file-manager-item-svg {
|
||||
@apply absolute left-3 top-6 sm:top-5 h-8 w-8 sm:h-10 sm:w-10 fill-primary stroke-gray-100 dark:stroke-gray-600 dark:brightness-150;
|
||||
}
|
||||
|
||||
.file-manager-item-name {
|
||||
@apply max-h-8 pointer-events-none transition duration-300 ease-in-out dark:opacity-90 mx-7 mb-0 text-slate-700 dark:text-gray-300;
|
||||
}
|
||||
|
||||
.base.file-manager-item-name {
|
||||
@apply text-sm md:text-base;
|
||||
}
|
||||
|
||||
.sm.file-manager-item-name {
|
||||
@apply text-sm;
|
||||
}
|
||||
|
||||
.xs.file-manager-item-name {
|
||||
@apply text-[0.8rem];
|
||||
}
|
||||
|
||||
.file-manager-item-dropdown {
|
||||
@apply absolute flex-col z-110 w-48 right-0 top-0 translate-y-16 shadow border border-gray-300 dark:border-slate-600 rounded;
|
||||
}
|
||||
|
||||
.file-manager-item-dropdown-btn {
|
||||
@apply dark:brightness-125 dark:hover:brightness-100 flex justify-center items-center absolute h-full w-10 bg-primary fill-white first-letter:absolute top-0 -right-1 font-bold text-center text-white uppercase transition-all rounded-none rounded-r-lg cursor-pointer leading-normal text-xs ease-in tracking-tight-rem bg-150 bg-x-25 active:opacity-85;
|
||||
}
|
||||
|
||||
.file-manager-item-btn {
|
||||
@apply duration-300 border-b border-b-gray-300 hover:brightness-90 bg-white my-0 relative px-6 py-2 text-center align-middle transition-all rounded-none cursor-pointer leading-normal text-sm ease-in tracking-tight-rem dark:border-slate-600 dark:bg-slate-700 dark:text-gray-300 w-full hover:bg-gray-100;
|
||||
}
|
||||
|
||||
.first.file-manager-item-btn {
|
||||
@apply rounded-t;
|
||||
}
|
||||
|
||||
.last.file-manager-item-btn {
|
||||
@apply border-none rounded-b;
|
||||
}
|
||||
|
||||
.file-manager-item-btn-text {
|
||||
@apply transition duration-300 ease-in-out text-gray-700 dark:text-gray-300 dark:opacity-80 ml-4 font-bold uppercase;
|
||||
}
|
||||
/* MODAL */
|
||||
|
||||
.modal-container {
|
||||
@apply w-full h-screen fixed bg-gray-600/50 z-[10000] top-0 left-0 flex justify-center items-center;
|
||||
|
|
@ -2517,7 +2478,7 @@ body {
|
|||
}
|
||||
|
||||
.dark-darker.fill {
|
||||
@apply fill-slate-600 dark:fill-slate-500;
|
||||
@apply fill-slate-600 dark:fill-gray-500;
|
||||
}
|
||||
|
||||
.amber-darker.fill {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -47,12 +47,18 @@ export default defineConfig({
|
|||
instances: resolve(__dirname, "./dashboard/pages/instances/index.html"),
|
||||
global_config: resolve(
|
||||
__dirname,
|
||||
"./dashboard/pages/global-config/index.html",
|
||||
"./dashboard/pages/global-config/index.html"
|
||||
),
|
||||
configs: resolve(__dirname, "./dashboard/pages/configs/index.html"),
|
||||
reports: resolve(__dirname, "./dashboard/pages/reports/index.html"),
|
||||
plugins: resolve(__dirname, "./dashboard/pages/plugins/index.html"),
|
||||
bans: resolve(__dirname, "./dashboard/pages/bans/index.html"),
|
||||
jobs: resolve(__dirname, "./dashboard/pages/jobs/index.html"),
|
||||
services: resolve(__dirname, "./dashboard/pages/services/index.html"),
|
||||
modes: resolve(__dirname, "./dashboard/pages/modes/index.html"),
|
||||
logs: resolve(__dirname, "./dashboard/pages/logs/index.html"),
|
||||
profile: resolve(__dirname, "./dashboard/pages/profile/index.html"),
|
||||
cache: resolve(__dirname, "./dashboard/pages/cache/index.html"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue