chg: [front] Removed daisyUI dependency
This commit is contained in:
parent
014f55a2c4
commit
77238fabe9
17 changed files with 608 additions and 234 deletions
47
package-lock.json
generated
47
package-lock.json
generated
|
@ -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 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
83
src/assets/styled-components/button.css
Normal file
83
src/assets/styled-components/button.css
Normal 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;
|
||||
}
|
||||
}
|
0
src/assets/styled-components/modal.css
Normal file
0
src/assets/styled-components/modal.css
Normal file
78
src/assets/styled-components/toggle.css
Normal file
78
src/assets/styled-components/toggle.css
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
27
src/assets/styled-components/transitions.css
Normal file
27
src/assets/styled-components/transitions.css
Normal 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;
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
7
src/components/elements/Loading.vue
Normal file
7
src/components/elements/Loading.vue
Normal 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>
|
72
src/components/elements/Modal.vue
Normal file
72
src/components/elements/Modal.vue
Normal 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>
|
58
src/components/elements/ToggleSwitch.vue
Normal file
58
src/components/elements/ToggleSwitch.vue
Normal 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>
|
|
@ -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
34
src/router.js
Normal 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
17
src/utils.js
Normal 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,
|
||||
})
|
||||
}
|
|
@ -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
|
||||
// },
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue