chg: [front] Removed daisyUI dependency

This commit is contained in:
Sami Mokaddem 2024-07-25 11:10:00 +02:00
parent 014f55a2c4
commit 77238fabe9
17 changed files with 608 additions and 234 deletions

47
package-lock.json generated
View file

@ -23,7 +23,6 @@
"@vitejs/plugin-vue": "^5.0.5",
"@vue/eslint-config-prettier": "^9.0.0",
"autoprefixer": "^10.4.19",
"daisyui": "^4.12.10",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"postcss": "^8.4.38",
@ -1444,16 +1443,6 @@
"node": ">= 8"
}
},
"node_modules/css-selector-tokenizer": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
"integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
"dev": true,
"dependencies": {
"cssesc": "^3.0.0",
"fastparse": "^1.1.2"
}
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@ -1471,34 +1460,6 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/culori": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz",
"integrity": "sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==",
"dev": true,
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
"node_modules/daisyui": {
"version": "4.12.10",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.10.tgz",
"integrity": "sha512-jp1RAuzbHhGdXmn957Z2XsTZStXGHzFfF0FgIOZj3Wv9sH7OZgLfXTRZNfKVYxltGUOBsG1kbWAdF5SrqjebvA==",
"dev": true,
"dependencies": {
"css-selector-tokenizer": "^0.8",
"culori": "^3",
"picocolors": "^1",
"postcss-js": "^4"
},
"engines": {
"node": ">=16.9.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/daisyui"
}
},
"node_modules/debug": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
@ -1919,12 +1880,6 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
"node_modules/fastparse": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
"dev": true
},
"node_modules/fastq": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
@ -3876,4 +3831,4 @@
}
}
}
}
}

View file

@ -26,7 +26,6 @@
"@vitejs/plugin-vue": "^5.0.5",
"@vue/eslint-config-prettier": "^9.0.0",
"autoprefixer": "^10.4.19",
"daisyui": "^4.12.10",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"postcss": "^8.4.38",
@ -35,4 +34,4 @@
"tailwindcss": "^3.4.4",
"vite": "^5.3.1"
}
}
}

View file

@ -1,3 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
@import "./styled-components/toggle.css";
@import "./styled-components/button.css";
@import "./styled-components/transitions.css";

View file

@ -0,0 +1,83 @@
.btn {
@apply px-2 py-1 font-semibold rounded border text-nowrap select-none;
@apply transition-all duration-75;
@apply border-slate-300;
&.btn-sm {
@apply px-1 py-0;
}
&.btn-xs {
@apply px-0.5 py-0;
@apply text-sm;
}
&.btn-lg {
@apply px-3 py-1;
@apply text-lg;
}
&.btn:not(:disabled) {
@apply hover:bg-slate-200 hover:border-slate-300;
@apply active:scale-90
}
&.btn:disabled {
@apply cursor-not-allowed opacity-60;
}
&.btn-primary:not(:disabled) {
@apply border-none;
@apply bg-blue-600 text-white hover:bg-blue-700;
}
&.btn-info:not(:disabled) {
@apply border-none;
@apply bg-blue-500 text-white hover:bg-blue-600;
}
&.btn-danger:not(:disabled) {
@apply border-none;
@apply bg-red-600 text-white hover:bg-red-700;
}
&.btn-success:not(:disabled) {
@apply border-none;
@apply bg-green-600 text-white hover:bg-green-700;
}
&.btn-warning:not(:disabled) {
@apply border-none;
@apply bg-amber-600 text-white hover:bg-amber-700;
}
&.btn-outline-primary:not(:disabled) {
@apply hover:bg-blue-600 hover:border-blue-700 hover:text-white;
@apply border-blue-700 hover:border-blue-800
}
&.btn-outline-info:not(:disabled) {
@apply hover:bg-blue-500 hover:border-blue-700 hover:text-white;
@apply border-blue-700 hover:border-blue-800
}
&.btn-outline-danger:not(:disabled) {
@apply hover:bg-red-500 hover:border-red-700 hover:text-white;
@apply border-red-700 hover:border-red-800
}
&.btn-outline-success:not(:disabled) {
@apply hover:bg-green-500 hover:border-green-700 hover:text-white;
@apply border-green-700 hover:border-green-800
}
&.btn-outline-warning:not(:disabled) {
@apply hover:bg-amber-500 hover:border-amber-700 hover:text-white;
@apply border-amber-700 hover:border-amber-800
}
&.btn-link:not(:disabled) {
@apply border-none;
@apply hover:bg-transparent hover:border-transparent hover:text-inherit;
}
}

