├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── main.yml ├── .gitignore ├── .gitpod.yml ├── .travis.yml ├── .vscode ├── launch.json └── settings.json ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── LICENSE ├── README.md ├── assets └── deno_gui01.png ├── egg.json ├── init.sh ├── localtest.ts ├── mod.ts ├── src ├── controllers.ts ├── engine.ts ├── engine_test.ts ├── models │ ├── CacheFolder.ts │ ├── Folder.ts │ ├── KeyValuePair.ts │ ├── OperatingSystem.ts │ └── ViewData.ts ├── test_deps.ts ├── utils.ts ├── utils_test.ts └── views │ ├── _shared │ ├── _layout.css.ts │ └── _layout.ts │ └── components │ ├── about.ts │ ├── console.ts │ ├── dashboard.ts │ ├── depscaches.ts │ ├── generic.ts │ └── stop.ts └── tslint.json /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Deno CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | build: 8 | name: ${{ matrix.kind }} ${{ matrix.os }} 9 | runs-on: ${{ matrix.os }} 10 | if: "!contains(github.event.head_commit.message, '[skip ci]')" 11 | strategy: 12 | matrix: 13 | os: [macOS-latest, ubuntu-latest, windows-latest] 14 | env: 15 | GH_ACTIONS: true 16 | DENO_BUILD_MODE: release 17 | V8_BINARY: true 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Setup Deno 21 | uses: denolib/setup-deno@master 22 | with: 23 | deno-version: 1.3.0 24 | - name: Tests 25 | run: deno test -A --unstable 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | localtest.ts 2 | sam.txt 3 | test.html 4 | .vercel -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - command: curl -fsSL https://deno.land/x/install/install.sh | sh && DENO_INSTALL="/home/gitpod/.deno" && PATH="$DENO_INSTALL/bin:$PATH" && deno run -A --unstable ./mod.ts 3 | ports: 4 | - port: 8000 5 | onOpen: open-preview 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | install: 4 | - curl -L https://deno.land/x/install/install.sh | sh 5 | - export PATH="$HOME/.deno/bin:$PATH" 6 | 7 | script: 8 | - deno test -A --unstable 9 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Deno", 6 | "type": "node", 7 | "request": "launch", 8 | "cwd": "${workspaceFolder}", 9 | "runtimeExecutable": "deno", 10 | "runtimeArgs": ["run", "--inspect-brk", "-A", "--unstable", "${file}"], 11 | "port": 9229 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deepscan.ignoreConfirmWarning": true, 3 | "deno.enable": true 4 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at s.fakoua@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.12.0 AS deno_gui 2 | RUN apk --no-cache add curl 3 | RUN curl -fsSL https://deno.land/x/install/install.sh | sh 4 | RUN cd /root/.deno/bin 5 | RUN ls /root/ 6 | RUN /root/.deno/bin/deno --version 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Sameh Fakoua 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/fakoua/deno_gui) 2 | 3 | # Deno GUI 4 | 5 | Deno Web GUI with REPL. 6 | 7 | ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/fakoua/deno_gui?style=for-the-badge) 8 | ![GitHub](https://img.shields.io/github/license/fakoua/deno_gui?style=for-the-badge) 9 | ![GitHub last commit](https://img.shields.io/github/last-commit/fakoua/deno_gui?style=for-the-badge) 10 | ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/fakoua/deno_gui/Deno%20CI?style=for-the-badge) 11 | 12 | ## CLI Installation 13 | ``` 14 | deno install -A --unstable -f -n deno_gui https://deno.land/x/deno_gui/mod.ts 15 | ``` 16 | ## Run the server from CLI 17 | ``` 18 | deno_gui 19 | ``` 20 | 21 | ## Using dpx 22 | 23 | ``` 24 | dpx deno_gui -A --unstable --reload 25 | ``` 26 | 27 | ## Run the server from URL 28 | ```bash 29 | deno run -A --unstable https://deno.land/x/deno_gui/mod.ts 30 | ``` 31 | 32 | ## Specify the port: 33 | 34 | ```bash 35 | deno run -A --unstable https://deno.land/x/deno_gui/mod.ts -p=9000 36 | ``` 37 | 38 | Or you can use --port=9000 39 | 40 | ```bash 41 | deno run -A --unstable https://deno.land/x/deno_gui/mod.ts --port=9000 42 | ``` 43 | 44 | Open: http://localhost:8080 45 | 46 | ## Screenshot 47 | 48 | ![Deno GUI](https://raw.githubusercontent.com/fakoua/deno_gui/master/assets/deno_gui01.png) 49 | 50 | ## License 51 | 52 | [MIT](LICENSE) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ffakoua%2Fdeno_gui.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ffakoua%2Fdeno_gui?ref=badge_shield) 53 | 54 | [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ffakoua%2Fdeno_gui.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Ffakoua%2Fdeno_gui?ref=badge_large) 55 | -------------------------------------------------------------------------------- /assets/deno_gui01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fakoua/deno_gui/561f8067bacd25ee5d9839e448e3f67ad02653e5/assets/deno_gui01.png -------------------------------------------------------------------------------- /egg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deno_gui", 3 | "description": "Deno Web GUI", 4 | "stable": true, 5 | "version": "2.0.6", 6 | "files": [ 7 | "./mod.ts", 8 | "./assets/**/*", 9 | "./README.md", 10 | "./src/**/*" 11 | ] 12 | } -------------------------------------------------------------------------------- /init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | curl -fsSL https://deno.land/x/install/install.sh | sh 3 | export DENO_INSTALL="/home/gitpod/.deno" 4 | export PATH="$DENO_INSTALL/bin:$PATH" 5 | echo "----------DONE-----------" 6 | -------------------------------------------------------------------------------- /localtest.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as ink from "https://deno.land/x/ink/mod.ts" 3 | 4 | await ink.drawImage("https://placekitten.com/50/50") 5 | -------------------------------------------------------------------------------- /mod.ts: -------------------------------------------------------------------------------- 1 | import { Application, Router } from "https://deno.land/x/oak/mod.ts"; 2 | import * as utils from "./src/utils.ts" 3 | import * as controllers from "./src/controllers.ts" 4 | import * as cow from "https://deno.land/x/cowsay/mod.ts" 5 | import {_layout_template} from "./src/views/_shared/_layout.ts" 6 | import { css } from "./src/views/_shared/_layout.css.ts" 7 | import { parse } from "https://deno.land/std/flags/mod.ts"; 8 | import * as ink from "https://deno.land/x/ink/mod.ts" 9 | 10 | import { renderAsync } from "./src/engine.ts" 11 | 12 | const router = new Router(); 13 | router 14 | // @ts-ignore 15 | .get("/", context => { 16 | context.response.headers.set("Content-Type", "text/html") 17 | const body = _layout_template.replace("/*@@CSS@@*/", css) 18 | context.response.body = body 19 | }) 20 | 21 | // @ts-ignore 22 | .get("/render/:com", async (context) => { 23 | // @ts-ignore 24 | const model = controllers.getModel(context.params.com) 25 | // @ts-ignore 26 | const result = await renderAsync(context.params.com, model); 27 | context.response.headers.set("Content-Type", "application/json") 28 | context.response.body = result 29 | }) 30 | 31 | // @ts-ignore 32 | .get("/api/deletefolder/:folder", async (context) => { 33 | // @ts-ignore 34 | const result = await utils.deleteFolder(context.params.folder) 35 | context.response.headers.set("Content-Type", "application/json") 36 | context.response.body = result 37 | }) 38 | // @ts-ignore 39 | .get("/api/run/:command", async (context) => { 40 | // @ts-ignore 41 | const result = await utils.runDeno(context.params.command) 42 | context.response.headers.set("Content-Type", "application/json") 43 | context.response.body = result 44 | }) 45 | 46 | // @ts-ignore 47 | .get("/api/folders/:folder", async (context) => { 48 | const folder = context.params.folder 49 | context.response.headers.set("Content-Type", "application/json") 50 | 51 | if (folder === "_root_") { 52 | context.response.body = utils.getCacheTree() 53 | } else { 54 | // @ts-ignore 55 | context.response.body = utils.getFiles(folder) 56 | } 57 | }) 58 | 59 | // @ts-ignore 60 | .get("/api/stop", async (context) => { 61 | context.response.headers.set("Content-Type", "application/json") 62 | Deno.exit(0) 63 | }) 64 | 65 | // @ts-ignore 66 | .get("/api/denolatest/", async (context) => { 67 | const version = await utils.fetchDenoVersion() 68 | context.response.headers.set("Content-Type", "application/json") 69 | context.response.body = version 70 | }) 71 | 72 | const app = new Application(); 73 | app.use(router.routes()); 74 | app.use(router.allowedMethods()); 75 | 76 | const opts = { 77 | default: { 78 | port: 8080 79 | }, 80 | alias: { 81 | port: "p" 82 | } 83 | } 84 | const argsv = parse(Deno.args, opts) 85 | 86 | const urlText = ink.colorize(`Open: http://localhost:${argsv.port}`) 87 | 88 | const text = cow.say({ 89 | text: urlText, 90 | cow: "kitten" 91 | }) 92 | 93 | export async function run() { 94 | console.log(text) 95 | await app.listen(`localhost:${argsv.port}`) 96 | } 97 | 98 | await run(); 99 | -------------------------------------------------------------------------------- /src/controllers.ts: -------------------------------------------------------------------------------- 1 | import * as utils from "./utils.ts" 2 | import startCase from "https://deno.land/x/lodash@4.17.15-es/startCase.js" 3 | 4 | export function getModel(action: string): any { 5 | try { 6 | action = startCase(action) 7 | // @ts-ignore 8 | return this["get" + action]() 9 | } catch (error) { 10 | return error 11 | } 12 | } 13 | 14 | export function getDashboard(): any { 15 | return { 16 | osInfo: utils.getOsInfo(), 17 | envs: utils.getEnv() 18 | } 19 | } 20 | 21 | export function getConsole(): any { 22 | return {} 23 | } 24 | 25 | export function getDepscaches(): any { 26 | const folders = utils.listDepsFolders() 27 | return { 28 | root: utils.getDepsCacheDir(), 29 | folders: folders 30 | } 31 | } 32 | 33 | export function getAbout(): any { 34 | return { 35 | 36 | } 37 | } 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/engine.ts: -------------------------------------------------------------------------------- 1 | import * as dejs from "https://deno.land/x/dejs/mod.ts" 2 | import type { ViewData } from "./models/ViewData.ts" 3 | 4 | import { title as dashboardTitle } from "./views/components/dashboard.ts" // NOSONAR 5 | import { title as aboutTitle } from "./views/components/about.ts" // NOSONAR 6 | import { title as consoleTitle } from "./views/components/console.ts" // NOSONAR 7 | import { title as depscachesTitle } from "./views/components/depscaches.ts" // NOSONAR 8 | 9 | export async function renderAsync(view: string, model: any): Promise { 10 | try { 11 | const comPath = `./views/components/${view}.ts` 12 | const template = await import(comPath) 13 | const output = await dejs.render(template.body, model) 14 | const dataArray = await Deno.readAll(output) 15 | const body = new TextDecoder().decode(dataArray); 16 | return { 17 | title: template.title, 18 | onBeforeRender: template.onBeforeRender, 19 | onAfterRender: template.onAfterRender, 20 | body: body 21 | }; 22 | } catch (error) { 23 | return { 24 | title: "Error", 25 | onBeforeRender: "", 26 | onAfterRender: "", 27 | body: "Not Found Or Internal Error." 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/engine_test.ts: -------------------------------------------------------------------------------- 1 | import * as engine from "./engine.ts" 2 | import { assertEquals } from "./test_deps.ts" 3 | 4 | Deno.test("test_engine_render", async function () { 5 | const result = await engine.renderAsync("generic", {id: 1}); 6 | assertEquals(result.title, "generic_title") 7 | assertEquals(result.body, "body_1") 8 | assertEquals(result.onBeforeRender, "before_script") 9 | assertEquals(result.onAfterRender, "after_script") 10 | }) 11 | -------------------------------------------------------------------------------- /src/models/CacheFolder.ts: -------------------------------------------------------------------------------- 1 | export interface CacheFolder { 2 | path: string 3 | name: string 4 | created: Date 5 | id: string 6 | } 7 | -------------------------------------------------------------------------------- /src/models/Folder.ts: -------------------------------------------------------------------------------- 1 | export interface Folder { 2 | id: string 3 | text: string 4 | children: Array 5 | } 6 | 7 | export interface FileExplorer { 8 | id: string 9 | name: string 10 | isFile: boolean, 11 | size: string 12 | } 13 | -------------------------------------------------------------------------------- /src/models/KeyValuePair.ts: -------------------------------------------------------------------------------- 1 | export interface KeyValuePair { 2 | key: string 3 | value: T 4 | } 5 | -------------------------------------------------------------------------------- /src/models/OperatingSystem.ts: -------------------------------------------------------------------------------- 1 | export interface OperatingSystem { 2 | arch: string 3 | os: string 4 | denoVersion: string 5 | v8Version: string, 6 | typescriptVersion: string 7 | denoPath: string 8 | currentPath: string 9 | homeDir: string 10 | hostname: string 11 | } 12 | -------------------------------------------------------------------------------- /src/models/ViewData.ts: -------------------------------------------------------------------------------- 1 | export interface ViewData { 2 | title: string 3 | body: string 4 | onBeforeRender: string 5 | onAfterRender: string 6 | } 7 | -------------------------------------------------------------------------------- /src/test_deps.ts: -------------------------------------------------------------------------------- 1 | export { 2 | assert, 3 | assertEquals, 4 | assertThrows, 5 | assertThrowsAsync 6 | } from "https://deno.land/std/testing/asserts.ts"; 7 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as path from "https://deno.land/std/path/mod.ts"; 2 | import type { OperatingSystem } from "./models/OperatingSystem.ts"; 3 | import type { CacheFolder } from "./models/CacheFolder.ts" 4 | import type { KeyValuePair } from "./models/KeyValuePair.ts" 5 | import type { Folder, FileExplorer } from "./models/Folder.ts" 6 | import "https://deno.land/x/humanizer/byteSize.ts" 7 | 8 | function listFolders(rootFolder: string): Array { 9 | const rtnVal = new Array() 10 | for (const dirEntry of Deno.readDirSync(rootFolder)) { 11 | const f: CacheFolder = { 12 | created: new Date(), 13 | name: dirEntry.name, 14 | path: rootFolder, 15 | id: btoa(path.join(rootFolder, dirEntry.name)) 16 | } 17 | rtnVal.push(f) 18 | } 19 | return rtnVal.slice(0, 20) 20 | } 21 | 22 | function getFoldersTree(p: string): Array { 23 | const folders: Array = new Array() 24 | 25 | for (const dirEntry of Deno.readDirSync(p)) { 26 | if (dirEntry.isDirectory) { 27 | const folder: Folder = { 28 | id: btoa(path.join(p, dirEntry.name)), 29 | text: dirEntry.name, 30 | children: [] 31 | } 32 | folders.push(folder) 33 | folder.children = getFoldersTree(path.join(p, dirEntry.name)) 34 | } 35 | } 36 | return folders; 37 | } 38 | 39 | enum OS { 40 | windows, linux, darwin 41 | } 42 | 43 | function getOS(): OS { 44 | // @ts-ignore 45 | return OS[Deno.build.os]; 46 | } 47 | 48 | function sortByName(folders: Array): Array { 49 | return folders.sort((f1, f2) => { 50 | if (f1.name > f2.name) { 51 | return 1 52 | } 53 | if (f1.name < f2.name) { 54 | return -1 55 | } 56 | return 0 57 | }) 58 | } 59 | 60 | function sortByType(folders: Array): Array { 61 | return folders.sort((f1, f2) => { 62 | if (f1.isFile) { 63 | return 1 64 | } 65 | if (f2.isFile) { 66 | return -1 67 | } 68 | return 0 69 | }) 70 | } 71 | 72 | // Exports 73 | export function getOsInfo(): OperatingSystem { 74 | return { 75 | arch: Deno.build.arch, 76 | currentPath: Deno.cwd(), 77 | denoPath: Deno.execPath(), 78 | denoVersion: Deno.version.deno, 79 | homeDir: getDenoDir(), 80 | hostname: Deno.hostname(), 81 | os: Deno.build.os, 82 | typescriptVersion: Deno.version.typescript, 83 | v8Version: Deno.version.v8 84 | }; 85 | } 86 | 87 | export function getEnv(): Array> { 88 | const rtnVal: Array> = new Array>() 89 | const env = Deno.env.toObject(); 90 | Object.keys(env).forEach((k) => { 91 | const item: KeyValuePair = { 92 | key: k, 93 | value: env[k] 94 | } 95 | rtnVal.push(item) 96 | }) 97 | return rtnVal 98 | } 99 | 100 | /** 101 | * Returs deno root directory 102 | * Example: 103 | * - (C:\Users\USERNAME\AppData\Local\deno) on windows 104 | * - (/home/USERNAME/.cache/deno) on linux 105 | */ 106 | export function getDenoDir(): string { 107 | const os = getOS(); 108 | const homeKey: string = os === OS.windows ? "USERPROFILE" : "HOME" 109 | const homeDir = Deno.env.get(homeKey) 110 | let relativeDir = ""; 111 | 112 | switch (os) { 113 | case OS.windows: 114 | relativeDir = "AppData/Local/deno" 115 | break; 116 | case OS.linux: 117 | relativeDir = ".cache/deno" 118 | break; 119 | case OS.darwin: 120 | relativeDir = "Library/Caches/deno" 121 | break; 122 | } 123 | // @ts-ignore 124 | return path.join(homeDir, relativeDir) 125 | } 126 | 127 | export function getDepsCacheDir(): string { 128 | const homeDir = getDenoDir() 129 | return path.join(homeDir, "deps/https/") 130 | } 131 | 132 | export function getTypeScriptCacheDirLocal(): string { 133 | const homeDir = getDenoDir() 134 | return path.join(homeDir, "gen/file") 135 | } 136 | 137 | export function getTypeScriptCacheDirRemote(): string { 138 | const homeDir = getDenoDir() 139 | return path.join(homeDir, "gen/https") 140 | } 141 | 142 | export function listDepsFolders(): Array { 143 | const rootFolder = getDepsCacheDir() 144 | return listFolders(rootFolder) 145 | } 146 | 147 | export async function deleteFolder(folder: string): Promise { 148 | try { 149 | folder = atob(folder) 150 | await Deno.remove(folder, { recursive: true }) 151 | return { 152 | success: true, 153 | error: "" 154 | } 155 | } catch (error) { 156 | return { 157 | success: false, 158 | error: error 159 | } 160 | } 161 | } 162 | 163 | export async function runDeno(command: string): Promise { 164 | try { 165 | command = atob(command); 166 | const p = Deno.run({ 167 | cmd: ["deno", "eval", "--unstable", command], 168 | stdout: "piped", 169 | stderr: "piped" 170 | }) 171 | 172 | const { code } = await p.status(); 173 | 174 | let res: string; 175 | if (code === 0) { 176 | const rawOutput = await p.output(); 177 | res = new TextDecoder("utf-8").decode(rawOutput) 178 | } else { 179 | const rawError = await p.stderrOutput(); 180 | res = new TextDecoder().decode(rawError); 181 | } 182 | p.close(); 183 | return res; 184 | } catch (error) { 185 | return error.toString(); 186 | } 187 | } 188 | 189 | export async function fetchDenoVersion(): Promise { 190 | try { 191 | const response = await fetch("https://github.com/denoland/deno/releases/latest") 192 | const body = await response.text() 193 | const regVer = new RegExp(/title\=\"v(.*)?\"/) 194 | const res = regVer.exec(body) 195 | // @ts-ignore 196 | return res[1] 197 | } catch (error) { 198 | return "Error fetching" 199 | } 200 | 201 | } 202 | 203 | export function getCacheTree(): Array { 204 | const p = getDenoDir() 205 | return getFoldersTree(p); 206 | } 207 | 208 | export function getFiles(root: string): Array { 209 | root = atob(root) 210 | let folders: Array = new Array() 211 | 212 | for (const element of Deno.readDirSync(root)) { 213 | const folder: FileExplorer = { 214 | id: btoa(path.join(root, element.name)), 215 | isFile: element.isFile, 216 | name: element.name, 217 | size: "" 218 | } 219 | folders.push(folder) 220 | } 221 | 222 | folders = sortByName(folders) 223 | folders = sortByType(folders) 224 | return folders 225 | } 226 | -------------------------------------------------------------------------------- /src/utils_test.ts: -------------------------------------------------------------------------------- 1 | import * as utils from "./utils.ts" 2 | import { assert } from "./test_deps.ts" 3 | 4 | Deno.test("test_utils_getOs", function () { 5 | assert(utils.getOsInfo().os.length > 2) 6 | }) 7 | 8 | Deno.test("test_utils_getDirInfo", function () { 9 | assert(utils.getDenoDir().includes("deno")) 10 | }) 11 | 12 | Deno.test("test_utils_getTypeScriptCacheDirLocal", function () { 13 | assert(utils.getTypeScriptCacheDirLocal().includes("gen")) 14 | }) 15 | -------------------------------------------------------------------------------- /src/views/_shared/_layout.css.ts: -------------------------------------------------------------------------------- 1 | export const css = ` 2 | body { 3 | -webkit-font-smoothing: antialiased; 4 | -moz-font-smoothing: grayscale; 5 | } 6 | #container { 7 | margin-top:18px; 8 | } 9 | #sidebar { 10 | position: fixed; 11 | height: 100vh; 12 | background-color: #f5f5f5; 13 | padding-top: 68px; 14 | padding-left: 0; 15 | padding-right: 0; 16 | } 17 | 18 | #sidebar .ui.menu > a.item { 19 | padding: 10px 20px; 20 | line-height: 20px; 21 | color: #337ab7; 22 | border-radius: 0 !important; 23 | margin-top: 0; 24 | margin-bottom: 0; 25 | } 26 | 27 | #sidebar .ui.menu > a.item.active { 28 | background-color: #337ab7; 29 | color: white; 30 | border: none !important; 31 | } 32 | 33 | #sidebar .ui.menu > a.item:hover { 34 | background-color: #eee; 35 | color: #23527c; 36 | } 37 | 38 | #content { 39 | padding-top: 56px; 40 | padding-left: 20px; 41 | padding-right: 20px; 42 | } 43 | 44 | #content h1 { 45 | font-size: 36px; 46 | } 47 | 48 | #content .ui.dividing.header { 49 | width: 100%; 50 | } 51 | 52 | .ui.centered.small.circular.image { 53 | margin-top: 14px; 54 | margin-bottom: 14px; 55 | } 56 | 57 | .ui.borderless.menu { 58 | box-shadow: none; 59 | flex-wrap: wrap; 60 | border: none; 61 | padding-left: 0; 62 | padding-right: 0; 63 | } 64 | 65 | .ui.mobile.only.grid .ui.menu .ui.vertical.menu { 66 | display: none; 67 | } 68 | 69 | @media only screen and (min-width: 992px) { 70 | .ui.column.grid>[class*="thirteen wide computer"].column, .ui.grid>.column.row>[class*="thirteen wide computer"].column, .ui.grid>.row>[class*="thirteen wide computer"].column, .ui.grid>[class*="thirteen wide computer"].column { 71 | width: 87.00%!important; 72 | } 73 | } 74 | ` 75 | -------------------------------------------------------------------------------- /src/views/_shared/_layout.ts: -------------------------------------------------------------------------------- 1 | export const _layout_template = ` 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Deno GUI 12 | 13 | 15 | 16 | 19 | 20 | 21 |
22 |
23 |

