mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-21 21:33:18 +01:00
Settings (#216)
* Settings in WIP * Updates some styles * Removes unused import * Adds version and switcher * Adds ionicons instead of fontawesome * Fixes ionicon for vuejs * Updates modules * Adds buefy * Adds search filter as settings * Adds localstorage * Fixes tests * Adds settings for menu width * Changes copy
This commit is contained in:
@@ -18,7 +18,8 @@ describe("<App />", () => {
|
|||||||
containers: [
|
containers: [
|
||||||
{ id: "abc", name: "Test 1" },
|
{ id: "abc", name: "Test 1" },
|
||||||
{ id: "xyz", name: "Test 2" }
|
{ id: "xyz", name: "Test 2" }
|
||||||
]
|
],
|
||||||
|
settings: { menuWidth: 15 }
|
||||||
};
|
};
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<main>
|
<main>
|
||||||
<mobile-menu v-if="isMobile"></mobile-menu>
|
<mobile-menu v-if="isMobile"></mobile-menu>
|
||||||
<splitpanes>
|
<splitpanes @resized="updateSetting({ menuWidth: $event[0].size })">
|
||||||
<pane min-size="10" size="15" v-if="!isMobile">
|
<pane min-size="10" :size="settings.menuWidth" v-if="!isMobile">
|
||||||
<side-menu></side-menu>
|
<side-menu></side-menu>
|
||||||
</pane>
|
</pane>
|
||||||
<pane :size="isMobile ? 100 : 85">
|
<pane :size="isMobile ? 100 : 100 - settings.menuWidth" min-size="10">
|
||||||
<splitpanes>
|
<splitpanes>
|
||||||
<pane>
|
<pane>
|
||||||
|
<search></search>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</pane>
|
</pane>
|
||||||
<pane v-for="other in activeContainers" :key="other.id">
|
<pane v-for="other in activeContainers" :key="other.id">
|
||||||
@@ -37,6 +38,7 @@ import LogViewerWithSource from "./components/LogViewerWithSource";
|
|||||||
import ScrollableView from "./components/ScrollableView";
|
import ScrollableView from "./components/ScrollableView";
|
||||||
import SideMenu from "./components/SideMenu";
|
import SideMenu from "./components/SideMenu";
|
||||||
import MobileMenu from "./components/MobileMenu";
|
import MobileMenu from "./components/MobileMenu";
|
||||||
|
import Search from "./components/Search";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
@@ -46,7 +48,8 @@ export default {
|
|||||||
MobileMenu,
|
MobileMenu,
|
||||||
ScrollableView,
|
ScrollableView,
|
||||||
Splitpanes,
|
Splitpanes,
|
||||||
Pane
|
Pane,
|
||||||
|
Search
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -65,12 +68,13 @@ export default {
|
|||||||
this.title = `${this.containers.length} containers`;
|
this.title = `${this.containers.length} containers`;
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["containers", "activeContainers", "isMobile"])
|
...mapState(["containers", "activeContainers", "isMobile", "settings"])
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions({
|
...mapActions({
|
||||||
fetchContainerList: "FETCH_CONTAINERS",
|
fetchContainerList: "FETCH_CONTAINERS",
|
||||||
removeActiveContainer: "REMOVE_ACTIVE_CONTAINER"
|
removeActiveContainer: "REMOVE_ACTIVE_CONTAINER",
|
||||||
|
updateSetting: "UPDATE_SETTING"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -91,4 +95,8 @@ export default {
|
|||||||
background: rgb(255, 221, 87);
|
background: rgb(255, 221, 87);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button.has-no-border {
|
||||||
|
border-color: transparent !important;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ exports[`<App /> renders correctly 1`] = `
|
|||||||
|
|
||||||
<pane-stub
|
<pane-stub
|
||||||
maxsize="100"
|
maxsize="100"
|
||||||
minsize="0"
|
minsize="10"
|
||||||
size="85"
|
size="85"
|
||||||
>
|
>
|
||||||
<splitpanes-stub
|
<splitpanes-stub
|
||||||
@@ -29,6 +29,8 @@ exports[`<App /> renders correctly 1`] = `
|
|||||||
maxsize="100"
|
maxsize="100"
|
||||||
minsize="0"
|
minsize="0"
|
||||||
>
|
>
|
||||||
|
<search-stub />
|
||||||
|
|
||||||
<router-view-stub />
|
<router-view-stub />
|
||||||
</pane-stub>
|
</pane-stub>
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ describe("<LogEventSource />", () => {
|
|||||||
localVue.component("log-event-source", LogEventSource);
|
localVue.component("log-event-source", LogEventSource);
|
||||||
localVue.component("log-viewer", LogViewer);
|
localVue.component("log-viewer", LogViewer);
|
||||||
|
|
||||||
const state = { searchFilter };
|
const state = { searchFilter, settings: { size: "medium" } };
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
state
|
state
|
||||||
@@ -66,7 +66,7 @@ describe("<LogEventSource />", () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ul
|
<ul
|
||||||
class="events"
|
class="events medium"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
`);
|
`);
|
||||||
@@ -126,7 +126,7 @@ describe("<LogEventSource />", () => {
|
|||||||
sources["/api/logs/stream?id=abc"].emitMessage({ data: `2019-06-12T10:55:42.459034602Z "This is a message."` });
|
sources["/api/logs/stream?id=abc"].emitMessage({ data: `2019-06-12T10:55:42.459034602Z "This is a message."` });
|
||||||
|
|
||||||
expect(wrapper.find("ul.events")).toMatchInlineSnapshot(`
|
expect(wrapper.find("ul.events")).toMatchInlineSnapshot(`
|
||||||
<ul class="events">
|
<ul class="events medium">
|
||||||
<li><span class="date">today at 10:55 AM</span> <span class="text">"This is a message."</span></li>
|
<li><span class="date">today at 10:55 AM</span> <span class="text">"This is a message."</span></li>
|
||||||
</ul>
|
</ul>
|
||||||
`);
|
`);
|
||||||
@@ -140,7 +140,7 @@ describe("<LogEventSource />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find("ul.events")).toMatchInlineSnapshot(`
|
expect(wrapper.find("ul.events")).toMatchInlineSnapshot(`
|
||||||
<ul class="events">
|
<ul class="events medium">
|
||||||
<li><span class="date">today at 10:55 AM</span> <span class="text"><span style="color:#000">black<span style="color:#AAA">white</span></span></span></li>
|
<li><span class="date">today at 10:55 AM</span> <span class="text"><span style="color:#000">black<span style="color:#AAA">white</span></span></span></li>
|
||||||
</ul>
|
</ul>
|
||||||
`);
|
`);
|
||||||
@@ -154,7 +154,7 @@ describe("<LogEventSource />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find("ul.events")).toMatchInlineSnapshot(`
|
expect(wrapper.find("ul.events")).toMatchInlineSnapshot(`
|
||||||
<ul class="events">
|
<ul class="events medium">
|
||||||
<li><span class="date">today at 10:55 AM</span> <span class="text"><test>foo bar</test></span></li>
|
<li><span class="date">today at 10:55 AM</span> <span class="text"><test>foo bar</test></span></li>
|
||||||
</ul>
|
</ul>
|
||||||
`);
|
`);
|
||||||
@@ -171,7 +171,7 @@ describe("<LogEventSource />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(wrapper.find("ul.events")).toMatchInlineSnapshot(`
|
expect(wrapper.find("ul.events")).toMatchInlineSnapshot(`
|
||||||
<ul class="events">
|
<ul class="events medium">
|
||||||
<li><span class="date">today at 10:55 AM</span> <span class="text">This is a <mark>test</mark> <hi></hi></span></li>
|
<li><span class="date">today at 10:55 AM</span> <span class="text">This is a <mark>test</mark> <hi></hi></span></li>
|
||||||
</ul>
|
</ul>
|
||||||
`);
|
`);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<ul class="events">
|
<ul class="events" :class="settings.size">
|
||||||
<li v-for="item in filtered" :key="item.key">
|
<li v-for="item in filtered" :key="item.key">
|
||||||
<span class="date">{{ item.date | relativeTime }}</span>
|
<span class="date">{{ item.date | relativeTime }}</span>
|
||||||
<span class="text" v-html="colorize(item.message)"></span>
|
<span class="text" v-html="colorize(item.message)"></span>
|
||||||
@@ -32,7 +32,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["searchFilter"]),
|
...mapState(["searchFilter", "settings"]),
|
||||||
filtered() {
|
filtered() {
|
||||||
const { searchFilter, messages } = this;
|
const { searchFilter, messages } = this;
|
||||||
if (searchFilter) {
|
if (searchFilter) {
|
||||||
@@ -69,9 +69,20 @@ export default {
|
|||||||
font-family: "Roboto Mono", monaco, monospace;
|
font-family: "Roboto Mono", monaco, monospace;
|
||||||
|
|
||||||
& > li {
|
& > li {
|
||||||
font-size: 13px;
|
|
||||||
line-height: 16px;
|
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
line-height: 130%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.small {
|
||||||
|
font-size: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.medium {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.large {
|
||||||
|
font-size: 120%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +95,7 @@ export default {
|
|||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
>>> mark {
|
::v-deep mark {
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background-color: #ffdd57;
|
background-color: #ffdd57;
|
||||||
animation: pops 0.2s ease-out;
|
animation: pops 0.2s ease-out;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
@click="scrollToBottom('smooth')"
|
@click="scrollToBottom('smooth')"
|
||||||
v-show="paused"
|
v-show="paused"
|
||||||
>
|
>
|
||||||
<span class="icon large"> <i class="fas fa-chevron-down"></i> </span>
|
<ion-icon name="download"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div class="search columns is-gapless is-vcentered" v-show="showSearch">
|
<div class="search columns is-gapless is-vcentered" v-show="showSearch" v-if="settings.search">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<p class="control has-icons-left">
|
<p class="control has-icons-left">
|
||||||
<input class="input" type="text" placeholder="Filter" ref="filter" v-model="filter" />
|
<input
|
||||||
<span class="icon is-small is-left"><i class="fas fa-search"></i></span>
|
class="input"
|
||||||
|
type="text"
|
||||||
|
placeholder="Filter"
|
||||||
|
ref="filter"
|
||||||
|
v-model="filter"
|
||||||
|
@keyup.esc="resetSearch()"
|
||||||
|
/>
|
||||||
|
<span class="icon is-small is-left"><ion-icon name="search"></ion-icon></span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-1 has-text-centered">
|
<div class="column is-1 has-text-centered">
|
||||||
@@ -14,6 +21,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapActions, mapState } from "vuex";
|
import { mapActions, mapState } from "vuex";
|
||||||
|
import hotkeys from "hotkeys-js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: [],
|
props: [],
|
||||||
name: "Search",
|
name: "Search",
|
||||||
@@ -23,31 +32,26 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
window.addEventListener("keydown", this.onKeyDown);
|
hotkeys("command+f, ctrl+f", (event, handler) => {
|
||||||
},
|
this.showSearch = true;
|
||||||
destroyed() {
|
this.$nextTick(() => this.$refs.filter.focus() || this.$refs.filter.select());
|
||||||
window.removeEventListener("keydown", this.onKeyDown);
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
hotkeys("esc", (event, handler) => {
|
||||||
|
this.resetSearch();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapActions({
|
...mapActions({
|
||||||
updateSearchFilter: "SET_SEARCH"
|
updateSearchFilter: "SET_SEARCH"
|
||||||
}),
|
}),
|
||||||
onKeyDown(e) {
|
|
||||||
if ((e.metaKey || e.ctrlKey) && e.key === "f") {
|
|
||||||
this.showSearch = true;
|
|
||||||
this.$nextTick(() => this.$refs.filter.focus());
|
|
||||||
e.preventDefault();
|
|
||||||
} else if (e.key === "Escape") {
|
|
||||||
this.resetSearch();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
resetSearch() {
|
resetSearch() {
|
||||||
this.showSearch = false;
|
this.showSearch = false;
|
||||||
this.filter = "";
|
this.filter = "";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["searchFilter"]),
|
...mapState(["searchFilter", "settings"]),
|
||||||
filter: {
|
filter: {
|
||||||
get() {
|
get() {
|
||||||
return this.searchFilter;
|
return this.searchFilter;
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<aside>
|
<aside>
|
||||||
<h1 class="title has-text-warning is-marginless">Dozzle</h1>
|
<div class="columns is-marginless">
|
||||||
|
<div class="column">
|
||||||
|
<h1 class="title has-text-warning is-marginless">Dozzle</h1>
|
||||||
|
</div>
|
||||||
|
<div class="column is-narrow has-text-right is-hidden-mobile">
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'settings' }"
|
||||||
|
active-class="is-active"
|
||||||
|
class="button is-small is-primary is-rounded is-inverted is-outlined "
|
||||||
|
>
|
||||||
|
<span class="icon"><ion-icon name="settings" size="large"></ion-icon></span>
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<p class="menu-label is-hidden-mobile">Containers</p>
|
<p class="menu-label is-hidden-mobile">Containers</p>
|
||||||
<ul class="menu-list is-hidden-mobile">
|
<ul class="menu-list is-hidden-mobile">
|
||||||
<li v-for="item in containers">
|
<li v-for="item in containers">
|
||||||
@@ -15,7 +28,7 @@
|
|||||||
class="icon is-small will-append-container"
|
class="icon is-small will-append-container"
|
||||||
:class="{ 'is-active': activeContainersById[item.id] }"
|
:class="{ 'is-active': activeContainersById[item.id] }"
|
||||||
>
|
>
|
||||||
<i class="fas fa-thumbtack"></i>
|
<ion-icon name="ios-add-circle"></ion-icon>
|
||||||
</span>
|
</span>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</div>
|
</div>
|
||||||
@@ -74,7 +87,6 @@ aside {
|
|||||||
.will-append-container.icon {
|
.will-append-container.icon {
|
||||||
transition: transform 0.2s ease-out;
|
transition: transform 0.2s ease-out;
|
||||||
&.is-active {
|
&.is-active {
|
||||||
transform: rotate(25deg);
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
color: #00d1b2;
|
color: #00d1b2;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,13 @@
|
|||||||
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono|Gafata" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono|Gafata" rel="stylesheet" />
|
||||||
<link rel="manifest" href="manifest.webmanifest" />
|
<link rel="manifest" href="manifest.webmanifest" />
|
||||||
<link href="styles.scss" rel="stylesheet" />
|
<link href="styles.scss" rel="stylesheet" />
|
||||||
<link rel="icon" href="favicon.ico">
|
<link rel="icon" href="favicon.ico" />
|
||||||
<script>
|
<script>
|
||||||
window["BASE_PATH"] = "{{ .Base }}";
|
window["BASE_PATH"] = "{{ .Base }}";
|
||||||
|
window["VERSION"] = "{{ .Version }}";
|
||||||
</script>
|
</script>
|
||||||
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
|
<script type="module" src="https://unpkg.com/ionicons@4.5.10-0/dist/ionicons/ionicons.esm.js"></script>
|
||||||
|
<script nomodule="" src="https://unpkg.com/ionicons@4.5.10-0/dist/ionicons/ionicons.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="is-dark">
|
<body class="is-dark">
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import VueRouter from "vue-router";
|
import VueRouter from "vue-router";
|
||||||
import Meta from "vue-meta";
|
import Meta from "vue-meta";
|
||||||
import Vuex from "vuex";
|
import { Dropdown, Switch } from "buefy";
|
||||||
import store from "./store";
|
import store from "./store";
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import Container from "./pages/Container.vue";
|
import Container from "./pages/Container.vue";
|
||||||
|
import Settings from "./pages/Settings.vue";
|
||||||
import Index from "./pages/Index.vue";
|
import Index from "./pages/Index.vue";
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
Vue.use(Meta);
|
Vue.use(Meta);
|
||||||
|
Vue.use(Dropdown);
|
||||||
|
Vue.use(Switch);
|
||||||
|
|
||||||
|
Vue.config.ignoredElements = [/^ion-/];
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
@@ -21,6 +26,11 @@ const routes = [
|
|||||||
component: Container,
|
component: Container,
|
||||||
name: "container",
|
name: "container",
|
||||||
props: true
|
props: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/settings",
|
||||||
|
component: Settings,
|
||||||
|
name: "settings"
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div>
|
<div>
|
||||||
<search></search>
|
|
||||||
<scrollable-logs-with-source :id="id"></scrollable-logs-with-source>
|
<scrollable-logs-with-source :id="id"></scrollable-logs-with-source>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ScrollableLogsWithSource from "../components/ScrollableLogsWithSource";
|
import ScrollableLogsWithSource from "../components/ScrollableLogsWithSource";
|
||||||
import Search from "../components/Search";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ["id", "name"],
|
props: ["id", "name"],
|
||||||
name: "Container",
|
name: "Container",
|
||||||
components: {
|
components: {
|
||||||
ScrollableLogsWithSource,
|
ScrollableLogsWithSource
|
||||||
Search
|
|
||||||
},
|
},
|
||||||
metaInfo() {
|
metaInfo() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
143
assets/pages/Settings.vue
Normal file
143
assets/pages/Settings.vue
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
<template lang="html">
|
||||||
|
<div class="is-fullheight">
|
||||||
|
<section class="section">
|
||||||
|
<div class="has-underline">
|
||||||
|
<h2 class="title is-4">About</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="title is-6 is-marginless">Version</h2>
|
||||||
|
<div>
|
||||||
|
You are using Dozzle <i>{{ currentVersion }}</i
|
||||||
|
>.
|
||||||
|
<span v-if="hasUpdate">
|
||||||
|
New version is available! Update to
|
||||||
|
<a :href="nextRelease.html_url" class="next-release">{{ nextRelease.name }}</a
|
||||||
|
>.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="section">
|
||||||
|
<div class="has-underline">
|
||||||
|
<h2 class="title is-4">Display</h2>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<b-switch v-model="search">
|
||||||
|
Enable searching with Dozzle using <code>command+f</code> or <code>ctrl+f</code>
|
||||||
|
</b-switch>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item">
|
||||||
|
<h2 class="title is-6 is-marginless">Font size</h2>
|
||||||
|
|
||||||
|
Modify the font size when viewing logs.
|
||||||
|
<br /><br />
|
||||||
|
<b-dropdown v-model="size" aria-role="list">
|
||||||
|
<button class="button is-primary" type="button" slot="trigger">
|
||||||
|
<span class="is-capitalized">{{ size }}</span>
|
||||||
|
<span class="icon"><ion-icon name="ios-arrow-down"></ion-icon></span>
|
||||||
|
</button>
|
||||||
|
<b-dropdown-item :value="value" aria-role="listitem" v-for="value in ['small', 'medium', 'large']">
|
||||||
|
<div class="media">
|
||||||
|
<span class="icon">
|
||||||
|
<ion-icon name="checkmark" v-if="value == size"></ion-icon>
|
||||||
|
</span>
|
||||||
|
<div class="media-content">
|
||||||
|
<h3 class="is-capitalized">{{ value }}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</b-dropdown-item>
|
||||||
|
</b-dropdown>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import gt from "semver/functions/gt";
|
||||||
|
import valid from "semver/functions/valid";
|
||||||
|
import { mapActions, mapState } from "vuex";
|
||||||
|
|
||||||
|
function computedSettings(names) {
|
||||||
|
return names.reduce((map, name) => {
|
||||||
|
map[name] = {
|
||||||
|
get() {
|
||||||
|
return this.settings[name];
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.updateSetting({ [name]: value });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return map;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: [],
|
||||||
|
name: "Settings",
|
||||||
|
components: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentVersion: VERSION,
|
||||||
|
nextRelease: null,
|
||||||
|
hasUpdate: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
async created() {
|
||||||
|
const releases = await (await fetch("https://api.github.com/repos/amir20/dozzle/releases")).json();
|
||||||
|
this.hasUpdate = gt(releases[0].tag_name, this.currentVersion);
|
||||||
|
this.nextRelease = releases[0];
|
||||||
|
},
|
||||||
|
metaInfo() {
|
||||||
|
return {
|
||||||
|
title: "Settings",
|
||||||
|
titleTemplate: "%s - Dozzle"
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapActions({
|
||||||
|
updateSetting: "UPDATE_SETTING"
|
||||||
|
})
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["settings"]),
|
||||||
|
...computedSettings.bind(this)(["search", "size"])
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.is-fullheight {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.next-release {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #00d1b2;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.has-underline {
|
||||||
|
border-bottom: 1px solid #fff;
|
||||||
|
padding: 1em 0px;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
padding: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #444;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
import Vue from "vue";
|
import Vue from "vue";
|
||||||
import Vuex from "vuex";
|
import Vuex from "vuex";
|
||||||
|
import storage from "store/dist/store.modern";
|
||||||
|
import { DEFAULT_SETTINGS, DOZZLE_SETTINGS_KEY } from "./settings";
|
||||||
|
|
||||||
|
Vue.use(Vuex);
|
||||||
|
|
||||||
const mql = window.matchMedia("(max-width: 770px)");
|
const mql = window.matchMedia("(max-width: 770px)");
|
||||||
|
|
||||||
Vue.use(Vuex);
|
storage.set(DOZZLE_SETTINGS_KEY, { ...DEFAULT_SETTINGS, ...storage.get(DOZZLE_SETTINGS_KEY) });
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
containers: [],
|
containers: [],
|
||||||
activeContainers: [],
|
activeContainers: [],
|
||||||
searchFilter: null,
|
searchFilter: null,
|
||||||
isMobile: mql.matches
|
isMobile: mql.matches,
|
||||||
|
settings: storage.get(DOZZLE_SETTINGS_KEY)
|
||||||
};
|
};
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
@@ -27,6 +32,10 @@ const mutations = {
|
|||||||
},
|
},
|
||||||
SET_MOBILE_WIDTH(state, value) {
|
SET_MOBILE_WIDTH(state, value) {
|
||||||
state.isMobile = value;
|
state.isMobile = value;
|
||||||
|
},
|
||||||
|
UPDATE_SETTINGS(state, newValues) {
|
||||||
|
state.settings = { ...state.settings, ...newValues };
|
||||||
|
storage.set(DOZZLE_SETTINGS_KEY, state.settings);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,13 +52,15 @@ const actions = {
|
|||||||
async FETCH_CONTAINERS({ commit }) {
|
async FETCH_CONTAINERS({ commit }) {
|
||||||
const containers = await (await fetch(`${BASE_PATH}/api/containers.json`)).json();
|
const containers = await (await fetch(`${BASE_PATH}/api/containers.json`)).json();
|
||||||
commit("SET_CONTAINERS", containers);
|
commit("SET_CONTAINERS", containers);
|
||||||
|
},
|
||||||
|
UPDATE_SETTING({ commit }, setting) {
|
||||||
|
commit("UPDATE_SETTINGS", setting);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const getters = {};
|
const getters = {};
|
||||||
|
|
||||||
const es = new EventSource(`${BASE_PATH}/api/events/stream`);
|
const es = new EventSource(`${BASE_PATH}/api/events/stream`);
|
||||||
es.addEventListener("containers-changed", e => setTimeout(() => store.dispatch("FETCH_CONTAINERS"), 1000), false);
|
es.addEventListener("containers-changed", e => setTimeout(() => store.dispatch("FETCH_CONTAINERS"), 1000), false);
|
||||||
|
|
||||||
mql.addListener(e => store.commit("SET_MOBILE_WIDTH", e.matches));
|
mql.addListener(e => store.commit("SET_MOBILE_WIDTH", e.matches));
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
|
|||||||
6
assets/store/settings.js
Normal file
6
assets/store/settings.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export const DOZZLE_SETTINGS_KEY = "DOZZLE_SETTINGS";
|
||||||
|
export const DEFAULT_SETTINGS = {
|
||||||
|
search: true,
|
||||||
|
size: "medium",
|
||||||
|
menuWidth: 15
|
||||||
|
};
|
||||||
@@ -3,8 +3,11 @@
|
|||||||
$menu-item-active-background-color: hsl(171, 100%, 41%);
|
$menu-item-active-background-color: hsl(171, 100%, 41%);
|
||||||
$menu-item-color: hsl(0, 6%, 87%);
|
$menu-item-color: hsl(0, 6%, 87%);
|
||||||
|
|
||||||
@import "../node_modules/bulma/bulma.sass";
|
@import "~bulma";
|
||||||
@import "../node_modules/splitpanes/dist/splitpanes.css";
|
@import "../node_modules/splitpanes/dist/splitpanes.css";
|
||||||
|
@import "~buefy/src/scss/utils/_all";
|
||||||
|
@import "~buefy/src/scss/components/_dropdown";
|
||||||
|
@import "~buefy/src/scss/components/_switch";
|
||||||
|
|
||||||
.is-dark {
|
.is-dark {
|
||||||
color: #ddd;
|
color: #ddd;
|
||||||
|
|||||||
5
main.go
5
main.go
@@ -150,7 +150,10 @@ func (h *handler) index(w http.ResponseWriter, req *http.Request) {
|
|||||||
path = base
|
path = base
|
||||||
}
|
}
|
||||||
|
|
||||||
data := struct{ Base string }{path}
|
data := struct {
|
||||||
|
Base string
|
||||||
|
Version string
|
||||||
|
}{path, version}
|
||||||
err = tmpl.Execute(w, data)
|
err = tmpl.Execute(w, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
|||||||
107
package-lock.json
generated
107
package-lock.json
generated
@@ -153,6 +153,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1202,6 +1208,12 @@
|
|||||||
"lodash": "^4.17.13",
|
"lodash": "^4.17.13",
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1331,6 +1343,12 @@
|
|||||||
"lodash": "^4.17.13",
|
"lodash": "^4.17.13",
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2766,6 +2784,21 @@
|
|||||||
"node-int64": "^0.4.0"
|
"node-int64": "^0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"buefy": {
|
||||||
|
"version": "0.8.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/buefy/-/buefy-0.8.8.tgz",
|
||||||
|
"integrity": "sha512-kTUnroPBLm998KFZbeJuUgJV+nJbDUJxw1c8gzeJoe+Mve73Nb3hi6AZpgrIH8FtXmh5r8nMBYBqwN54EtPWXg==",
|
||||||
|
"requires": {
|
||||||
|
"bulma": "0.7.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bulma": {
|
||||||
|
"version": "0.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.7.5.tgz",
|
||||||
|
"integrity": "sha512-cX98TIn0I6sKba/DhW0FBjtaDpxTelU166pf7ICXpCCuplHWyu6C9LYZmL5PEsnePIeJaiorsTEzzNk3Tsm1hw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"buffer": {
|
"buffer": {
|
||||||
"version": "4.9.1",
|
"version": "4.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
||||||
@@ -3417,6 +3450,14 @@
|
|||||||
"semver": "^5.5.0",
|
"semver": "^5.5.0",
|
||||||
"shebang-command": "^1.2.0",
|
"shebang-command": "^1.2.0",
|
||||||
"which": "^1.2.9"
|
"which": "^1.2.9"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"crypto-browserify": {
|
"crypto-browserify": {
|
||||||
@@ -4156,6 +4197,12 @@
|
|||||||
"pseudomap": "^1.0.2",
|
"pseudomap": "^1.0.2",
|
||||||
"yallist": "^2.1.2"
|
"yallist": "^2.1.2"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -5585,6 +5632,11 @@
|
|||||||
"integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
|
"integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"hotkeys-js": {
|
||||||
|
"version": "3.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.7.3.tgz",
|
||||||
|
"integrity": "sha512-CSaeVPAKEEYNexYR35znMJnCqoofk7oqG/AOOqWow1qDT0Yxy+g+Y8Hs/LhGlsZaSJ7973YN6/N41LAr3t30QQ=="
|
||||||
|
},
|
||||||
"hsl-regex": {
|
"hsl-regex": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
|
||||||
@@ -5774,6 +5826,14 @@
|
|||||||
"resolve": "^1.10.0",
|
"resolve": "^1.10.0",
|
||||||
"semver": "2 || 3 || 4 || 5",
|
"semver": "2 || 3 || 4 || 5",
|
||||||
"validate-npm-package-license": "^3.0.1"
|
"validate-npm-package-license": "^3.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"parse-json": {
|
"parse-json": {
|
||||||
@@ -7783,6 +7843,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||||
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
|
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -8133,6 +8199,14 @@
|
|||||||
"semver": "^5.5.0",
|
"semver": "^5.5.0",
|
||||||
"shellwords": "^0.1.1",
|
"shellwords": "^0.1.1",
|
||||||
"which": "^1.3.0"
|
"which": "^1.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-releases": {
|
"node-releases": {
|
||||||
@@ -8178,6 +8252,14 @@
|
|||||||
"is-builtin-module": "^1.0.0",
|
"is-builtin-module": "^1.0.0",
|
||||||
"semver": "2 || 3 || 4 || 5",
|
"semver": "2 || 3 || 4 || 5",
|
||||||
"validate-npm-package-license": "^3.0.1"
|
"validate-npm-package-license": "^3.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"normalize-path": {
|
"normalize-path": {
|
||||||
@@ -8754,6 +8836,12 @@
|
|||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
@@ -10130,9 +10218,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sass": {
|
"sass": {
|
||||||
"version": "1.23.7",
|
"version": "1.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.23.7.tgz",
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.24.0.tgz",
|
||||||
"integrity": "sha512-cYgc0fanwIpi0rXisGxl+/wadVQ/HX3RhpdRcjLdj2o2ye/sxUTpAxIhbmJy3PLQgRFbf6Pn8Jsrta2vdXcoOQ==",
|
"integrity": "sha512-1TsPyMhLTx+9DLlmwg02iBW2p4poGA7LlkWJLpUY/XticFKNhPcx+l4FsIJLKl6oSUfXmAKpVljHEez1hwjqiw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chokidar": ">=2.0.0 <4.0.0"
|
"chokidar": ">=2.0.0 <4.0.0"
|
||||||
@@ -10154,10 +10242,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.6.0",
|
"version": "7.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.1.1.tgz",
|
||||||
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
|
"integrity": "sha512-WfuG+fl6eh3eZ2qAf6goB7nhiCd7NPXhmyFxigB/TOkQyeLP8w8GsVehvtGNtnNmyboz4TgeK40B1Kbql/8c5A=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"semver-compare": {
|
"semver-compare": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -10535,9 +10622,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"splitpanes": {
|
"splitpanes": {
|
||||||
"version": "2.1.2",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-2.2.0.tgz",
|
||||||
"integrity": "sha512-IiVeC1wk7yVq4QZ3VTj6FbOTUJQmy/gFxpR1pDk67P+Pj8V0daUsPeoBNcKmcvJp2v3272GHSeLTNEyDCKRXSQ=="
|
"integrity": "sha512-n87JXR3xNHC6Zrcvg1JGU4wgqOxV95bFShhHhGM/cvQVFxN2HRJuaVWvvwgQzd9cF+4UyXtjcreqkOxr5bPnoA=="
|
||||||
},
|
},
|
||||||
"sprintf-js": {
|
"sprintf-js": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
|
|||||||
@@ -25,10 +25,13 @@
|
|||||||
"homepage": "https://github.com/amir20/dozzle#readme",
|
"homepage": "https://github.com/amir20/dozzle#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-to-html": "^0.6.13",
|
"ansi-to-html": "^0.6.13",
|
||||||
|
"buefy": "^0.8.8",
|
||||||
"bulma": "^0.8.0",
|
"bulma": "^0.8.0",
|
||||||
"date-fns": "^2.8.1",
|
"date-fns": "^2.8.1",
|
||||||
|
"hotkeys-js": "^3.7.3",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"splitpanes": "^2.1.2",
|
"semver": "^7.1.1",
|
||||||
|
"splitpanes": "^2.2.0",
|
||||||
"store": "^2.0.12",
|
"store": "^2.0.12",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-meta": "^2.3.1",
|
"vue-meta": "^2.3.1",
|
||||||
@@ -52,7 +55,7 @@
|
|||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"parcel-bundler": "^1.12.4",
|
"parcel-bundler": "^1.12.4",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
"sass": "^1.23.7",
|
"sass": "^1.24.0",
|
||||||
"vue-hot-reload-api": "^2.3.4",
|
"vue-hot-reload-api": "^2.3.4",
|
||||||
"vue-jest": "^3.0.5",
|
"vue-jest": "^3.0.5",
|
||||||
"vue-template-compiler": "^2.6.11"
|
"vue-template-compiler": "^2.6.11"
|
||||||
|
|||||||
Reference in New Issue
Block a user