View file

View file

@ -0,0 +1,78 @@
.toggle:where(.dark, .dark *) {
--tglbg: theme(colors.slate.800) !important;
}
.toggle {
--tglbg: theme(colors.slate.200);
--animation-input: 0.2s;
--handleoffset: 1.5rem;
--handleoffsetcalculator: calc(var(--handleoffset) * -1);
--togglehandleborder: 0 0;
@apply h-6 w-12 rounded-3xl cursor-pointer appearance-none border border-current bg-current;
transition:
background,
box-shadow var(--animation-input, 0.2s) ease-out;
box-shadow:
var(--handleoffsetcalculator) 0 0 2px var(--tglbg) inset,
0 0 0 2px var(--tglbg) inset,
var(--togglehandleborder);
@apply text-slate-500;
&:focus-visible {
@apply outline outline-2 outline-offset-2;
}
&:hover {
@apply bg-current;
}
&:checked,
&[aria-checked="true"] {
background-image: none;
--handleoffsetcalculator: var(--handleoffset);
}
&:indeterminate {
box-shadow:
calc(var(--handleoffset) / 2) 0 0 2px var(--tglbg) inset,
calc(var(--handleoffset) / -2) 0 0 2px var(--tglbg) inset,
0 0 0 2px var(--tglbg) inset;
}
&:disabled {
@apply cursor-not-allowed bg-transparent opacity-30;
--togglehandleborder: 0 0 0 3px #000 inset,
var(--handleoffsetcalculator) 0 0 3px #000 inset;
}
&.toggle-success {
&:focus-visible {
@apply outline-green-400;
}
&:checked,
&[aria-checked="true"] {
@apply border-green-500 bg-green-400 text-slate-900 border-opacity-10;
}
}
&.toggle-warning {
&:focus-visible {
@apply outline-amber-400;
}
&:checked,
&[aria-checked="true"] {
@apply border-amber-500 bg-amber-400 text-slate-900 border-opacity-10;
}
}
&.toggle-info {
&:focus-visible {
@apply outline-blue-400;
}
&:checked,
&[aria-checked="true"] {
@apply border-blue-500 bg-blue-400 text-slate-900 border-opacity-10;
}
}
&.toggle-danger {
&:focus-visible {
@apply outline-red-400;
}
&:checked,
&[aria-checked="true"] {
@apply border-red-500 bg-red-400 text-slate-900 border-opacity-10;
}
}
}

View file

