mirror of https://github.com/statping/statping
vue
parent
e306d42269
commit
ac60daa879
|
@ -17,6 +17,7 @@
|
||||||
"@fortawesome/vue-fontawesome": "^0.1.9",
|
"@fortawesome/vue-fontawesome": "^0.1.9",
|
||||||
"apexcharts": "^3.15.0",
|
"apexcharts": "^3.15.0",
|
||||||
"axios": "^0.19.1",
|
"axios": "^0.19.1",
|
||||||
|
"codemirror-colorpicker": "^1.9.66",
|
||||||
"core-js": "^3.4.4",
|
"core-js": "^3.4.4",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"querystring": "^0.2.0",
|
"querystring": "^0.2.0",
|
||||||
|
|
|
@ -91,6 +91,22 @@ HTML,BODY {
|
||||||
color: #6d6d6d;
|
color: #6d6d6d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.font-0 {
|
||||||
|
font-size: 5pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-1 {
|
||||||
|
font-size: 7pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-2 {
|
||||||
|
font-size: 9pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-3 {
|
||||||
|
font-size: 11pt;
|
||||||
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: $global-border-radius;
|
border-radius: $global-border-radius;
|
||||||
|
|
|
@ -152,6 +152,22 @@ class Api {
|
||||||
return axios.get('/api/logs/last').then(response => (response.data))
|
return axios.get('/api/logs/last').then(response => (response.data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async theme () {
|
||||||
|
return axios.get('/api/theme').then(response => (response.data))
|
||||||
|
}
|
||||||
|
|
||||||
|
async theme_generate (create=true) {
|
||||||
|
if (create) {
|
||||||
|
return axios.get('/api/theme/create').then(response => (response.data))
|
||||||
|
} else {
|
||||||
|
return axios.delete('/api/theme').then(response => (response.data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async theme_save (data) {
|
||||||
|
return axios.post('/api/theme', data).then(response => (response.data))
|
||||||
|
}
|
||||||
|
|
||||||
async login (username, password) {
|
async login (username, password) {
|
||||||
const f = {username: username, password: password}
|
const f = {username: username, password: password}
|
||||||
return axios.post('/api/login', qs.stringify(f))
|
return axios.post('/api/login', qs.stringify(f))
|
||||||
|
|
|
@ -1,24 +1,46 @@
|
||||||
<template >
|
<template >
|
||||||
<form method="POST" action="settings/css">
|
<div>
|
||||||
|
<div v-if="loaded && !directory" class="jumbotron jumbotron-fluid">
|
||||||
|
<div class="text-center col-12">
|
||||||
|
<h1 class="display-5">Enable Local Assets</h1>
|
||||||
|
<span class="lead">Customize your status page design by enabling local assets. This will create a 'assets' directory containing all CSS.<p>
|
||||||
|
<button @click.prevent="createAssets" :disabled="pending" href="#" class="btn btn-primary mt-3">Enable Local Assets</button>
|
||||||
|
</p></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form v-if="loaded && directory" @submit.prevent="saveAssets" :disabled="pending">
|
||||||
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
|
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
|
||||||
<li class="nav-item col text-center">
|
<li class="nav-item col text-center">
|
||||||
<a class="nav-link active" id="pills-vars-tab" data-toggle="pill" href="#pills-vars" role="tab" aria-controls="pills-vars" aria-selected="true">Variables</a>
|
<a @click.prevent="changeTab('vars')" class="nav-link" :class="{active: tab === 'vars'}" id="pills-vars-tab" data-toggle="pill" href="#pills-vars" role="tab" aria-controls="pills-vars" aria-selected="true">Variables</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item col text-center">
|
<li class="nav-item col text-center">
|
||||||
<a class="nav-link" id="pills-theme-tab" data-toggle="pill" href="#pills-theme" role="tab" aria-controls="pills-theme" aria-selected="false">Base Theme</a>
|
<a @click.prevent="changeTab('base')" class="nav-link" :class="{active: tab === 'base'}" id="pills-base-tab" data-toggle="pill" href="#pills-base" role="tab" aria-controls="pills-base" aria-selected="false">Base Theme</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item col text-center">
|
<li class="nav-item col text-center">
|
||||||
<a class="nav-link" id="pills-mobile-tab" data-toggle="pill" href="#pills-mobile" role="tab" aria-controls="pills-mobile" aria-selected="false">Mobile</a>
|
<a @click.prevent="changeTab('mobile')" class="nav-link" :class="{active: tab === 'mobile'}" id="pills-mobile-tab" data-toggle="pill" href="#pills-mobile" role="tab" aria-controls="pills-mobile" aria-selected="false">Mobile</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content" id="pills-tabContent">
|
<div class="tab-content" id="pills-tabContent">
|
||||||
<div class="tab-pane show active" id="pills-vars" role="tabpanel" aria-labelledby="pills-vars-tab">
|
<div class="tab-pane show" :class="{active: tab === 'vars'}" id="pills-vars" role="tabpanel" aria-labelledby="pills-vars-tab">
|
||||||
<codemirror v-if="loaded" v-model="base" :options="cmOptions"></codemirror>
|
<codemirror v-if="loaded && tab === 'vars'" v-model="vars" :options="cmOptions" class="codemirrorInput"/>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane show" :class="{active: tab === 'base'}" id="pills-base" role="tabpanel" aria-labelledby="pills-base-tab">
|
||||||
|
<codemirror v-if="loaded && tab === 'base'" v-model="base" :options="cmOptions" class="codemirrorInput"/>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane show" :class="{active: tab === 'mobile'}" id="pills-mobile" role="tabpanel" aria-labelledby="pills-mobile-tab">
|
||||||
|
<codemirror v-if="loaded && tab === 'mobile'" v-model="mobile" :options="cmOptions" class="codemirrorInput"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary btn-block mt-2">Save Style</button>
|
<div v-if="error" class="alert alert-danger mt-3" style="white-space: pre-line;">{{error}}</div>
|
||||||
<a href="settings/delete_assets" class="btn btn-danger btn-block confirm-btn">Delete All Assets</a>
|
|
||||||
|
<button @submit.prevent="saveAssets" type="submit" class="btn btn-primary btn-block mt-2" :disabled="pending">{{pending ? "Saving..." : "Save Style"}}</button>
|
||||||
|
<button v-if="directory" @click.prevent="deleteAssets" href="#" class="btn btn-danger btn-block confirm-btn" :disabled="pending">Delete Local Assets</button>
|
||||||
|
|
||||||
|
<h6 class="text-muted text-monospace text-sm-center font-1 mt-3">
|
||||||
|
Asset Directory: {{directory}}
|
||||||
|
</h6>
|
||||||
</form>
|
</form>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -26,8 +48,11 @@
|
||||||
|
|
||||||
// require component
|
// require component
|
||||||
import { codemirror } from 'vue-codemirror'
|
import { codemirror } from 'vue-codemirror'
|
||||||
// require styles
|
import 'codemirror/mode/css/css.js'
|
||||||
|
|
||||||
import 'codemirror/lib/codemirror.css'
|
import 'codemirror/lib/codemirror.css'
|
||||||
|
import 'codemirror-colorpicker/dist/codemirror-colorpicker.css'
|
||||||
|
import 'codemirror-colorpicker'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ThemeEditor',
|
name: 'ThemeEditor',
|
||||||
|
@ -43,29 +68,89 @@
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
base: "",
|
base: "",
|
||||||
|
vars: "",
|
||||||
|
mobile: "",
|
||||||
|
error: null,
|
||||||
|
directory: null,
|
||||||
|
tab: "vars",
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
pending: false,
|
||||||
cmOptions: {
|
cmOptions: {
|
||||||
// codemirror options
|
height: 600,
|
||||||
tabSize: 4,
|
tabSize: 4,
|
||||||
mode: 'text/javascript',
|
|
||||||
theme: 'base16-dark',
|
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
|
matchBrackets: true,
|
||||||
|
mode: "text/x-scss",
|
||||||
line: true,
|
line: true,
|
||||||
// more codemirror options, 更多 codemirror 的高级配置...
|
colorpicker: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
codemirror () {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
async mounted () {
|
async mounted () {
|
||||||
this.base = await Api.scss_base()
|
await this.fetchTheme()
|
||||||
window.console.log(this.base)
|
|
||||||
this.loaded = true
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
async fetchTheme() {
|
||||||
|
this.loaded = true
|
||||||
|
this.pending = true
|
||||||
|
const theme = await Api.theme()
|
||||||
|
this.directory = theme.directory
|
||||||
|
if (this.directory) {
|
||||||
|
this.base = theme.base
|
||||||
|
this.vars = theme.variables
|
||||||
|
this.mobile = theme.mobile
|
||||||
|
}
|
||||||
|
this.pending = false
|
||||||
|
this.loaded = true
|
||||||
|
},
|
||||||
|
async createAssets() {
|
||||||
|
this.pending = true
|
||||||
|
const resp = await Api.theme_generate(true)
|
||||||
|
window.console.log(resp)
|
||||||
|
this.pending = false
|
||||||
|
await this.fetchTheme()
|
||||||
|
},
|
||||||
|
async deleteAssets() {
|
||||||
|
this.pending = true
|
||||||
|
let c = confirm('Are you sure you want to delete all local assets?')
|
||||||
|
if (c) {
|
||||||
|
const resp = await Api.theme_generate(false)
|
||||||
|
window.console.log(resp)
|
||||||
|
await this.fetchTheme()
|
||||||
|
}
|
||||||
|
this.pending = false
|
||||||
|
},
|
||||||
|
async saveAssets() {
|
||||||
|
this.pending = true
|
||||||
|
const data = {base: this.base, variables: this.vars, mobile: this.mobile}
|
||||||
|
const resp = await Api.theme_save(data)
|
||||||
|
if (resp.error) {
|
||||||
|
this.error = resp.error
|
||||||
|
this.pending = false
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
this.error = null
|
||||||
|
}
|
||||||
|
this.pending = false
|
||||||
|
window.console.log(resp)
|
||||||
|
await this.fetchTheme()
|
||||||
|
},
|
||||||
|
changeTab (v) {
|
||||||
|
this.tab = v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||||
<style scoped>
|
<style>
|
||||||
|
.CodeMirror {
|
||||||
|
border: 1px solid #eee;
|
||||||
|
height: 550px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-12 col-md-2">
|
<div class="col-sm-12 col-md-2">
|
||||||
<router-link :to="serviceLink(service)" class="btn btn-sm float-right dyn-dark btn-block" :class="{'bg-success': service.online, 'bg-danger': !service.online}">
|
<router-link :to="serviceLink(service)" class="btn btn-sm float-right dyn-dark btn-block text-white" :class="{'bg-success': service.online, 'bg-danger': !service.online}">
|
||||||
View Service</router-link>
|
View Service</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -44,7 +44,7 @@ export default {
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
const core = await Api.core()
|
const core = await Api.core()
|
||||||
context.commit("setCore", core);
|
this.$store.commit("setCore", core);
|
||||||
if (!core.setup) {
|
if (!core.setup) {
|
||||||
this.$router.push('/setup')
|
this.$router.push('/setup')
|
||||||
}
|
}
|
||||||
|
|
|
@ -2093,6 +2093,11 @@ code-point-at@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||||
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
|
||||||
|
|
||||||
|
codemirror-colorpicker@^1.9.66:
|
||||||
|
version "1.9.66"
|
||||||
|
resolved "https://registry.yarnpkg.com/codemirror-colorpicker/-/codemirror-colorpicker-1.9.66.tgz#de1f7373be73bc0f242c50a1b682858f5130b3af"
|
||||||
|
integrity sha512-wI4qLOzJ49Zs8jyVb/6eDdS02cd7Wi8NUb6QGSG8Ej6zmYbflttlBOLAD9Ywb0b1iSLpD1CV+eht/66f3KrKWg==
|
||||||
|
|
||||||
codemirror@^5.41.0:
|
codemirror@^5.41.0:
|
||||||
version "5.51.0"
|
version "5.51.0"
|
||||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.51.0.tgz#7746caaf5223e68f5c55ea11e2f3cc82a9a3929e"
|
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.51.0.tgz#7746caaf5223e68f5c55ea11e2f3cc82a9a3929e"
|
||||||
|
|
|
@ -17,6 +17,7 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/hunterlong/statping/core"
|
"github.com/hunterlong/statping/core"
|
||||||
|
@ -24,6 +25,7 @@ import (
|
||||||
"github.com/hunterlong/statping/source"
|
"github.com/hunterlong/statping/source"
|
||||||
"github.com/hunterlong/statping/utils"
|
"github.com/hunterlong/statping/utils"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -79,6 +81,91 @@ func logsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
returnJson(logs, w, r)
|
returnJson(logs, w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type themeApi struct {
|
||||||
|
Directory string `json:"directory,omitempty"`
|
||||||
|
Base string `json:"base"`
|
||||||
|
Variables string `json:"variables"`
|
||||||
|
Mobile string `json:"mobile"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiThemeHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var base, variables, mobile, dir string
|
||||||
|
assets := utils.Directory + "/assets"
|
||||||
|
|
||||||
|
if _, err := os.Stat(assets); err == nil {
|
||||||
|
dir = assets
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir != "" {
|
||||||
|
base, _ = utils.OpenFile(dir + "/scss/base.scss")
|
||||||
|
variables, _ = utils.OpenFile(dir + "/scss/variables.scss")
|
||||||
|
mobile, _ = utils.OpenFile(dir + "/scss/mobile.scss")
|
||||||
|
} else {
|
||||||
|
base, _ = source.TmplBox.String("scss/base.scss")
|
||||||
|
variables, _ = source.TmplBox.String("scss/variables.scss")
|
||||||
|
mobile, _ = source.TmplBox.String("scss/mobile.scss")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &themeApi{
|
||||||
|
Directory: dir,
|
||||||
|
Base: base,
|
||||||
|
Variables: variables,
|
||||||
|
Mobile: mobile,
|
||||||
|
}
|
||||||
|
returnJson(resp, w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiThemeSaveHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var themes themeApi
|
||||||
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
err := decoder.Decode(&themes)
|
||||||
|
if err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := source.SaveAsset([]byte(themes.Base), utils.Directory+"/assets/scss/base.scss"); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := source.SaveAsset([]byte(themes.Variables), utils.Directory+"/assets/scss/variables.scss"); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := source.SaveAsset([]byte(themes.Mobile), utils.Directory+"/assets/scss/mobile.scss"); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := source.CompileSASS(utils.Directory); err != nil {
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resetRouter()
|
||||||
|
sendJsonAction(themes, "saved", w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiThemeCreateHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dir := utils.Directory
|
||||||
|
utils.Log.Infof("creating assets in folder: %s/%s", dir, "assets")
|
||||||
|
if err := source.CreateAllAssets(dir); err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
sendErrorJson(err, w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := source.CompileSASS(dir); err != nil {
|
||||||
|
source.CopyToPublic(source.TmplBox, dir+"/assets/css", "base.css")
|
||||||
|
log.Errorln("Default 'base.css' was inserted because SASS did not work.")
|
||||||
|
}
|
||||||
|
resetRouter()
|
||||||
|
sendJsonAction(dir+"/assets", "created", w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func apiThemeRemoveHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err := source.DeleteAllAssets(utils.Directory); err != nil {
|
||||||
|
log.Errorln(fmt.Errorf("error deleting all assets %v", err))
|
||||||
|
}
|
||||||
|
sendJsonAction(utils.Directory+"/assets", "deleted", w, r)
|
||||||
|
}
|
||||||
|
|
||||||
func logsLineHandler(w http.ResponseWriter, r *http.Request) {
|
func logsLineHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if lastLine := utils.GetLastLine(); lastLine != nil {
|
if lastLine := utils.GetLastLine(); lastLine != nil {
|
||||||
w.Header().Set("Content-Type", "text/plain")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
|
|
@ -83,6 +83,12 @@ func Router() *mux.Router {
|
||||||
r.Handle("/api/logs", authenticated(logsHandler, false)).Methods("GET")
|
r.Handle("/api/logs", authenticated(logsHandler, false)).Methods("GET")
|
||||||
r.Handle("/api/logs/last", authenticated(logsLineHandler, false)).Methods("GET")
|
r.Handle("/api/logs/last", authenticated(logsLineHandler, false)).Methods("GET")
|
||||||
|
|
||||||
|
// API SCSS and ASSETS Routes
|
||||||
|
r.Handle("/api/theme", authenticated(apiThemeHandler, false)).Methods("GET")
|
||||||
|
r.Handle("/api/theme", authenticated(apiThemeSaveHandler, false)).Methods("POST")
|
||||||
|
r.Handle("/api/theme/create", authenticated(apiThemeCreateHandler, false)).Methods("GET")
|
||||||
|
r.Handle("/api/theme", authenticated(apiThemeRemoveHandler, false)).Methods("DELETE")
|
||||||
|
|
||||||
// API INTEGRATIONS Routes
|
// API INTEGRATIONS Routes
|
||||||
r.Handle("/api/integrations", authenticated(apiAllIntegrationsHandler, false)).Methods("GET")
|
r.Handle("/api/integrations", authenticated(apiAllIntegrationsHandler, false)).Methods("GET")
|
||||||
r.Handle("/api/integrations/{name}", authenticated(apiIntegrationViewHandler, false)).Methods("GET")
|
r.Handle("/api/integrations/{name}", authenticated(apiIntegrationViewHandler, false)).Methods("GET")
|
||||||
|
|
|
@ -81,9 +81,9 @@ func saveSASSHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
theme := form.Get("theme")
|
theme := form.Get("theme")
|
||||||
variables := form.Get("variables")
|
variables := form.Get("variables")
|
||||||
mobile := form.Get("mobile")
|
mobile := form.Get("mobile")
|
||||||
source.SaveAsset([]byte(theme), utils.Directory, "scss/base.scss")
|
source.SaveAsset([]byte(theme), utils.Directory+"/assets/scss/base.scss")
|
||||||
source.SaveAsset([]byte(variables), utils.Directory, "scss/variables.scss")
|
source.SaveAsset([]byte(variables), utils.Directory+"/assets/scss/variables.scss")
|
||||||
source.SaveAsset([]byte(mobile), utils.Directory, "scss/mobile.scss")
|
source.SaveAsset([]byte(mobile), utils.Directory+"/assets/scss/mobile.scss")
|
||||||
source.CompileSASS(utils.Directory)
|
source.CompileSASS(utils.Directory)
|
||||||
resetRouter()
|
resetRouter()
|
||||||
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "settings")
|
ExecuteResponse(w, r, "settings.gohtml", core.CoreApp, "settings")
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/russross/blackfriday/v2"
|
"github.com/russross/blackfriday/v2"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -59,15 +60,15 @@ func CompileSASS(folder string) error {
|
||||||
|
|
||||||
stdout, stderr, err := utils.Command(command)
|
stdout, stderr, err := utils.Command(command)
|
||||||
|
|
||||||
if stdout != "" || stderr != "" {
|
|
||||||
log.Errorln(fmt.Sprintf("Failed to compile assets with SASS %v", err))
|
|
||||||
return errors.New("failed to capture stdout or stderr")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorln(fmt.Sprintf("Failed to compile assets with SASS %v", err))
|
log.Errorln(fmt.Sprintf("Failed to compile assets with SASS %v", err))
|
||||||
log.Errorln(fmt.Sprintf("sh -c %v", command))
|
log.Errorln(fmt.Sprintf("sh -c %v", command))
|
||||||
return err
|
return fmt.Errorf("failed to compile assets with SASS: %v %v \n%v", err, stdout, stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stdout != "" || stderr != "" {
|
||||||
|
log.Errorln(fmt.Sprintf("Failed to compile assets with SASS %v %v %v", err, stdout, stderr))
|
||||||
|
return errors.New("failed to capture stdout or stderr")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infoln(fmt.Sprintf("out: %v | error: %v", stdout, stderr))
|
log.Infoln(fmt.Sprintf("out: %v | error: %v", stdout, stderr))
|
||||||
|
@ -96,8 +97,7 @@ func UsingAssets(folder string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveAsset will save an asset to the '/assets/' folder.
|
// SaveAsset will save an asset to the '/assets/' folder.
|
||||||
func SaveAsset(data []byte, folder, file string) error {
|
func SaveAsset(data []byte, location string) error {
|
||||||
location := folder + "/assets/" + file
|
|
||||||
log.Infoln(fmt.Sprintf("Saving %v", location))
|
log.Infoln(fmt.Sprintf("Saving %v", location))
|
||||||
err := utils.SaveFile(location, data)
|
err := utils.SaveFile(location, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -120,14 +120,20 @@ func OpenAsset(folder, file string) string {
|
||||||
// CreateAllAssets will dump HTML, CSS, SCSS, and JS assets into the '/assets' directory
|
// CreateAllAssets will dump HTML, CSS, SCSS, and JS assets into the '/assets' directory
|
||||||
func CreateAllAssets(folder string) error {
|
func CreateAllAssets(folder string) error {
|
||||||
log.Infoln(fmt.Sprintf("Dump Statping assets into %v/assets", folder))
|
log.Infoln(fmt.Sprintf("Dump Statping assets into %v/assets", folder))
|
||||||
MakePublicFolder(folder + "/assets")
|
fp := filepath.Join
|
||||||
MakePublicFolder(folder + "/assets/js")
|
|
||||||
MakePublicFolder(folder + "/assets/css")
|
MakePublicFolder(fp(folder, "/assets"))
|
||||||
MakePublicFolder(folder + "/assets/scss")
|
MakePublicFolder(fp(folder, "assets", "js"))
|
||||||
MakePublicFolder(folder + "/assets/font")
|
MakePublicFolder(fp(folder, "assets", "css"))
|
||||||
MakePublicFolder(folder + "/assets/files")
|
MakePublicFolder(fp(folder, "assets", "scss"))
|
||||||
|
MakePublicFolder(fp(folder, "assets", "font"))
|
||||||
|
MakePublicFolder(fp(folder, "assets", "files"))
|
||||||
log.Infoln("Inserting scss, css, and javascript files into assets folder")
|
log.Infoln("Inserting scss, css, and javascript files into assets folder")
|
||||||
CopyAllToPublic(TmplBox, folder+"/assets")
|
|
||||||
|
if err := CopyAllToPublic(TmplBox, fp(folder, "assets")); err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
}
|
||||||
|
|
||||||
CopyToPublic(TmplBox, folder+"/assets", "robots.txt")
|
CopyToPublic(TmplBox, folder+"/assets", "robots.txt")
|
||||||
CopyToPublic(TmplBox, folder+"/assets", "banner.png")
|
CopyToPublic(TmplBox, folder+"/assets", "banner.png")
|
||||||
CopyToPublic(TmplBox, folder+"/assets", "favicon.ico")
|
CopyToPublic(TmplBox, folder+"/assets", "favicon.ico")
|
||||||
|
@ -153,20 +159,32 @@ func DeleteAllAssets(folder string) error {
|
||||||
|
|
||||||
// CopyAllToPublic will copy all the files in a rice box into a local folder
|
// CopyAllToPublic will copy all the files in a rice box into a local folder
|
||||||
func CopyAllToPublic(box *rice.Box, folder string) error {
|
func CopyAllToPublic(box *rice.Box, folder string) error {
|
||||||
|
|
||||||
|
exclude := map[string]bool{
|
||||||
|
"base.gohtml": true,
|
||||||
|
"index.html": true,
|
||||||
|
"swagger.json": true,
|
||||||
|
"postman.json": true,
|
||||||
|
"grafana.json": true,
|
||||||
|
}
|
||||||
|
|
||||||
err := box.Walk("/", func(path string, info os.FileInfo, err error) error {
|
err := box.Walk("/", func(path string, info os.FileInfo, err error) error {
|
||||||
if info.Name() == "" {
|
if info.Name() == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if info.IsDir() {
|
if exclude[info.Name()] {
|
||||||
folder := fmt.Sprintf("%v/assets/%v/%v", utils.Directory, folder, info.Name())
|
return nil
|
||||||
return MakePublicFolder(folder)
|
|
||||||
}
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
utils.Log.Infoln(path)
|
||||||
file, err := box.Bytes(path)
|
file, err := box.Bytes(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
filePath := fmt.Sprintf("%v/%v", folder, path)
|
filePath := filepath.Join(folder, path)
|
||||||
return SaveAsset(file, utils.Directory, filePath)
|
return SaveAsset(file, filePath)
|
||||||
})
|
})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,6 +223,11 @@ func FolderExists(folder string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func OpenFile(filePath string) (string, error) {
|
||||||
|
data, err := ioutil.ReadFile(filePath)
|
||||||
|
return string(data), err
|
||||||
|
}
|
||||||
|
|
||||||
// CopyFile will copy a file to a new directory
|
// CopyFile will copy a file to a new directory
|
||||||
// CopyFile("source.jpg", "/tmp/source.jpg")
|
// CopyFile("source.jpg", "/tmp/source.jpg")
|
||||||
func CopyFile(src, dst string) error {
|
func CopyFile(src, dst string) error {
|
||||||
|
@ -262,7 +267,10 @@ func Command(cmd string) (string, string, error) {
|
||||||
var errStdout, errStderr error
|
var errStdout, errStderr error
|
||||||
stdoutIn, _ := testCmd.StdoutPipe()
|
stdoutIn, _ := testCmd.StdoutPipe()
|
||||||
stderrIn, _ := testCmd.StderrPipe()
|
stderrIn, _ := testCmd.StderrPipe()
|
||||||
testCmd.Start()
|
err := testCmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn)
|
stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn)
|
||||||
|
@ -272,13 +280,13 @@ func Command(cmd string) (string, string, error) {
|
||||||
stderr, errStderr = copyAndCapture(os.Stderr, stderrIn)
|
stderr, errStderr = copyAndCapture(os.Stderr, stderrIn)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err := testCmd.Wait()
|
err = testCmd.Wait()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return string(stdout), string(stderr), err
|
||||||
}
|
}
|
||||||
|
|
||||||
if errStdout != nil || errStderr != nil {
|
if errStdout != nil || errStderr != nil {
|
||||||
return "", "", errors.New("failed to capture stdout or stderr")
|
return string(stdout), string(stderr), errors.New("failed to capture stdout or stderr")
|
||||||
}
|
}
|
||||||
|
|
||||||
outStr, errStr := string(stdout), string(stderr)
|
outStr, errStr := string(stdout), string(stderr)
|
||||||
|
@ -327,7 +335,7 @@ func DurationReadable(d time.Duration) string {
|
||||||
// SaveFile will create a new file with data inside it
|
// SaveFile will create a new file with data inside it
|
||||||
// SaveFile("newfile.json", []byte('{"data": "success"}')
|
// SaveFile("newfile.json", []byte('{"data": "success"}')
|
||||||
func SaveFile(filename string, data []byte) error {
|
func SaveFile(filename string, data []byte) error {
|
||||||
err := ioutil.WriteFile(filename, data, 0644)
|
err := ioutil.WriteFile(filename, data, 0655)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue