UNPKG

@browsercapturesalt/herokuappman

Version:
476 lines (460 loc) 13.4 kB
<style> .accounts { border-collapse: collapse; font-family: monospace; font-size: 20px; } .accounts td { border: solid 1px #777; padding: 3px; padding-left: 10px; padding-right: 10px; } .builds { border-collapse: collapse; font-family: monospace; font-size: 20px; } .builds td { border: solid 1px #777; padding: 3px; padding-left: 10px; padding-right: 10px; } .config { border-collapse: collapse; font-family: monospace; font-size: 20px; } .config td { border: solid 1px #777; padding: 3px; padding-left: 10px; padding-right: 10px; } </style> <script src="/vue.js"></script> <script src="/utils.js"></script> <div id="app"> <div v-if="!params.appName"> {{ welcome }} <hr /> <button @click="setadminpass">Set Admin Pass</button> <hr /> <table class="accounts"> <tr v-for="account in appMan.accounts"> <td style="font-weight: bold; color: #700; text-align: center"> {{ account.name }} </td> <td style="font-weight: bold; color: #070; text-align: center"> {{ Math.round((account.quotaTotal - account.quotaUsed)/3600) }} </td> <td> <table> <tr v-for="app in account.apps"> <td style=" font-weight: bold; color: #007; min-width: 200px; font-size: 18px; " > <a rel="noopener noreferrer" target="_blank" :href="`https://${app.name}.herokuapp.com`" >{{ app.name }} </a> </td> <td style=" font-weight: bold; color: #700; min-width: 30px; text-align: center; font-size: 18px; " > {{ Math.round(app.quotaUsed/3600) }} </td> <td style=" font-weight: bold; color: #770; min-width: 30px; text-align: center; " > {{ app.region }} </td> <td style=""> <button style="background-color: #ffa; margin-left: 10px" @click="getconfig(app)" > Config </button> <button style="background-color: #afa; margin-left: 10px" @click="getlogs(app)" > Logs </button> <button style="background-color: #aff; margin-left: 10px" @click="getbuilds(app)" > Builds </button> </td> </tr> </table> </td> </tr> </table> <hr /> <input v-model="filterrepo" placeholder="Filter by Repo Name" style="font-family: monospace; font-size: 16px" /> <select v-model="sortReposBy" style=" font-family: monospace; margin-left: 10px; font-size: 16px; padding: 3px; " > <option v-for="sortCriteria in sortReposByCriteria" :value="sortCriteria.value" > {{ sortCriteria.display }} </option> </select> <hr /> <table class="accounts"> <tr v-for="account in gitMan.accounts"> <td style="font-weight: bold; color: #700; text-align: center"> <a rel="noopener noreferrer" target="_blank" :href="account.gitUrl"> {{ account.gitUserName }} </a> </td> <td> <button @click="createrepo(account.gitUserName, false)" style="background-color: #afa" > Create Empty Repo </button> <button @click="createrepo(account.gitUserName, true)" style="margin-left: 10px; background-color: #ffa" > Create Initialized Repo </button> <hr /> <div style="max-height: 300px; overflow-y: scroll"> <table> <tr v-for="(repo, index) in account.repos.filter(repo => repo.name.match(new RegExp(filterrepo))).sort(sortReposFunc)" > <td>{{ index + 1 }}</td> <td> <a rel="noopener noreferrer" target="_blank" :href="repo.repoUrl" > {{ repo.name }} </a> </td> <td style="text-align: center; color: #070; font-weight: bold"> {{ repo.stars ? `* ${repo.stars}` : "" }} </td> <td style="text-align: center; color: #707; font-weight: bold"> {{ repo.forks ? `-> ${repo.forks}` : "" }} </td> <td style="color: #770">> {{ repo.pushedAt }}</td> <td> <select @change="forkat($event, account, repo)"> <option value="">Fork At</option> <option v-for="account in gitMan.accounts" :value="account.gitUserName" > {{ account.gitUserName }} </option> </select> </td> <td> <button @click="deleterepo(account.gitUserName, repo)" style="background-color: #faa" > Del </button> </td> </tr> </table> </div> </td> </tr> </table> </div> <div v-if="params.config"> <span style="font-family: monospace"> Config of <span style="color: #070; font-weight: bold; font-size: 20px" >{{ params.appName }}</span > </span> <hr /> <button style="background-color: #afa" @click="addkey">Add Key</button> <button style="background-color: #ffa; margin-left: 10px" @click="uploadconfig" > Upload Config </button> <hr /> <table class="config"> <tr v-for="key in Object.keys(params.config).sort((a,b)=>a.localeCompare(b))" > <td style="color: #007">{{ key }}</td> <td> <button style="background-color: #afa" @click="editkey(key)"> Edit </button> </td> <td style="max-width: 600px; overflow: hidden"> {{params.config[key]}} </td> <td> <button style="background-color: #afa" @click="editvalue(key)"> Edit </button> </td> <td> <button style="background-color: #faa" @click="delkey(key)"> Del </button> </td> </tr> </table> </div> <div v-if="params.builds"> <span style="font-family: monospace"> Builds of <span style="color: #070; font-weight: bold; font-size: 20px" >{{ params.appName }}</span > </span> <hr /> <table class="builds"> <tr v-for="build in params.builds"> <td style="color: #007">{{ build.id }}</td> <td>{{build.created_at}}</td> <td :style="`font-weight:bold;${build.status === 'succeeded'?'color:#070;':'color:#700;'}`" > {{ build.status }} </td> <td> <a rel="noopener noreferrer" target="_blank" :href="build.output_stream_url" >Logs</a > </td> </tr> </table> </div> </div> <script> Vue.createApp({ computed: {}, methods: { sortReposFunc(a, b) { if (this.sortReposBy === "pushedat") return ( new Date(b.pushedAt).getTime() - new Date(a.pushedAt).getTime() ); if (this.sortReposBy === "stars") return b.stars - a.stars; if (this.sortReposBy === "forks") return b.forks - a.forks; return a.name.localeCompare(b.name); }, forkat(ev, account, repo) { const gitUserName = ev.target.value; ev.target.value = ""; const owner = account.gitUserName; const name = repo.name; post("fork", { gitUserName, owner, name, }).then((result) => { if (result.forkResult.error) { window.alert(JSON.stringify(result.forkResult)); } else { this.gitMan = result.gitMan; } }); }, createrepo(gitUserName, init) { const name = window.prompt("Name"); if (name) { post("createrepo", { gitUserName, name, init, }).then((result) => { if (result.createResult.error) { window.alert(JSON.stringify(result.createResult)); } else { this.gitMan = result.gitMan; } }); } }, deleterepo(gitUserName, repo) { const confirm = window.prompt(`Type "${repo.name}" To Delete`); if (confirm === repo.name) { post("deleterepo", { gitUserName, name: repo.name, }).then((result) => { if (result.deleteResult.error) { window.alert(JSON.stringify(result.deleteResult)); } else { this.gitMan = result.gitMan; } }); } else { window.alert("Deletion Canceled"); } }, uploadconfig() { post("setconfig", { name: this.params.appName, config: this.params.config, }).then((result) => { if (result.error) { window.alert(result.error); } else { document.location.reload(); } }); }, addkey() { const key = window.prompt("Key"); if (key) { const value = window.prompt("Value"); if (value !== undefined && value !== null) { const smartKey = key.toUpperCase().replace(/ /g, "_"); this.params.config[smartKey] = value; } } }, editkey(key) { const value = this.params.config[key]; const newKey = window.prompt("Key", key); if (newKey) { if (this.params.config[newKey] !== undefined) { window.alert("Key already exists!"); } else { delete this.params.config[key]; this.params.config[newKey] = value; } } }, delkey(key) { delete this.params.config[key]; }, editvalue(key) { const value = this.params.config[key]; const newValue = window.prompt("Key", value); if (newValue) { this.params.config[key] = newValue; } }, getlogs(app) { post("getlogs", { app }).then((result) => { if (result.error) { window.alert(result.error); } else { window.open(result.logplex_url, "_blank"); } }); }, getbuilds(app) { window.open(`?builds=${app.name}`, "_blank"); }, getconfig(app) { window.open(`?config=${app.name}`, "_blank"); }, setadminpass() { const pass = window.prompt("Admin Pass"); localStorage.setItem("ADMIN_PASS", pass); document.location.reload(); }, }, data() { return { welcome: "Welcome to Heroku App Manager !", appMan: { accounts: [] }, gitMan: { accounts: [] }, params: {}, filterrepo: "", sortReposBy: "pushedat", sortReposByCriteria: [ { value: "pushedat", display: "Sort repos by most recent push" }, { value: "alphabetical", display: "Sort repos alphabetically" }, { value: "stars", display: "Sort repos by stars" }, { value: "forks", display: "Sort repos by forks" }, ], }; }, mounted() { const params = new URL(document.location).searchParams; const builds = params.get("builds"); if (builds) { this.params.builds = []; this.params.appName = builds; post("getbuilds", { name: builds }).then((result) => { if (result.error) { window.alert(result.error); } else { this.params.builds = result; } }); } const config = params.get("config"); if (config) { this.params.config = {}; this.params.appName = config; post("getconfig", { name: config }).then((result) => { if (result.error) { window.alert(result.error); } else { this.params.config = result; } }); } post("allman", {}).then((result) => { if (result.error) { window.alert(result.error); } else { this.appMan = result.appMan; this.gitMan = result.gitMan; } }); }, }).mount("#app"); hotReload(); </script>