@ -0,0 +1,27 @@
.slide-fade-enter-active {
transition: all 0.2s ease-out;
}
.slide-fade-leave-active {
transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter-from,
.slide-fade-leave-to {
transform: translateX(20px);
opacity: 0;
}
.slide-fade-reverse-enter-active {
transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-reverse-leave-active {
transition: all 0.2s ease-out;
}
.slide-fade-reverse-enter-from,
.slide-fade-reverse-leave-to {
transform: translateX(-20px);
opacity: 0;
}

View file

@ -20,8 +20,9 @@
remediateSetting(setting)
}
const showModal = ref(false)
function showTheModal() {
admin_modal.value.showModal()
showModal.value = true
clickedButtons.value = []
debouncedGetDiangostic()
}
@ -30,176 +31,169 @@
<template>
<button
@click="showTheModal()"
class="px-2 py-1 rounded-md focus-outline font-semibold bg-blue-600 text-slate-200 hover:bg-blue-700"
@click="showTheModal()"
class="btn btn-primary"
>
<FontAwesomeIcon :icon="faScrewdriverWrench" class="mr-1"></FontAwesomeIcon>
Admin panel
</button>
<FontAwesomeIcon :icon="faScrewdriverWrench" class="mr-1"></FontAwesomeIcon>
Admin panel
</button>
<dialog ref="admin_modal" class="modal">
<div class="modal-box w-11/12 max-w-6xl top-24 absolute bg-slate-200 dark:bg-slate-600 text-slate-700 dark:text-slate-200">
<h2 class="text-2xl font-bold">
<FontAwesomeIcon :icon="faScrewdriverWrench" class=""></FontAwesomeIcon>
Admin panel
</h2>
<div class="modal-action">
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"></button>
</form>
</div>
<div>
<div class="flex mb-5 gap-2">
<button
@click="fullReload()"
class="h-10 min-h-10 px-2 py-1 font-semibold bg-blue-600 text-slate-200 hover:bg-blue-700 btn btn-sm gap-1"
>
<FontAwesomeIcon :icon="faRotate" size="lg" fixed-width></FontAwesomeIcon>
Full refresh
</button>
<button
@click="resetAllExerciseProgress()"
class="h-10 min-h-10 px-2 py-1 font-semibold bg-red-600 text-slate-200 hover:bg-red-700 btn btn-sm gap-1"
>
<FontAwesomeIcon :icon="faTrash" size="lg" fixed-width></FontAwesomeIcon>
Reset All Exercises
</button>
<button
@click="resetAll()"
class="h-10 min-h-10 px-2 py-1 font-semibold bg-red-600 text-slate-200 hover:bg-red-700 btn btn-sm gap-1"
>
<FontAwesomeIcon :icon="faTrash" size="lg" fixed-width></FontAwesomeIcon>
Reset All
</button>
<button
@click="resetLiveLogs()"
class="h-10 min-h-10 px-2 py-1 font-semibold bg-amber-600 text-slate-200 hover:bg-amber-700 btn btn-sm gap-1"
>
<FontAwesomeIcon :icon="faBan" size="lg"> fixed-width</FontAwesomeIcon>
Clear Live Logs
</button>
</div>
<h3 class="text-lg font-semibold">
<FontAwesomeIcon :icon="faGraduationCap" class="mr-1"></FontAwesomeIcon>
Selected Exercises
</h3>
<div
v-for="(exercise) in exercises"
:key="exercise.name"
class="form-control pl-3"
<Modal :showModal="showModal" @modal-close="showModal = false">
<template #header>
<h2 class="text-2xl font-bold">
<FontAwesomeIcon :icon="faScrewdriverWrench" class=""></FontAwesomeIcon>
Admin panel
</h2>
</template>
<template #body>
<div class="dark:text-slate-700 text-slate-700">
<div class="flex mb-5 gap-2">
<button
@click="fullReload()"
class="h-10 min-h-10 font-semibold btn-info btn gap-1"
>
<label class="label cursor-pointer justify-start">
<input
@change="changeSelectionState($event.target.checked, exercise.uuid)"
type="checkbox"
:checked="selected_exercises.includes(exercise.uuid)"
:value="exercise.uuid"
:class="`checkbox ${selected_exercises.includes(exercise.uuid) ? 'checkbox-success' : ''} [--fallback-bc:#94a3b8]`"
/>
<span class="font-mono font-semibold text-base ml-3">{{ exercise.name }}</span>
</label>
</div>
<FontAwesomeIcon :icon="faRotate" size="lg" fixed-width></FontAwesomeIcon>
Full refresh
</button>
<button
@click="resetAllExerciseProgress()"
class="h-10 min-h-10 font-semibold btn-danger btn gap-1"
>
<FontAwesomeIcon :icon="faTrash" size="lg" fixed-width></FontAwesomeIcon>
Reset All Exercises
</button>
<button
@click="resetAll()"
class="h-10 min-h-10 font-semibold btn-danger btn gap-1"
>
<FontAwesomeIcon :icon="faTrash" size="lg" fixed-width></FontAwesomeIcon>
Reset All
</button>
<button
@click="resetLiveLogs()"
class="h-10 min-h-10 font-semibold btn-warning btn gap-1"
>
<FontAwesomeIcon :icon="faBan" size="lg"> fixed-width</FontAwesomeIcon>
Clear Live Logs
</button>
</div>
<h3 class="text-lg font-semibold mt-4">
<FontAwesomeIcon :icon="faSuitcaseMedical" class="mr-1"></FontAwesomeIcon>
Diagnostic
</h3>
<h4 class="font-semibold ml-1 my-3">
<strong>MISP Status:</strong>
<span class="ml-2">
<span :class="{
'rounded-lg py-1 px-2': true,
'dark:bg-neutral-800 bg-neutral-400 text-slate-800 dark:text-slate-200': diagnosticLoading,
'dark:bg-green-700 bg-green-500 text-slate-800 dark:text-slate-200': !diagnosticLoading && isMISPOnline,
'dark:bg-red-700 bg-red-700 text-slate-200 dark:text-slate-200': !diagnosticLoading && !isMISPOnline,
}">
<span v-if="diagnosticLoading" class="loading loading-dots loading-sm h-4 inline-block align-middle"></span>
<span v-else class="font-bold">
{{ !isMISPOnline ? 'Unreachable' : `Online (${diagnostic['version']['version']})` }}
</span>
</span>
</span>
</h4>
<h4 class="font-semibold ml-1 my-3">
<strong>ZMQ Status:</strong>
<span class="ml-2">
<span :class="{
'rounded-lg py-1 px-2': true,
'dark:bg-neutral-800 bg-neutral-400 text-slate-800 dark:text-slate-200': diagnosticLoading,
'dark:bg-green-700 bg-green-500 text-slate-800 dark:text-slate-200': !diagnosticLoading && isZMQActive,
'dark:bg-red-700 bg-red-700 text-slate-200 dark:text-slate-200': !diagnosticLoading && !isZMQActive,
}">
<span v-if="diagnosticLoading" class="loading loading-dots loading-sm h-4 inline-block align-middle"></span>
<span v-else class="font-bold">
{{ !isZMQActive ? 'No message received yet' : `ZMQ Active (${ZMQMessageCount} messages)` }}
</span>
</span>
</span>
</h4>
<h3 class="text-lg font-semibold">
<FontAwesomeIcon :icon="faGraduationCap" class="mr-1"></FontAwesomeIcon>
Selected Exercises
</h3>
<div
v-for="(exercise) in exercises"
:key="exercise.name"
class="form-control pl-3"
>
<label class="label cursor-pointer justify-start">
<input
@change="changeSelectionState($event.target.checked, exercise.uuid)"
type="checkbox"
:checked="selected_exercises.includes(exercise.uuid)"
:value="exercise.uuid"
:class="`checkbox ${selected_exercises.includes(exercise.uuid) ? 'checkbox-success' : ''} [--fallback-bc:#94a3b8]`"
/>
<span class="font-mono font-semibold text-base ml-3">{{ exercise.name }}</span>
</label>
</div>
<template v-if="diagnosticLoading || isMISPOnline">
<h4 class="font-semibold ml-1"><strong>MISP Settings:</strong></h4>
<div class="ml-3">
<div v-if="diagnosticLoading" class="flex justify-center">
<span class="loading loading-dots loading-lg"></span>
</div>
<table v-else class="bg-white dark:bg-slate-700 rounded-lg shadow-xl w-full mt-2">
<thead>
<tr>
<th class="border-b border-slate-200 dark:border-slate-600 p-2 text-left">Setting</th>
<th class="border-b border-slate-200 dark:border-slate-600 p-2 text-left">Value</th>
<th class="border-b border-slate-200 dark:border-slate-600 p-2 text-left">Expected Value</th>
<th class="border-b border-slate-200 dark:border-slate-600 p-2 text-center">Action</th>
</tr>
</thead>
<tbody>
<tr
v-for="(settingValues, setting) in diagnostic['settings']"
:key="setting"
>
<td class="font-mono font-semibold text-base px-2">{{ setting }}</td>
<td
:class="`font-mono text-base tracking-tight px-2 ${settingValues.expected_value != settingValues.value ? 'text-red-600 dark:text-red-600' : ''}`"
>
<i v-if="settingValues.value === undefined || settingValues.value === null" class="text-nowrap">- none -</i>
{{ settingValues.value }}
</td>
<td class="font-mono text-base tracking-tight px-2">{{ settingValues.expected_value }}</td>
<td class="px-2 text-center">
<span v-if="settingValues.error === true"
class="text-red-600 dark:text-red-600"
>Error: {{ settingValues.errorMessage }}</span>
<button
v-else-if="settingValues.expected_value != settingValues.value"
@click="clickedButtons.push(setting) && settingHandler(setting)"
:disabled="clickedButtons.includes(setting)"
class="h-8 min-h-8 px-2 font-semibold bg-green-600 text-slate-200 hover:bg-green-700 btn gap-1"
>
<template v-if="!clickedButtons.includes(setting)">
<FontAwesomeIcon :icon="faHammer" size="sm" fixed-width></FontAwesomeIcon>
Remediate
</template>
<template v-else>
<span class="loading loading-dots loading-sm"></span>
</template>
</button>
<span v-else class="text-base font-bold text-green-600 dark:text-green-600">
<FontAwesomeIcon :icon="faCheck" class=""></FontAwesomeIcon>
OK
</span>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<h3 class="text-lg font-semibold mt-4">
<FontAwesomeIcon :icon="faSuitcaseMedical" class="mr-1"></FontAwesomeIcon>
Diagnostic
</h3>
<h4 class="font-semibold ml-1 my-3">
<strong>MISP Status:</strong>
<span class="ml-2">
<span :class="{
'rounded-lg py-1 px-2 inline-flex': true,
'dark:bg-neutral-800 bg-neutral-400 text-slate-800 dark:text-slate-200': diagnosticLoading,
'dark:bg-green-700 bg-green-500 text-slate-800 dark:text-slate-200': !diagnosticLoading && isMISPOnline,
'dark:bg-red-700 bg-red-700 text-slate-200 dark:text-slate-200': !diagnosticLoading && !isMISPOnline,
}">
<Loading v-if="diagnosticLoading" class="inline-block text-xl"></Loading>
<span v-else class="font-bold">
{{ !isMISPOnline ? 'Unreachable' : `Online (${diagnostic['version']['version']})` }}
</span>
</span>
</span>
</h4>
<h4 class="font-semibold ml-1 my-3">
<strong>ZMQ Status:</strong>
<span class="ml-2">
<span :class="{
'rounded-lg py-1 px-2 inline-flex': true,
'dark:bg-neutral-800 bg-neutral-400 text-slate-800 dark:text-slate-200': diagnosticLoading,
'dark:bg-green-700 bg-green-500 text-slate-800 dark:text-slate-200': !diagnosticLoading && isZMQActive,
'dark:bg-red-700 bg-red-700 text-slate-200 dark:text-slate-200': !diagnosticLoading && !isZMQActive,
}">
<Loading v-if="diagnosticLoading" class="inline-block text-xl"></Loading>
<span v-else class="font-bold">
{{ !isZMQActive ? 'No message received yet' : `ZMQ Active (${ZMQMessageCount} messages)` }}
</span>
</span>
</span>
</h4>
</div>
<template v-if="diagnosticLoading || isMISPOnline">
<h4 class="font-semibold ml-1"><strong>MISP Settings:</strong></h4>
<div class="ml-3">
<div v-if="diagnosticLoading" class="flex justify-center">
<Loading class="text-3xl"></Loading>
</div>
<form method="dialog" class="modal-backdrop backdrop-blur">
<button>close</button>
</form>
</dialog>
<table v-else class="bg-white dark:bg-slate-700 dark:text-slate-100 text-slate-700 rounded-lg shadow-xl w-full mt-2">
<thead>
<tr>
<th class="border-b border-slate-200 dark:border-slate-600 p-2 text-left">Setting</th>
<th class="border-b border-slate-200 dark:border-slate-600 p-2 text-left">Value</th>
<th class="border-b border-slate-200 dark:border-slate-600 p-2 text-left">Expected Value</th>
<th class="border-b border-slate-200 dark:border-slate-600 p-2 text-center">Action</th>
</tr>
</thead>
<tbody>
<tr
v-for="(settingValues, setting) in diagnostic['settings']"
:key="setting"
>
<td class="font-mono font-semibold text-base px-2">{{ setting }}</td>
<td
:class="`font-mono text-base tracking-tight px-2 ${settingValues.expected_value != settingValues.value ? 'text-red-600 dark:text-red-600' : ''}`"
>
<i v-if="settingValues.value === undefined || settingValues.value === null" class="text-nowrap">- none -</i>
{{ settingValues.value }}
</td>
<td class="font-mono text-base tracking-tight px-2">{{ settingValues.expected_value }}</td>
<td class="px-2 text-center">
<span v-if="settingValues.error === true"
class="text-red-600 dark:text-red-600"
>Error: {{ settingValues.errorMessage }}</span>
<button
v-else-if="settingValues.expected_value != settingValues.value"
@click="clickedButtons.push(setting) && settingHandler(setting)"
:disabled="clickedButtons.includes(setting)"
class="h-8 min-h-8 px-2 font-semibold bg-green-600 text-slate-200 hover:bg-green-700 btn gap-1"
>
<template v-if="!clickedButtons.includes(setting)">
<FontAwesomeIcon :icon="faHammer" size="sm" fixed-width></FontAwesomeIcon>
Remediate
</template>
<template v-else>
<Loading class="text-xl"></Loading>
</template>
</button>
<span v-else class="text-base font-bold text-green-600 dark:text-green-600">
<FontAwesomeIcon :icon="faCheck" class=""></FontAwesomeIcon>
OK
</span>
</td>
</tr>
</tbody>
</table>
</div>
</template>
</div>
</template>
</Modal>
</template>