Loading

24 |
25 |
26 |
27 | 30 |
31 |
32 | 52 |
53 |
54 | 65 |
66 |
67 |
68 |
69 |
70 | Deno GUI 71 |
Loading ...
72 |
73 |
74 |
75 |
76 |
77 |
78 | 79 | 80 | 82 | 84 | 85 | 86 | 87 | 190 | 191 | 192 | 193 | ` 194 | -------------------------------------------------------------------------------- /src/views/components/about.ts: -------------------------------------------------------------------------------- 1 | export const title = "About Deno GUI" 2 | export const body = ` 3 |

Deno GUI

4 | A Web interface for Deno 5 |
6 |

Credits

7 |
8 |
9 |
10 | 11 |
12 | Deno: A secure runtime for JavaScript and TypeScript 13 |
14 |
15 | 16 |
17 | 18 |
19 | oak: A middleware framework for Deno's net server 20 |
21 |
22 | 23 |
24 | 25 |
26 | lodash: A modern JavaScript utility library delivering modularity, performance & extras. 27 |
28 |
29 | 30 |
31 | 32 |
33 | Semantic UI: UI component framework based around useful principles from natural language. 34 |
35 |
36 | 37 |
38 | 39 |
40 | Monaco Editor: The Monaco Editor is the code editor that powers VS Code. 41 |
42 |
43 | 44 |
45 | 46 |
47 | Xterm.js: A terminal for the web. 48 |
49 |
50 | 51 |
52 | 53 |
54 | jQuery: write less, do more. 55 |
56 |
57 | 58 |
59 | 60 |
61 | axios: Promise based HTTP client for the browser and node.js 62 |
63 |
64 | 65 |
66 | 67 |
68 | ink: Terminal string color for Deno 69 |
70 |
71 | 72 |
73 | 74 |
75 | cowsay: Configurable talking cow for Deno 76 |
77 |
78 | 79 |
80 | 81 |

