add versioning

This commit is contained in:
Jakob Schrettenbrunner 2020-04-13 17:52:24 +02:00
parent 01c8a1e8c0
commit ee515d0129
26 changed files with 284 additions and 53 deletions

View File

@ -111,24 +111,51 @@ module.exports = {
{
title: 'Panel',
collapsable: false,
children: [
'/panel/getting_started',
'/panel/webserver_configuration',
'/panel/upgrading',
'/panel/configuration',
'/panel/troubleshooting',
path: '/panel/',
currentVersion: '0.7',
versions: [
{
name: '0.6',
status: 'deprecated',
children: []
},
{
name: '0.7',
status: 'stable',
children: [
'/getting_started',
'/webserver_configuration',
'/upgrading',
'/configuration',
'/troubleshooting',
]
},
{
name: '1.0',
status: 'beta',
children: [
'/getting_started',
]
}
]
},
{
title: 'Daemon',
collapsable: false,
children: [
'/daemon/installing',
'/daemon/upgrading',
'/daemon/configuration',
'/daemon/kernel_modifications',
'/daemon/debian_8_docker',
'/daemon/standalone_sftp',
path: '/daemon/',
currentVersion: '0.6',
versions: [
{
name: '0.6',
children: [
'/installing',
'/upgrading',
'/configuration',
'/kernel_modifications',
'/debian_8_docker',
'/standalone_sftp',
]
}
]
},
{

View File

@ -1,28 +1,79 @@
<template>
<div class="sidebar-group" :class="{ first, collapsable }">
<p class="sidebar-heading" :class="{ open }" @click="$emit('toggle')">
<span>{{ item.title }}</span>
<span class="arrow"
v-if="collapsable"
:class="open ? 'down' : 'right'"></span>
</p>
<DropdownTransition>
<ul class="sidebar-group-items" ref="items" v-if="open || !collapsable">
<li v-for="child in item.children">
<SidebarLink :item="child"/>
</li>
</ul>
</DropdownTransition>
</div>
<div class="sidebar-group" :class="{ first, collapsable }">
<p class="sidebar-heading" :class="{ open }" @click="$emit('toggle')">
<span>{{ item.title }}</span>
<span class="arrow" v-if="collapsable" :class="open ? 'down' : 'right'"></span>
<VersionSelect
class="float-right"
v-if="isVersioned"
:versions="item.versions"
v-model="versionSelect"
/>
</p>
<DropdownTransition>
<ul class="sidebar-group-items" ref="items" v-if="open || !collapsable">
<li v-for="child in children">
<SidebarLink :item="child" />
</li>
</ul>
</DropdownTransition>
</div>
</template>
<script>
import SidebarLink from './SidebarLink.vue';
import DropdownTransition from './DropdownTransition.vue';
import SidebarLink from "./SidebarLink.vue";
import DropdownTransition from "./DropdownTransition.vue";
import VersionSelect from "./VersionSelect.vue";
export default {
name: 'SidebarGroup',
props: ['item', 'first', 'open', 'collapsable'],
components: { SidebarLink, DropdownTransition }
export default {
name: "SidebarGroup",
props: ["item", "first", "open", "collapsable"],
components: { SidebarLink, DropdownTransition, VersionSelect },
data: function() {
let isVersioned = this.item.versions.length > 0;
return {
isVersioned,
versionSelect: isVersioned ? getSelectedVersion(this.item) : ""
};
},
watch: {
versionSelect(newVersion, oldVersion) {
if (
oldVersion !== newVersion &&
this.$router.currentRoute.path.startsWith(this.item.path) &&
this.selectedVersion.children.length > 0
) {
this.$router.push(this.selectedVersion.children[0]);
}
},
$route(to, from) {
if (this.isVersioned && to.path.startsWith(this.item.path)) {
const pathVersion = to.path.split("/")[2];
if (~this.item.versions.map(v => v.name).indexOf(pathVersion)) {
this.versionSelect = pathVersion;
}
}
}
},
computed: {
selectedVersion: function() {
return this.item.versions.find(v => v.name == this.versionSelect);
},
children: function() {
return this.isVersioned
? this.selectedVersion.children
: this.item.children;
}
}
};
function getSelectedVersion(item) {
if (window.location.pathname.startsWith(item.path)) {
const pathVersion = window.location.pathname.split("/")[2];
return ~item.versions.map(v => v.name).indexOf(pathVersion)
? pathVersion
: item.currentVersion;
}
return item.currentVersion;
}
</script>

View File

@ -0,0 +1,63 @@
<template>
<div class="version-select custom-select" :tabindex="tabindex" @blur="open = false">
<div class="selected" :class="{open: open}" @click="open = !open">
<VersionSelectItem :version="selected" />
<span class="arrow down"></span>
</div>
<div class="items" :class="{hidden: !open}">
<div
class="item"
v-for="version in versions"
:key="version.name"
@click="selected=version; open=false; $emit('input', version.name)"
>
<VersionSelectItem :version="version" />
</div>
</div>
</div>
</template>
<script>
import VersionSelectItem from "./VersionSelectItem.vue";
export default {
name: "VersionSelect",
components: { VersionSelectItem },
props: {
versions: {
type: Array,
required: true
},
tabindex: {
type: Number,
required: false,
default: 0
},
value: {
type: String,
required: false
}
},
data: function() {
return {
selected:
this.versions.find(v => v.name === this.value) ||
(this.versions.length > 0 ? this.versions[0] : null),
open: false
};
},
watch: {
value(newValue, oldValue) {
if (newValue !== oldValue) {
let version = this.versions.find(v => v.name === this.value);
if (version) {
this.selected = version;
}
}
}
},
mounted() {
this.$emit("input", this.selected.name);
}
};
</script>

View File

@ -0,0 +1,32 @@
<template>
<div class="inline-block">
{{ version.name }}
<span class="rounded-full px-2 ml-1" :class="classes">{{version.status}}</span>
</div>
</template>
<script>
import VersionSelectItem from "./VersionSelectItem.vue";
export default {
name: "VersionSelectItem",
props: {
version: {
type: Object,
required: true
}
},
computed: {
classes() {
return (
{
deprecated: ["text-orange"],
current: ["text-green-dark"],
stable: ["text-green-dark"],
beta: ["text-blue"]
}[this.version.status] || ["text-grey"]
);
}
}
};
</script>

View File

@ -90,6 +90,55 @@ $arrow-bg: #000;
&.open .arrow {
top: -0.18em;
}
.version-select {
@apply .relative .inline-block .text-sm;
&:focus {
@apply .outline-none;
}
.selected {
@apply .border .select-none .cursor-pointer .px-4;
border-radius: 1rem;
&.open {
@apply .border-blue .outline-none;
}
&:after {
position: absolute;
content: "";
top: .5em;
right: 10px;
width: 0;
height: 0;
border: 4px solid transparent;
border-color: #fff transparent transparent transparent;
}
}
.items {
@apply .absolute .pin-r .bg-white .border .p-1 .mt-1;
border-radius: 1rem;
z-index: 100;
.item {
@apply .select-none .rounded-full .cursor-pointer .px-2 .border .border-white;
white-space: nowrap;
margin-top: .125rem;
margin-bottom: .125rem;
&:hover, &:focus {
@apply .bg-grey-lighter;
}
&:last-child {
@apply .mb-0;
}
}
}
}
}
.sidebar-group-items {

View File

@ -3,32 +3,32 @@ export const extRE = /\.(md|html)$/
export const endingSlashRE = /\/$/
export const outboundRE = /^(https?:|mailto:|tel:)/
export function normalize (path) {
export function normalize(path) {
return decodeURI(path)
.replace(hashRE, '')
.replace(extRE, '')
}
export function getHash (path) {
export function getHash(path) {
const match = path.match(hashRE)
if (match) {
return match[0]
}
}
export function isExternal (path) {
export function isExternal(path) {
return outboundRE.test(path)
}
export function isMailto (path) {
export function isMailto(path) {
return /^mailto:/.test(path)
}
export function isTel (path) {
export function isTel(path) {
return /^tel:/.test(path)
}
export function ensureExt (path) {
export function ensureExt(path) {
if (isExternal(path)) {
return path
}
@ -42,7 +42,7 @@ export function ensureExt (path) {
return normalized + '.html' + hash
}
export function isActive (route, path) {
export function isActive(route, path) {
const routeHash = route.hash
const linkHash = getHash(path)
if (linkHash && routeHash !== linkHash) {
@ -53,7 +53,7 @@ export function isActive (route, path) {
return routePath === pagePath
}
export function resolvePage (pages, rawPath, base) {
export function resolvePage(pages, rawPath, base) {
if (base) {
rawPath = resolvePath(rawPath, base)
}
@ -70,7 +70,7 @@ export function resolvePage (pages, rawPath, base) {
return {}
}
function resolvePath (relative, base, append) {
function resolvePath(relative, base, append) {
const firstChar = relative.charAt(0)
if (firstChar === '/') {
return relative
@ -108,7 +108,7 @@ function resolvePath (relative, base, append) {
return stack.join('/')
}
export function resolveSidebarItems (page, route, site, localePath) {
export function resolveSidebarItems(page, route, site, localePath) {
const { pages, themeConfig } = site
const localeConfig = localePath && themeConfig.locales
@ -131,7 +131,7 @@ export function resolveSidebarItems (page, route, site, localePath) {
}
}
function resolveHeaders (page) {
function resolveHeaders(page) {
const headers = groupHeaders(page.headers || [])
return [{
type: 'group',
@ -147,7 +147,7 @@ function resolveHeaders (page) {
}]
}
export function groupHeaders (headers) {
export function groupHeaders(headers) {
// group h3s under h2
headers = headers.map(h => Object.assign({}, h))
let lastH2
@ -161,13 +161,13 @@ export function groupHeaders (headers) {
return headers.filter(h => h.level === 2)
}
export function resolveNavLinkItem (linkItem) {
export function resolveNavLinkItem(linkItem) {
return Object.assign(linkItem, {
type: linkItem.items && linkItem.items.length ? 'links' : 'link'
})
}
export function resolveMatchingConfig (route, config) {
export function resolveMatchingConfig(route, config) {
if (Array.isArray(config)) {
return {
base: '/',
@ -185,13 +185,13 @@ export function resolveMatchingConfig (route, config) {
return {}
}
function ensureEndingSlash (path) {
function ensureEndingSlash(path) {
return /(\.html|\/)$/.test(path)
? path
: path + '/'
}
function resolveItem (item, pages, base, isNested) {
function resolveItem(item, pages, base, isNested) {
if (typeof item === 'string') {
return resolvePage(pages, item, base)
} else if (Array.isArray(item)) {
@ -206,11 +206,18 @@ function resolveItem (item, pages, base, isNested) {
)
}
const children = item.children || []
const versions = item.versions || []
return {
type: 'group',
title: item.title,
...item,
children: children.map(child => resolveItem(child, pages, base, true)),
collapsable: item.collapsable !== false
collapsable: item.collapsable !== false,
versions: versions.map(version => ({
...version,
status: version.name === item.currentVersion ? "current" : version.status,
children: version.children.map(child => resolveItem(item.path + version.name + child, pages, base, true))
})),
}
}
}

View File

@ -148,7 +148,7 @@ Once you have done that there will be a tab called Configuration when you view t
Simply copy and paste the code block and paste it into a file called `core.json` in `/srv/daemon/config` and save it.
You may also use the Auto-Deployment feature rather than manually creating the files.
![](./../.vuepress/public/daemon_configuration_example.png)
![](./../../.vuepress/public/daemon_configuration_example.png)
## Starting the Daemon
To start your daemon simply move into the daemon directory and run the command below which will start the daemon in

View File

@ -1,5 +1,7 @@
# Getting Started
BETA
[[toc]]
Pterodactyl Panel is designed to run on your own web server. You will need to have root access to your server in order to run and use this panel.