View file

@ -4,6 +4,7 @@
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { faSignal, faCloud, faCog, faUsers, faCircle } from '@fortawesome/free-solid-svg-icons'
import TheLiveLogsActivityGraphVue from "./TheLiveLogsActivityGraph.vue";
import ToggleSwitch from "@/components/elements/ToggleSwitch.vue"
const verbose = ref(false)
@ -60,13 +61,13 @@
</span>
<span class="flex items-center">
<label class="mr-1 flex items-center cursor-pointer text-slate-700 dark:text-slate-300">
<input type="checkbox" class="toggle toggle-warning [--fallback-su:#22c55e] mr-1" :checked="verbose" @change="verbose = !verbose"/>
<input type="checkbox" class="toggle toggle-warning mr-1" :checked="verbose" @change="verbose = !verbose"/>
Verbose
</label>
</span>
<span class="flex items-center">
<label class="mr-1 flex items-center cursor-pointer text-slate-700 dark:text-slate-300">
<input type="checkbox" class="toggle toggle-success [--fallback-su:#22c55e] mr-1" :checked="api_query" @change="api_query = !api_query"/>
<input type="checkbox" class="toggle toggle-success mr-1" :checked="api_query" @change="api_query = !api_query"/>
<FontAwesomeIcon :icon="faCog" size="sm" :mask="faCloud" transform="shrink-7 left-1" class="mr-1"></FontAwesomeIcon>
API Queries
</label>

View file

@ -23,9 +23,9 @@
type="checkbox"
@click="darkMode = !darkMode"
:checked="darkMode"
class="toggle theme-controller bg-slate-400 col-span-2 col-start-1 row-start-1 [--tglbg:#e2e8f0]" />
class="toggle theme-controller bg-slate-500 col-span-2 col-start-1 row-start-1 [--tglbg:#e2e8f0] dark:[--tglbg:#1d232a]" />
<svg
class="stroke-base-100 fill-base-100 col-start-1 row-start-1"
class="stroke-slate-800 dark:stroke-slate-100 fill-slate-800 dark:fill-slate-100 col-start-1 row-start-1"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
@ -40,7 +40,7 @@
d="M12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4" />
</svg>
<svg
class="stroke-base-100 fill-base-100 col-start-2 row-start-1"
class="dark:stroke-slate-800 stroke-slate-700 dark:fill-slate-800 fill-slate-700 col-start-2 row-start-1"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
@ -54,4 +54,42 @@
</svg>
</label>
</div>
</template>
</template>
<style scoped>
.toggle {
--animation-input: 0.2s;
--handleoffset: 1.5rem;
--handleoffsetcalculator: calc(var(--handleoffset) * -1);
--togglehandleborder: 0 0;
@apply h-6 w-12 rounded-3xl cursor-pointer appearance-none border border-current bg-current;
transition:
background,
box-shadow var(--animation-input, 0.2s) ease-out;
box-shadow:
var(--handleoffsetcalculator) 0 0 2px var(--tglbg) inset,
0 0 0 2px var(--tglbg) inset,
var(--togglehandleborder);
&:focus-visible {
@apply outline outline-2 outline-offset-2;
}
&:hover {
@apply bg-current;
}
&:checked,
&[aria-checked="true"] {
background-image: none;
--handleoffsetcalculator: var(--handleoffset);
}
&:indeterminate {
box-shadow:
calc(var(--handleoffset) / 2) 0 0 2px var(--tglbg) inset,
calc(var(--handleoffset) / -2) 0 0 2px var(--tglbg) inset,
0 0 0 2px var(--tglbg) inset;
}
&:disabled {
@apply cursor-not-allowed bg-transparent opacity-30;
--togglehandleborder: 0 0 0 3px #000 inset,
var(--handleoffsetcalculator) 0 0 3px #000 inset;
}
}</style>