Author

82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | github 90 |
91 |
92 |
93 | 94 |
95 |
96 |
Sameh Fakoua
97 |
98 | s.fakoua@gmail.com 99 |
100 |
101 | 107 |
108 |
109 | ` 110 | export const onBeforeRender = `` 111 | export const onAfterRender = ` 112 | inlineScript = function () { 113 | $('.special.cards .image').dimmer({ 114 | on: 'hover' 115 | }); 116 | } 117 | ` 118 | -------------------------------------------------------------------------------- /src/views/components/console.ts: -------------------------------------------------------------------------------- 1 | export const title = "Web REPL" 2 | export const body = ` 3 |
4 |
5 | 9 | 64 |
65 |
66 |
67 | // Text To Speech 68 | import * as swissKnife from "https://deno.land/x/swissKnife/mod.ts" 69 | await swissKnife.speak("Hello from Deno", {rate: 1, volume: 100}) 70 | console.log("Done.") 71 |
72 |
73 | // Play Beep 74 | import * as swissKnife from "https://deno.land/x/swissKnife/mod.ts" 75 | await swissKnife.beep(500, 1000) //play 500 hz for 1 sec. 76 |
77 | 78 |
79 | // Show Windows Notification 80 | import * as swissKnife from "https://deno.land/x/swissKnife/mod.ts" 81 | await swissKnife.notification("My Title", "Hello Notification", 77, 2000) 82 |
83 | 84 |
85 | // Question box. NB 86 | // NB: The message box may appear in the background. 87 | import * as swissKnife from "https://deno.land/x/swissKnife/mod.ts" 88 | 89 | let res = await swissKnife.questionBox("A Question", "Do you want to quite smoking?") 90 | if (res) { 91 | console.log("Great, keep trying!") 92 | } else { 93 | console.log("Not Great, but keep trying!") 94 | } 95 |
96 | 97 |
98 | // ByteSize 99 | import "https://deno.land/x/humanizer/byteSize.ts" 100 | 101 | let fileSize = (10).kilobytes() 102 | console.log(fileSize.bits) // 81920 103 | console.log(fileSize.bytes) // 10240 104 | console.log(fileSize.kilobytes) // 10 105 | console.log(fileSize.megabytes) // 0.009765625 106 | console.log(fileSize.gigabytes) // 0.0000095367431640625 107 | console.log(fileSize.terabytes) // 9.313225746154785e-9 108 |
109 | 110 |
111 | // ByteSize 112 | import "https://deno.land/x/humanizer/byteSize.ts" 113 | 114 | let f = (4).gigabytes().add((22).megabytes()).subtract((980).kilobytes()).addGigabytes(1) 115 | console.log(f.toString()) // - 5.020549774169922 GB 116 |
117 | 118 |
119 | import "https://deno.land/x/humanizer/vocabularies.ts" 120 | 121 | console.log("Man".pluralize()) 122 | console.log("string".pluralize()) 123 | 124 | //Singularize 125 | 126 | console.log("Men".singularize()) 127 | console.log("strings".singularize()) 128 |
129 | 130 |
131 | import "https://deno.land/x/humanizer/ordinalize.ts" 132 | 133 | console.log((1).ordinalize()) 134 | console.log((5).ordinalize()) 135 |
136 | 137 |
138 | import { ShowQuantityAs } from "https://deno.land/x/humanizer/toQuantity.ts" 139 | 140 | console.log("case".toQuantity(0)) 141 | console.log("case".toQuantity(1)) 142 | console.log("case".toQuantity(5)) 143 | console.log("man".toQuantity(0)) 144 | console.log("man".toQuantity(1)) 145 | console.log("man".toQuantity(2)) 146 | 147 | //ToQuantity can figure out whether the input word is singular or plural and will singularize or pluralize as necessary: 148 | 149 | console.log("men".toQuantity(2)) 150 | console.log("process".toQuantity(2)) 151 | console.log("process".toQuantity(1)) 152 | console.log("processes".toQuantity(2)) 153 | console.log("processes".toQuantity(1)) 154 | 155 | /* 156 | You can also pass a second argument, ShowQuantityAs, to toQuantity to specify how you want the provided quantity 157 | to be outputted. The default value is ShowQuantityAs.Numeric which is what we saw above. The other two values are 158 | ShowQuantityAs.Words and ShowQuantityAs.None. 159 | */ 160 | 161 | console.log("case".toQuantity(5, ShowQuantityAs.Words)) 162 | console.log("case".toQuantity(5, ShowQuantityAs.None)) 163 |
164 | 165 |
166 | import "https://deno.land/x/humanizer/numberToNumbers.ts" 167 | 168 | console.log((1.25).billions()) 169 | console.log((3).hundreds().thousands()) 170 |
171 | 172 |
173 | import "https://deno.land/x/humanizer/numberToWords.ts" 174 | 175 | console.log((1).toWords()) 176 | console.log((10).toWords()) 177 | console.log((11).toWords()) 178 | console.log((122).toWords()) 179 | console.log((3501).toWords()) 180 |
181 | 182 |
183 | import "https://deno.land/x/humanizer/numberToWords.ts" 184 | 185 | console.log((0).toOrdinalWords()) 186 | console.log((1).toOrdinalWords()) 187 | console.log((2).toOrdinalWords()) 188 | console.log((8).toOrdinalWords()) 189 | console.log((10).toOrdinalWords()) 190 | console.log((11).toOrdinalWords()) 191 | console.log((12).toOrdinalWords()) 192 | console.log((20).toOrdinalWords()) 193 | console.log((21).toOrdinalWords()) 194 | console.log((121).toOrdinalWords()) 195 |
196 | 197 |
198 | import "https://deno.land/x/humanizer/romanNumerals.ts" 199 | 200 | console.log((1).toRoman()) 201 | console.log((2).toRoman()) 202 | console.log((3).toRoman()) 203 | console.log((4).toRoman()) 204 | console.log((5).toRoman()) 205 | console.log((6).toRoman()) 206 | console.log((7).toRoman()) 207 | console.log((8).toRoman()) 208 | console.log((9).toRoman()) 209 | console.log((10).toRoman()) 210 | 211 | //Also the reverse operation using the fromRoman extension. 212 | 213 | console.log("I".fromRoman()) 214 | console.log("II".fromRoman()) 215 | console.log("III".fromRoman()) 216 | console.log("IV".fromRoman()) 217 | console.log("V".fromRoman()) 218 |
219 | 220 |
221 | import "https://deno.land/x/humanizer/metricNumerals.ts" 222 | 223 | console.log((1).toMetric()) 224 | console.log((1230).toMetric()) 225 | console.log((0.1).toMetric()) 226 | 227 | //Also the reverse operation using the fromMetric extension. 228 | 229 | console.log("1.23k".fromMetric()) 230 | console.log("100m".fromMetric()) 231 |
232 | 233 |
234 | // Capture web url 235 | // Make sure the folder MyFolder exists 236 | // May take log time at first run to download chromium. 237 | 238 | import { Capture } from 'https://deno.land/x/deno_shot/mod.ts' 239 | 240 | let res = await Capture({ 241 | url: 'https://www.github.com', 242 | image: 'C:/MyFolder/image.png', 243 | maximized: false, 244 | windowSize: { 245 | width: 1000, 246 | height: 890 247 | } 248 | }); 249 | 250 | if (res.success) { 251 | console.log(res.image) 252 | } 253 |
254 | 255 |
256 | import { soxa } from 'https://deno.land/x/soxa/mod.ts' 257 | 258 | // Make a request for todos 259 | soxa.get('https://jsonplaceholder.typicode.com/todos/1') 260 | .then(function (response) { 261 | // handle success 262 | console.log(response.data); 263 | }) 264 | .catch(function (error) { 265 | // handle error 266 | console.log(error); 267 | }) 268 | .finally(function () { 269 | console.log("Done") 270 | }); 271 |
272 | 273 |
274 | import { soxa } from 'https://deno.land/x/soxa/mod.ts' 275 | 276 | let body = await soxa.get('https://github.com/denoland/deno/releases/latest'); 277 | const regVer = new RegExp(/title\=\"v(.*)?\"/) 278 | let res = regVer.exec(body.data) 279 | //@ts-ignore 280 | console.log("Deno live version: ", res[1]) 281 |
282 | 283 |
284 | import * as o from 'https://deno.land/x/cowsay/mod.ts' 285 | 286 | let m = o.say({ 287 | text: 'hello every one' 288 | }) 289 | console.log(m) 290 |
291 | 292 |
293 | import * as ink from 'https://deno.land/x/ink/mod.ts' 294 | 295 | let text = ink.colorize('Hello World') 296 | console.log(text) 297 | 298 | //You can use nested style: 299 | 300 | text = ink.colorize('Hello World') 301 | 302 | console.log(text) 303 |
304 | 305 |
306 | import * as ink from 'https://deno.land/x/ink/mod.ts' 307 | 308 | ink.terminal.log('Hello %s', 'World') 309 |
310 | 311 |
312 | import * as ink from 'https://deno.land/x/ink/mod.ts' 313 | 314 | let html = ' ' + 315 | '' + 316 | ' Im Red, background Green, underlined and bold!' + 317 | ' ' + 318 | ' My BG is black again, but Im italic :(' + 319 | ' ' + 320 | ' My BG is Green Again!' + 321 | '' + 322 | 'No Format here'; 323 | 324 | let result = ink.html(html) 325 | console.log(result); 326 |
327 | 328 |
329 | 330 |
331 | 332 | ` 333 | export const onBeforeRender = `` 334 | export const onAfterRender = ` 335 | inlineScript = function() { 336 | $('.ui.dropdown').dropdown({ 337 | action: 'hide', 338 | onChange: function() { 339 | let index = $(arguments[2]).data("index"); 340 | let code = $('div[data-example="' + index + '"]').html(); 341 | editor.setValue(code); 342 | } 343 | }); 344 | let data =''; 345 | term = new Terminal({ 346 | cursorBlink: false, 347 | disableStdin: true, 348 | rows: 20 349 | }); 350 | term.open(document.getElementById('terminal')); 351 | term.prompt = () => { 352 | term.write('\\r\\ndeno> '); 353 | }; 354 | term.writeln('Welcome to Deno Terminal'); 355 | term.prompt(term); 356 | } 357 | ` 358 | -------------------------------------------------------------------------------- /src/views/components/dashboard.ts: -------------------------------------------------------------------------------- 1 | export const title = "Dashboard" 2 | export const body = ` 3 |
4 |
5 | 6 |
7 |
8 | 9 |
10 |
Host:
11 |
<%=osInfo.hostname%>
12 |
13 |
14 |
15 | 16 |
17 |
Operating System:
18 |
<%=osInfo.os%>
19 |
20 |
21 |
22 | 23 |
24 |
Architecture:
25 |
<%=osInfo.arch%>
26 |
27 |
28 |
29 | 30 |
31 |
Current Path:
32 |
<%=osInfo.currentPath%>
33 |
34 |
35 |
36 | 37 |
38 |
Home Directory:
39 |
<%=osInfo.homeDir%>
40 |
41 |
42 |
43 | 44 |
45 |
Deno Path:
46 |
<%=osInfo.denoPath%>
47 |
48 |
49 |
50 | 51 |
52 |
Deno Version:
53 |
<%=osInfo.denoVersion%> latest version: 54 | ...
55 |
56 |
57 |
58 | 59 |
60 |
Typescript Version:
61 |
<%=osInfo.typescriptVersion%>
62 |
63 |
64 |
65 | 66 |
67 |
V8 Version:
68 |
<%=osInfo.v8Version%>
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | 77 |

78 | Environment Variables 79 |

80 | 81 |
82 | <% envs.forEach(function(env){ %> 83 |
84 | 85 |
86 |
<%=env.key%>:
87 |
<%=env.value%>
88 |
89 |
90 | <% }); %> 91 |
92 | 93 |
94 |
95 | ` 96 | export const onBeforeRender = `` 97 | export const onAfterRender = ` 98 | inlineScript = function() { 99 | axios.get('/api/denolatest/') 100 | .then((res) => { 101 | $('#denolatest').html(res.data) 102 | }) 103 | } 104 | ` 105 | -------------------------------------------------------------------------------- /src/views/components/depscaches.ts: -------------------------------------------------------------------------------- 1 | export const title = "Deno Cache" 2 | export const body = ` 3 |
4 |
5 |
6 |
7 |
8 |
9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | 20 |
13 | 15 |
21 |
22 |
23 |
24 | 25 | 42 | ` 43 | export const onBeforeRender = `` 44 | export const onAfterRender = ` 45 | inlineScript = function() { 46 | $('.ui.dimmer.modals').remove() 47 | function uiPrompt(e) { 48 | let modal= $('.mini.modal') 49 | .modal({ 50 | onApprove: () => { 51 | processDelete(e) 52 | }, 53 | onDeny: () => { 54 | //console.log('deny') 55 | }, 56 | onHide: () => { 57 | //console.log('hide') 58 | } 59 | }); 60 | modal.modal('show') 61 | } 62 | 63 | $('button[data-folder]').click((e) => { 64 | uiPrompt(e); 65 | }); 66 | 67 | function processDelete(e) { 68 | let folder = $(e.currentTarget).data('folder') 69 | let isfile = $(e.currentTarget).data('isfile') 70 | $(e.currentTarget).addClass('loading') 71 | axios.get('/api/deletefolder/' + folder) 72 | .then((res) => { 73 | if (res.data.success) { 74 | //$('.ui.dimmer.modals').remove(); 75 | //renderComponent('depscaches'); 76 | //remove the file or folder 77 | $('tr[data-id="' + folder + '"]').remove() 78 | let node = $('#jstree-tree').jstree(true).get_node(folder) 79 | if (!isfile) { 80 | $.jstree.reference("#jstree-tree").delete_node(node); 81 | console.log('reeeeeeeeee') 82 | } 83 | } else { 84 | alert("Error deleting this folder: Error -> " + res.data.error.name) 85 | } 86 | }) 87 | .catch((error) => { 88 | alert(error) 89 | }) 90 | .finally(() => { 91 | $(e.currentTarget).removeClass('loading') 92 | }) 93 | } 94 | 95 | 96 | $('#jstree-tree') 97 | .on('changed.jstree', function (e, data) { 98 | let tmp = '{{#each folders}}' + 99 | '' + 100 | ' {{this.name}}' + 101 | '{{this.size}}' + 102 | '' + 103 | ' ' + 106 | '' + 107 | '{{/each}}'; 108 | 109 | 110 | let hd = '
Home
' 111 | 112 | let bcTemp = '{{#each items}}' + 113 | '' + 114 | '
{{this}}
' + 115 | '{{/each}}' 116 | 117 | var objNode = data.instance.get_node(data.selected); 118 | var objPath = data.instance.get_path(data.selected) 119 | axios.get('/api/folders/' + objNode.id) 120 | .then((res) => { 121 | const template = Handlebars.compile(tmp) 122 | let folders = { 123 | folders: res.data 124 | } 125 | let html = template(folders) 126 | $('#explorer-body').html(html) 127 | 128 | const bc = Handlebars.compile(bcTemp) 129 | let bcHtml = bc({items: objPath}) 130 | $('#breadcrumb').html(hd + bcHtml) 131 | $('button[data-folder]').click((e) => { 132 | uiPrompt(e); 133 | //alert(1) 134 | }); 135 | }) 136 | }) 137 | .jstree({ 138 | core: { 139 | data: { 140 | url: '/api/folders/_root_' 141 | }, 142 | check_callback: function() { 143 | return true; 144 | } 145 | }, 146 | "plugins" : [ "wholerow" ] 147 | }); 148 | 149 | } 150 | ` 151 | -------------------------------------------------------------------------------- /src/views/components/generic.ts: -------------------------------------------------------------------------------- 1 | export const title = "generic_title" 2 | export const body = `body_<%=id%>` 3 | export const onBeforeRender = `before_script` 4 | export const onAfterRender = `after_script` 5 | -------------------------------------------------------------------------------- /src/views/components/stop.ts: -------------------------------------------------------------------------------- 1 | export const title = "Stop Deno GUI" 2 | export const body = ` 3 |
4 |
5 |

6 | 7 | Thank you for using Deno GUI 8 |

9 |
10 |
11 |
12 | 16 |
17 | ` 18 | export const onBeforeRender = `` 19 | export const onAfterRender = ` 20 | inlineScript = function() { 21 | $("#btn-stop").click((e) => { 22 | e.preventDefault(); 23 | $("#btn-stop").addClass("loading"); 24 | axios.get('/api/stop') 25 | .then((res) => { 26 | 27 | }) 28 | .catch((error) => { 29 | }) 30 | .finally(() => { 31 | $('#dim').dimmer({opacity: 0.5, closable: false}).dimmer('show'); 32 | }) 33 | }) 34 | } 35 | ` 36 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ ], 3 | "rules": { 4 | "arrow-return-shorthand": true, 5 | "callable-types": true, 6 | "class-name": true, 7 | "comment-format": [ 8 | true, 9 | "check-space" 10 | ], 11 | "curly": true, 12 | "eofline": true, 13 | "forin": true, 14 | "import-blacklist": [ 15 | true, 16 | "rxjs" 17 | ], 18 | "import-spacing": true, 19 | "indent": [ 20 | true, 21 | "spaces" 22 | ], 23 | "interface-over-type-literal": true, 24 | "label-position": true, 25 | "max-line-length": [ 26 | true, 27 | 140 28 | ], 29 | "member-access": false, 30 | "no-arg": true, 31 | "no-bitwise": true, 32 | "no-console": [ 33 | true, 34 | "debug", 35 | "info", 36 | "time", 37 | "timeEnd", 38 | "trace" 39 | ], 40 | "no-construct": true, 41 | "no-debugger": true, 42 | "no-duplicate-super": true, 43 | "no-empty": false, 44 | "no-empty-interface": true, 45 | "no-eval": true, 46 | "no-inferrable-types": [ 47 | true, 48 | "ignore-params" 49 | ], 50 | "no-misused-new": true, 51 | "no-non-null-assertion": true, 52 | "no-shadowed-variable": true, 53 | "no-string-literal": false, 54 | "no-string-throw": true, 55 | "no-switch-case-fall-through": true, 56 | "no-trailing-whitespace": false, 57 | "no-unnecessary-initializer": true, 58 | "no-unused-expression": true, 59 | "no-var-keyword": true, 60 | "object-literal-sort-keys": false, 61 | "one-line": [ 62 | true, 63 | "check-open-brace", 64 | "check-catch", 65 | "check-else", 66 | "check-whitespace" 67 | ], 68 | "prefer-const": true, 69 | "quotemark": [ 70 | true, 71 | "double" 72 | ], 73 | "radix": true, 74 | "semicolon": [ 75 | "always" 76 | ], 77 | "triple-equals": [ 78 | true, 79 | "allow-null-check" 80 | ], 81 | "typedef-whitespace": [ 82 | true, 83 | { 84 | "call-signature": "nospace", 85 | "index-signature": "nospace", 86 | "parameter": "nospace", 87 | "property-declaration": "nospace", 88 | "variable-declaration": "nospace" 89 | } 90 | ], 91 | "unified-signatures": true, 92 | "variable-name": false, 93 | "whitespace": [ 94 | true, 95 | "check-branch", 96 | "check-decl", 97 | "check-operator", 98 | "check-separator", 99 | "check-type" 100 | ] 101 | } 102 | } --------------------------------------------------------------------------------