mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-21 13:23:07 +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: [
|
||||
{ id: "abc", name: "Test 1" },
|
||||
{ id: "xyz", name: "Test 2" }
|
||||
]
|
||||
],
|
||||
settings: { menuWidth: 15 }
|
||||
};
|
||||
|
||||
const actions = {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
<template lang="html">
|
||||
<main>
|
||||
<mobile-menu v-if="isMobile"></mobile-menu>
|
||||
<splitpanes>
|
||||
<pane min-size="10" size="15" v-if="!isMobile">
|
||||
<splitpanes @resized="updateSetting({ menuWidth: $event[0].size })">
|
||||
<pane min-size="10" :size="settings.menuWidth" v-if="!isMobile">
|
||||
<side-menu></side-menu>
|
||||
</pane>
|
||||
<pane :size="isMobile ? 100 : 85">
|
||||
<pane :size="isMobile ? 100 : 100 - settings.menuWidth" min-size="10">
|
||||
<splitpanes>
|
||||
<pane>
|
||||
<search></search>
|
||||
<router-view></router-view>
|
||||
</pane>
|
||||
<pane v-for="other in activeContainers" :key="other.id">
|
||||
@@ -37,6 +38,7 @@ import LogViewerWithSource from "./components/LogViewerWithSource";
|
||||
import ScrollableView from "./components/ScrollableView";
|
||||
import SideMenu from "./components/SideMenu";
|
||||
import MobileMenu from "./components/MobileMenu";
|
||||
import Search from "./components/Search";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
@@ -46,7 +48,8 @@ export default {
|
||||
MobileMenu,
|
||||
ScrollableView,
|
||||
Splitpanes,
|
||||
Pane
|
||||
Pane,
|
||||
Search
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -65,12 +68,13 @@ export default {
|
||||
this.title = `${this.containers.length} containers`;
|
||||
},
|
||||
computed: {
|
||||
...mapState(["containers", "activeContainers", "isMobile"])
|
||||
...mapState(["containers", "activeContainers", "isMobile", "settings"])
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
.button.has-no-border {
|
||||
border-color: transparent !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -18,7 +18,7 @@ exports[`<App /> renders correctly 1`] = `
|
||||
|
||||
<pane-stub
|
||||
maxsize="100"
|
||||
minsize="0"
|
||||
minsize="10"
|
||||
size="85"
|
||||
>
|
||||
<splitpanes-stub
|
||||
@@ -29,6 +29,8 @@ exports[`<App /> renders correctly 1`] = `
|
||||
maxsize="100"
|
||||
minsize="0"
|
||||
>
|
||||
<search-stub />
|
||||
|
||||
<router-view-stub />
|
||||
</pane-stub>
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ describe("<LogEventSource />", () => {
|
||||
localVue.component("log-event-source", LogEventSource);
|
||||
localVue.component("log-viewer", LogViewer);
|
||||
|
||||
const state = { searchFilter };
|
||||
const state = { searchFilter, settings: { size: "medium" } };
|
||||
|
||||
const store = new Vuex.Store({
|
||||
state
|
||||
@@ -66,7 +66,7 @@ describe("<LogEventSource />", () => {
|
||||
/>
|
||||
|
||||
<ul
|
||||
class="events"
|
||||
class="events medium"
|
||||
/>
|
||||
</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."` });
|
||||
|
||||
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>
|
||||
</ul>
|
||||
`);
|
||||
@@ -140,7 +140,7 @@ describe("<LogEventSource />", () => {
|
||||
});
|
||||
|
||||
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>
|
||||
</ul>
|
||||
`);
|
||||
@@ -154,7 +154,7 @@ describe("<LogEventSource />", () => {
|
||||
});
|
||||
|
||||
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>
|
||||
</ul>
|
||||
`);
|
||||
@@ -171,7 +171,7 @@ describe("<LogEventSource />", () => {
|
||||
});
|
||||
|
||||
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>
|
||||
</ul>
|
||||
`);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template lang="html">
|
||||
<ul class="events">
|
||||
<ul class="events" :class="settings.size">
|
||||
<li v-for="item in filtered" :key="item.key">
|
||||
<span class="date">{{ item.date | relativeTime }}</span>
|
||||
<span class="text" v-html="colorize(item.message)"></span>
|
||||
@@ -32,7 +32,7 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(["searchFilter"]),
|
||||
...mapState(["searchFilter", "settings"]),
|
||||
filtered() {
|
||||
const { searchFilter, messages } = this;
|
||||
if (searchFilter) {
|
||||
@@ -69,9 +69,20 @@ export default {
|
||||
font-family: "Roboto Mono", monaco, monospace;
|
||||
|
||||
& > li {
|
||||
font-size: 13px;
|
||||
line-height: 16px;
|
||||
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;
|
||||
}
|
||||
|
||||
>>> mark {
|
||||
::v-deep mark {
|
||||
border-radius: 2px;
|
||||
background-color: #ffdd57;
|
||||
animation: pops 0.2s ease-out;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
@click="scrollToBottom('smooth')"
|
||||
v-show="paused"
|
||||
>
|
||||
<span class="icon large"> <i class="fas fa-chevron-down"></i> </span>
|
||||
<ion-icon name="download"></ion-icon>
|
||||
</button>
|
||||
</transition>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
<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">
|
||||
<p class="control has-icons-left">
|
||||
<input class="input" type="text" placeholder="Filter" ref="filter" v-model="filter" />
|
||||
<span class="icon is-small is-left"><i class="fas fa-search"></i></span>
|
||||
<input
|
||||
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>
|
||||
</div>
|
||||
<div class="column is-1 has-text-centered">
|
||||
@@ -14,6 +21,8 @@
|
||||
|
||||
<script>
|
||||
import { mapActions, mapState } from "vuex";
|
||||
import hotkeys from "hotkeys-js";
|
||||
|
||||
export default {
|
||||
props: [],
|
||||
name: "Search",
|
||||
@@ -23,31 +32,26 @@ export default {
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener("keydown", this.onKeyDown);
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener("keydown", this.onKeyDown);
|
||||
hotkeys("command+f, ctrl+f", (event, handler) => {
|
||||
this.showSearch = true;
|
||||
this.$nextTick(() => this.$refs.filter.focus() || this.$refs.filter.select());
|
||||
event.preventDefault();
|
||||
});
|
||||
hotkeys("esc", (event, handler) => {
|
||||
this.resetSearch();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
...mapActions({
|
||||
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() {
|
||||
this.showSearch = false;
|
||||
this.filter = "";
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(["searchFilter"]),
|
||||
...mapState(["searchFilter", "settings"]),
|
||||
filter: {
|
||||
get() {
|
||||
return this.searchFilter;
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
<template lang="html">
|
||||
<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>
|
||||
<ul class="menu-list is-hidden-mobile">
|
||||
<li v-for="item in containers">
|
||||
@@ -15,7 +28,7 @@
|
||||
class="icon is-small will-append-container"
|
||||
:class="{ 'is-active': activeContainersById[item.id] }"
|
||||
>
|
||||
<i class="fas fa-thumbtack"></i>
|
||||
<ion-icon name="ios-add-circle"></ion-icon>
|
||||
</span>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
@@ -74,7 +87,6 @@ aside {
|
||||
.will-append-container.icon {
|
||||
transition: transform 0.2s ease-out;
|
||||
&.is-active {
|
||||
transform: rotate(25deg);
|
||||
pointer-events: none;
|
||||
color: #00d1b2;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto|Roboto+Mono|Gafata" rel="stylesheet" />
|
||||
<link rel="manifest" href="manifest.webmanifest" />
|
||||
<link href="styles.scss" rel="stylesheet" />
|
||||
<link rel="icon" href="favicon.ico">
|
||||
<link rel="icon" href="favicon.ico" />
|
||||
<script>
|
||||
window["BASE_PATH"] = "{{ .Base }}";
|
||||
window["VERSION"] = "{{ .Version }}";
|
||||
</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>
|
||||
|
||||
<body class="is-dark">
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import Vue from "vue";
|
||||
import VueRouter from "vue-router";
|
||||
import Meta from "vue-meta";
|
||||
import Vuex from "vuex";
|
||||
import { Dropdown, Switch } from "buefy";
|
||||
import store from "./store";
|
||||
import App from "./App.vue";
|
||||
import Container from "./pages/Container.vue";
|
||||
import Settings from "./pages/Settings.vue";
|
||||
import Index from "./pages/Index.vue";
|
||||
|
||||
Vue.use(VueRouter);
|
||||
Vue.use(Meta);
|
||||
Vue.use(Dropdown);
|
||||
Vue.use(Switch);
|
||||
|
||||
Vue.config.ignoredElements = [/^ion-/];
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@@ -21,6 +26,11 @@ const routes = [
|
||||
component: Container,
|
||||
name: "container",
|
||||
props: true
|
||||
},
|
||||
{
|
||||
path: "/settings",
|
||||
component: Settings,
|
||||
name: "settings"
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
<template lang="html">
|
||||
<div>
|
||||
<search></search>
|
||||
<scrollable-logs-with-source :id="id"></scrollable-logs-with-source>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ScrollableLogsWithSource from "../components/ScrollableLogsWithSource";
|
||||
import Search from "../components/Search";
|
||||
|
||||
export default {
|
||||
props: ["id", "name"],
|
||||
name: "Container",
|
||||
components: {
|
||||
ScrollableLogsWithSource,
|
||||
Search
|
||||
ScrollableLogsWithSource
|
||||
},
|
||||
metaInfo() {
|
||||
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 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)");
|
||||
|
||||
Vue.use(Vuex);
|
||||
storage.set(DOZZLE_SETTINGS_KEY, { ...DEFAULT_SETTINGS, ...storage.get(DOZZLE_SETTINGS_KEY) });
|
||||
|
||||
const state = {
|
||||
containers: [],
|
||||
activeContainers: [],
|
||||
searchFilter: null,
|
||||
isMobile: mql.matches
|
||||
isMobile: mql.matches,
|
||||
settings: storage.get(DOZZLE_SETTINGS_KEY)
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
@@ -27,6 +32,10 @@ const mutations = {
|
||||
},
|
||||
SET_MOBILE_WIDTH(state, 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 }) {
|
||||
const containers = await (await fetch(`${BASE_PATH}/api/containers.json`)).json();
|
||||
commit("SET_CONTAINERS", containers);
|
||||
},
|
||||
UPDATE_SETTING({ commit }, setting) {
|
||||
commit("UPDATE_SETTINGS", setting);
|
||||
}
|
||||
};
|
||||
const getters = {};
|
||||
|
||||
const es = new EventSource(`${BASE_PATH}/api/events/stream`);
|
||||
es.addEventListener("containers-changed", e => setTimeout(() => store.dispatch("FETCH_CONTAINERS"), 1000), false);
|
||||
|
||||
mql.addListener(e => store.commit("SET_MOBILE_WIDTH", e.matches));
|
||||
|
||||
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-color: hsl(0, 6%, 87%);
|
||||
|
||||
@import "../node_modules/bulma/bulma.sass";
|
||||
@import "~bulma";
|
||||
@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 {
|
||||
color: #ddd;
|
||||
|
||||
5
main.go
5
main.go
@@ -150,7 +150,10 @@ func (h *handler) index(w http.ResponseWriter, req *http.Request) {
|
||||
path = base
|
||||
}
|
||||
|
||||
data := struct{ Base string }{path}
|
||||
data := struct {
|
||||
Base string
|
||||
Version string
|
||||
}{path, version}
|
||||
err = tmpl.Execute(w, data)
|
||||
if err != nil {
|
||||
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",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"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",
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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": {
|
||||
"version": "4.9.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
|
||||
@@ -3417,6 +3450,14 @@
|
||||
"semver": "^5.5.0",
|
||||
"shebang-command": "^1.2.0",
|
||||
"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": {
|
||||
@@ -4156,6 +4197,12 @@
|
||||
"pseudomap": "^1.0.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==",
|
||||
"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": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
|
||||
@@ -5774,6 +5826,14 @@
|
||||
"resolve": "^1.10.0",
|
||||
"semver": "2 || 3 || 4 || 5",
|
||||
"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": {
|
||||
@@ -7783,6 +7843,12 @@
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
|
||||
"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",
|
||||
"shellwords": "^0.1.1",
|
||||
"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": {
|
||||
@@ -8178,6 +8252,14 @@
|
||||
"is-builtin-module": "^1.0.0",
|
||||
"semver": "2 || 3 || 4 || 5",
|
||||
"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": {
|
||||
@@ -8754,6 +8836,12 @@
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"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": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
@@ -10130,9 +10218,9 @@
|
||||
}
|
||||
},
|
||||
"sass": {
|
||||
"version": "1.23.7",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.23.7.tgz",
|
||||
"integrity": "sha512-cYgc0fanwIpi0rXisGxl+/wadVQ/HX3RhpdRcjLdj2o2ye/sxUTpAxIhbmJy3PLQgRFbf6Pn8Jsrta2vdXcoOQ==",
|
||||
"version": "1.24.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.24.0.tgz",
|
||||
"integrity": "sha512-1TsPyMhLTx+9DLlmwg02iBW2p4poGA7LlkWJLpUY/XticFKNhPcx+l4FsIJLKl6oSUfXmAKpVljHEez1hwjqiw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": ">=2.0.0 <4.0.0"
|
||||
@@ -10154,10 +10242,9 @@
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
|
||||
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
|
||||
"dev": true
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.1.1.tgz",
|
||||
"integrity": "sha512-WfuG+fl6eh3eZ2qAf6goB7nhiCd7NPXhmyFxigB/TOkQyeLP8w8GsVehvtGNtnNmyboz4TgeK40B1Kbql/8c5A=="
|
||||
},
|
||||
"semver-compare": {
|
||||
"version": "1.0.0",
|
||||
@@ -10535,9 +10622,9 @@
|
||||
}
|
||||
},
|
||||
"splitpanes": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-2.1.2.tgz",
|
||||
"integrity": "sha512-IiVeC1wk7yVq4QZ3VTj6FbOTUJQmy/gFxpR1pDk67P+Pj8V0daUsPeoBNcKmcvJp2v3272GHSeLTNEyDCKRXSQ=="
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/splitpanes/-/splitpanes-2.2.0.tgz",
|
||||
"integrity": "sha512-n87JXR3xNHC6Zrcvg1JGU4wgqOxV95bFShhHhGM/cvQVFxN2HRJuaVWvvwgQzd9cF+4UyXtjcreqkOxr5bPnoA=="
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
|
||||
@@ -25,10 +25,13 @@
|
||||
"homepage": "https://github.com/amir20/dozzle#readme",
|
||||
"dependencies": {
|
||||
"ansi-to-html": "^0.6.13",
|
||||
"buefy": "^0.8.8",
|
||||
"bulma": "^0.8.0",
|
||||
"date-fns": "^2.8.1",
|
||||
"hotkeys-js": "^3.7.3",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"splitpanes": "^2.1.2",
|
||||
"semver": "^7.1.1",
|
||||
"splitpanes": "^2.2.0",
|
||||
"store": "^2.0.12",
|
||||
"vue": "^2.6.11",
|
||||
"vue-meta": "^2.3.1",
|
||||
@@ -52,7 +55,7 @@
|
||||
"node-fetch": "^2.6.0",
|
||||
"parcel-bundler": "^1.12.4",
|
||||
"prettier": "^1.19.1",
|
||||
"sass": "^1.23.7",
|
||||
"sass": "^1.24.0",
|
||||
"vue-hot-reload-api": "^2.3.4",
|
||||
"vue-jest": "^3.0.5",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
|
||||
Reference in New Issue
Block a user