View file

@ -0,0 +1,7 @@
<script setup>
import { faSpinner } from '@fortawesome/free-solid-svg-icons'
</script>
<template>
<FontAwesomeIcon :icon="faSpinner" class="fa-spin" fixed-width></FontAwesomeIcon>
</template>

View file

@ -0,0 +1,72 @@
<script setup>
import { ref, watch } from "vue";
import { faTimes } from '@fortawesome/free-solid-svg-icons'
const props = defineProps({
showModal: Boolean,
});
const dialog = ref(null)
const emit = defineEmits(["modal-close"]);
function closeModal() {
emit('modal-close')
}
</script>
<template>
<Teleport to="body">
<div>
<Transition>
<div
v-if="props.showModal"
class="fixed w-4/6 top-20 left-2/4 -translate-x-1/2 rounded-lg border border-slate-800 shadow-lg z-50"
>
<Teleport to="body">
<div
@click.stop="closeModal()"
class="bg-white/30 backdrop-blur-sm fixed top-0 bottom-0 left-0 right-0 z-40 cursor-pointer"
></div>
</Teleport>
<div class="flex px-4 py-3 bg-slate-700 rounded-t-lg border-b border-slate-800">
<h2 class="text-white font-semibold text-lg">
<slot name="header"></slot>
</h2>
<span class="ml-auto text-xl">
<button @click.stop="closeModal()"
class="hover:text-slate-200 hover:dark:text-slate-50 hover:bg-slate-200/20 rounded-full p-1"
>
<FontAwesomeIcon :icon="faTimes" class="fa-fw"></FontAwesomeIcon>
</button>
</span>
</div>
<div class="px-4 py-3 bg-slate-100">
<slot name="body"></slot>
</div>
<div class="px-4 py-3 bg-slate-100 rounded-b-lg">
<slot name="footer">
<div class="flex flex-row-reverse">
<button class="btn btn-primary btn-lg" @click.stop="closeModal()">Ok</button>
</div>
</slot>
</div>
</div>
</Transition>
</div>
</Teleport>
</template>
<style scoped>
.v-enter-active {
@apply transition duration-150 ease-out;
}
.v-leave-active {
@apply transition duration-150 ease-in;
}
.v-enter-from,
.v-leave-to {
@apply scale-90;
@apply opacity-0;
}
</style>

