mirror of
https://github.com/pterodactyl/documentation.git
synced 2025-12-10 10:44:43 -06:00
add versioning
This commit is contained in:
parent
01c8a1e8c0
commit
ee515d0129
@ -111,24 +111,51 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
title: 'Panel',
|
title: 'Panel',
|
||||||
collapsable: false,
|
collapsable: false,
|
||||||
children: [
|
path: '/panel/',
|
||||||
'/panel/getting_started',
|
currentVersion: '0.7',
|
||||||
'/panel/webserver_configuration',
|
versions: [
|
||||||
'/panel/upgrading',
|
{
|
||||||
'/panel/configuration',
|
name: '0.6',
|
||||||
'/panel/troubleshooting',
|
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',
|
title: 'Daemon',
|
||||||
collapsable: false,
|
collapsable: false,
|
||||||
children: [
|
path: '/daemon/',
|
||||||
'/daemon/installing',
|
currentVersion: '0.6',
|
||||||
'/daemon/upgrading',
|
versions: [
|
||||||
'/daemon/configuration',
|
{
|
||||||
'/daemon/kernel_modifications',
|
name: '0.6',
|
||||||
'/daemon/debian_8_docker',
|
children: [
|
||||||
'/daemon/standalone_sftp',
|
'/installing',
|
||||||
|
'/upgrading',
|
||||||
|
'/configuration',
|
||||||
|
'/kernel_modifications',
|
||||||
|
'/debian_8_docker',
|
||||||
|
'/standalone_sftp',
|
||||||
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,28 +1,79 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="sidebar-group" :class="{ first, collapsable }">
|
<div class="sidebar-group" :class="{ first, collapsable }">
|
||||||
<p class="sidebar-heading" :class="{ open }" @click="$emit('toggle')">
|
<p class="sidebar-heading" :class="{ open }" @click="$emit('toggle')">
|
||||||
<span>{{ item.title }}</span>
|
<span>{{ item.title }}</span>
|
||||||
<span class="arrow"
|
<span class="arrow" v-if="collapsable" :class="open ? 'down' : 'right'"></span>
|
||||||
v-if="collapsable"
|
<VersionSelect
|
||||||
:class="open ? 'down' : 'right'"></span>
|
class="float-right"
|
||||||
</p>
|
v-if="isVersioned"
|
||||||
<DropdownTransition>
|
:versions="item.versions"
|
||||||
<ul class="sidebar-group-items" ref="items" v-if="open || !collapsable">
|
v-model="versionSelect"
|
||||||
<li v-for="child in item.children">
|
/>
|
||||||
<SidebarLink :item="child"/>
|
</p>
|
||||||
</li>
|
<DropdownTransition>
|
||||||
</ul>
|
<ul class="sidebar-group-items" ref="items" v-if="open || !collapsable">
|
||||||
</DropdownTransition>
|
<li v-for="child in children">
|
||||||
</div>
|
<SidebarLink :item="child" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</DropdownTransition>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SidebarLink from './SidebarLink.vue';
|
import SidebarLink from "./SidebarLink.vue";
|
||||||
import DropdownTransition from './DropdownTransition.vue';
|
import DropdownTransition from "./DropdownTransition.vue";
|
||||||
|
import VersionSelect from "./VersionSelect.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SidebarGroup',
|
name: "SidebarGroup",
|
||||||
props: ['item', 'first', 'open', 'collapsable'],
|
props: ["item", "first", "open", "collapsable"],
|
||||||
components: { SidebarLink, DropdownTransition }
|
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>
|
</script>
|
||||||
|
|||||||
63
.vuepress/theme/VersionSelect.vue
Normal file
63
.vuepress/theme/VersionSelect.vue
Normal 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>
|
||||||
32
.vuepress/theme/VersionSelectItem.vue
Normal file
32
.vuepress/theme/VersionSelectItem.vue
Normal 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>
|
||||||
@ -90,6 +90,55 @@ $arrow-bg: #000;
|
|||||||
&.open .arrow {
|
&.open .arrow {
|
||||||
top: -0.18em;
|
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 {
|
.sidebar-group-items {
|
||||||
|
|||||||
@ -3,32 +3,32 @@ export const extRE = /\.(md|html)$/
|
|||||||
export const endingSlashRE = /\/$/
|
export const endingSlashRE = /\/$/
|
||||||
export const outboundRE = /^(https?:|mailto:|tel:)/
|
export const outboundRE = /^(https?:|mailto:|tel:)/
|
||||||
|
|
||||||
export function normalize (path) {
|
export function normalize(path) {
|
||||||
return decodeURI(path)
|
return decodeURI(path)
|
||||||
.replace(hashRE, '')
|
.replace(hashRE, '')
|
||||||
.replace(extRE, '')
|
.replace(extRE, '')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getHash (path) {
|
export function getHash(path) {
|
||||||
const match = path.match(hashRE)
|
const match = path.match(hashRE)
|
||||||
if (match) {
|
if (match) {
|
||||||
return match[0]
|
return match[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isExternal (path) {
|
export function isExternal(path) {
|
||||||
return outboundRE.test(path)
|
return outboundRE.test(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isMailto (path) {
|
export function isMailto(path) {
|
||||||
return /^mailto:/.test(path)
|
return /^mailto:/.test(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isTel (path) {
|
export function isTel(path) {
|
||||||
return /^tel:/.test(path)
|
return /^tel:/.test(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureExt (path) {
|
export function ensureExt(path) {
|
||||||
if (isExternal(path)) {
|
if (isExternal(path)) {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ export function ensureExt (path) {
|
|||||||
return normalized + '.html' + hash
|
return normalized + '.html' + hash
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isActive (route, path) {
|
export function isActive(route, path) {
|
||||||
const routeHash = route.hash
|
const routeHash = route.hash
|
||||||
const linkHash = getHash(path)
|
const linkHash = getHash(path)
|
||||||
if (linkHash && routeHash !== linkHash) {
|
if (linkHash && routeHash !== linkHash) {
|
||||||
@ -53,7 +53,7 @@ export function isActive (route, path) {
|
|||||||
return routePath === pagePath
|
return routePath === pagePath
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolvePage (pages, rawPath, base) {
|
export function resolvePage(pages, rawPath, base) {
|
||||||
if (base) {
|
if (base) {
|
||||||
rawPath = resolvePath(rawPath, base)
|
rawPath = resolvePath(rawPath, base)
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ export function resolvePage (pages, rawPath, base) {
|
|||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolvePath (relative, base, append) {
|
function resolvePath(relative, base, append) {
|
||||||
const firstChar = relative.charAt(0)
|
const firstChar = relative.charAt(0)
|
||||||
if (firstChar === '/') {
|
if (firstChar === '/') {
|
||||||
return relative
|
return relative
|
||||||
@ -108,7 +108,7 @@ function resolvePath (relative, base, append) {
|
|||||||
return stack.join('/')
|
return stack.join('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveSidebarItems (page, route, site, localePath) {
|
export function resolveSidebarItems(page, route, site, localePath) {
|
||||||
const { pages, themeConfig } = site
|
const { pages, themeConfig } = site
|
||||||
|
|
||||||
const localeConfig = localePath && themeConfig.locales
|
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 || [])
|
const headers = groupHeaders(page.headers || [])
|
||||||
return [{
|
return [{
|
||||||
type: 'group',
|
type: 'group',
|
||||||
@ -147,7 +147,7 @@ function resolveHeaders (page) {
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function groupHeaders (headers) {
|
export function groupHeaders(headers) {
|
||||||
// group h3s under h2
|
// group h3s under h2
|
||||||
headers = headers.map(h => Object.assign({}, h))
|
headers = headers.map(h => Object.assign({}, h))
|
||||||
let lastH2
|
let lastH2
|
||||||
@ -161,13 +161,13 @@ export function groupHeaders (headers) {
|
|||||||
return headers.filter(h => h.level === 2)
|
return headers.filter(h => h.level === 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveNavLinkItem (linkItem) {
|
export function resolveNavLinkItem(linkItem) {
|
||||||
return Object.assign(linkItem, {
|
return Object.assign(linkItem, {
|
||||||
type: linkItem.items && linkItem.items.length ? 'links' : 'link'
|
type: linkItem.items && linkItem.items.length ? 'links' : 'link'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveMatchingConfig (route, config) {
|
export function resolveMatchingConfig(route, config) {
|
||||||
if (Array.isArray(config)) {
|
if (Array.isArray(config)) {
|
||||||
return {
|
return {
|
||||||
base: '/',
|
base: '/',
|
||||||
@ -185,13 +185,13 @@ export function resolveMatchingConfig (route, config) {
|
|||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureEndingSlash (path) {
|
function ensureEndingSlash(path) {
|
||||||
return /(\.html|\/)$/.test(path)
|
return /(\.html|\/)$/.test(path)
|
||||||
? path
|
? path
|
||||||
: path + '/'
|
: path + '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveItem (item, pages, base, isNested) {
|
function resolveItem(item, pages, base, isNested) {
|
||||||
if (typeof item === 'string') {
|
if (typeof item === 'string') {
|
||||||
return resolvePage(pages, item, base)
|
return resolvePage(pages, item, base)
|
||||||
} else if (Array.isArray(item)) {
|
} else if (Array.isArray(item)) {
|
||||||
@ -206,11 +206,18 @@ function resolveItem (item, pages, base, isNested) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
const children = item.children || []
|
const children = item.children || []
|
||||||
|
const versions = item.versions || []
|
||||||
return {
|
return {
|
||||||
type: 'group',
|
type: 'group',
|
||||||
title: item.title,
|
...item,
|
||||||
children: children.map(child => resolveItem(child, pages, base, true)),
|
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))
|
||||||
|
})),
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.
|
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.
|
You may also use the Auto-Deployment feature rather than manually creating the files.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Starting the Daemon
|
## Starting the Daemon
|
||||||
To start your daemon simply move into the daemon directory and run the command below which will start the daemon in
|
To start your daemon simply move into the daemon directory and run the command below which will start the daemon in
|
||||||
@ -1,5 +1,7 @@
|
|||||||
# Getting Started
|
# Getting Started
|
||||||
|
|
||||||
|
BETA
|
||||||
|
|
||||||
[[toc]]
|
[[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.
|
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.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user