View file

@ -0,0 +1,58 @@
<script setup>
</script>
<template>
<label class="grid cursor-pointer place-items-center">
<input
type="checkbox"
class="toggle theme-controller bg-slate-500 col-span-2 col-start-1 row-start-1 [--tglbg:#e2e8f0] dark:[--tglbg:#1d232a]" />
</label>
</template>
<style scoped>
.toggle {
--animation-input: 0.2s;
--handleoffset: 1.5rem;
--handleoffsetcalculator: calc(var(--handleoffset) * -1);
--togglehandleborder: 0 0;
@apply h-6 w-12 rounded-3xl cursor-pointer appearance-none border border-current bg-current;
transition:
background,
box-shadow var(--animation-input, 0.2s) ease-out;
box-shadow:
var(--handleoffsetcalculator) 0 0 2px var(--tglbg) inset,
0 0 0 2px var(--tglbg) inset,
var(--togglehandleborder);
&:focus-visible {
@apply outline outline-2 outline-offset-2;
}
&:hover {
@apply bg-current;
}
&:checked,
&[aria-checked="true"] {
background-image: none;
--handleoffsetcalculator: var(--handleoffset);
}
&:indeterminate {
box-shadow:
calc(var(--handleoffset) / 2) 0 0 2px var(--tglbg) inset,
calc(var(--handleoffset) / -2) 0 0 2px var(--tglbg) inset,
0 0 0 2px var(--tglbg) inset;
}
&:disabled {
@apply cursor-not-allowed bg-transparent opacity-30;
--togglehandleborder: 0 0 0 3px #000 inset,
var(--handleoffsetcalculator) 0 0 3px #000 inset;
}
&-success {
}
}
/* backward compatibility */
.toggle-mark {
@apply hidden;
}
</style>

View file

@ -4,7 +4,14 @@ import VueApexCharts from "vue3-apexcharts";
import { createApp } from 'vue'
import App from './App.vue'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import Modal from "@/components/elements/Modal.vue"
import Loading from "@/components/elements/Loading.vue"
const app = createApp(App)
app.component('FontAwesomeIcon', FontAwesomeIcon)
app.component('Modal', Modal)
app.component('Loading', Loading)
app.use(VueApexCharts)
app.mount('#app')

34
src/router.js Normal file
View file

@ -0,0 +1,34 @@
import { createWebHistory, createRouter } from 'vue-router'
const routes = [
{ path: '/', component: ScenarioList },
{ path: '/scenarios/index', name: 'Scenario Index', component: ScenarioList, meta: { requiresScenarioSelection: false }, },
{ path: '/scenarios/add', name: 'New Scenario', component: ScenarioNew, meta: { requiresScenarioSelection: false }, },
{ path: '/scenarios/overview/:uuid?', name: 'Scenario Overview', component: ScenarioOverview, meta: { requiresScenarioSelection: true }, props: true },
{ path: '/scenarios/designer/:uuid?', name: 'Scenario Designer', component: ScenarioDesigner, meta: { requiresScenarioSelection: true }, props: true },
{ path: '/injects/tester/:uuid?', name: 'Inject Tester', component: InjectTester, props: true },
]
const router = createRouter({
history: createWebHistory(),
routes,
})
router.beforeEach(async (to, from) => {
if (to.path === '/') {
return { path: '/scenarios/index' }
}
if (!hasScenarios()) {
fetchScenarios()
}
if (from.name == undefined && ['Scenario Overview', 'Scenario Designer'].includes(to.name) && to?.params?.uuid !== undefined) {
store.selected_scenario = to.params.uuid
}
if (to?.meta?.requiresScenarioSelection === true && store.selected_scenario === null) {
return { path: '/scenarios/index' }
}
if (to.matched.length == 0) {
return { path: '/scenarios/index' }
}
})

17
src/utils.js Normal file
View file

@ -0,0 +1,17 @@
let toastID = 0
export const toastBuffer = ref([])
export function toast(toast) {
toastID += 1
toast.id = toastID
toastBuffer.value.push(toast)
}
export function removeToast(id) {
toastBuffer.value = toastBuffer.value.filter((toast) => toast.id != id)
}
export function ajaxFeedback(response) {
toast({
variant: response.success ? 'success' : 'danger',
message: String(response.message),
title: response.title,
})
}

View file

@ -23,17 +23,17 @@ export default {
},
},
plugins: [
require('daisyui'),
// require('daisyui'),
],
darkMode: ['selector'],
daisyui: {
themes: false, // false: only light + dark | true: all themes | array: specific themes like this ["light", "dark", "cupcake"]
darkTheme: "dark", // name of one of the included themes for dark mode
base: false, // applies background color and foreground color for root element by default
styled: true, // include daisyUI colors and design decisions for all components
utils: false, // adds responsive and modifier utility classes
prefix: "", // prefix for daisyUI classnames (components, modifiers and responsive class names. Not colors)
logs: false, // Shows info about daisyUI version and used config in the console when building your CSS
themeRoot: ":root", // The element that receives theme color CSS variables
},
// daisyui: {
// themes: false, // false: only light + dark | true: all themes | array: specific themes like this ["light", "dark", "cupcake"]
// darkTheme: "dark", // name of one of the included themes for dark mode
// base: false, // applies background color and foreground color for root element by default
// styled: true, // include daisyUI colors and design decisions for all components
// utils: false, // adds responsive and modifier utility classes
// prefix: "", // prefix for daisyUI classnames (components, modifiers and responsive class names. Not colors)
// logs: false, // Shows info about daisyUI version and used config in the console when building your CSS
// themeRoot: ":root", // The element that receives theme color CSS variables
// },
}