Ctrl K
ComunidadGuías…

extensions/web-base/www/app.html

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
  <title>App</title>
  <link rel="stylesheet" href="app.css">
  <link rel="stylesheet" href="static/fa/css/all.min.css">
  <link rel="icon" type="image/png" sizes="32x32" href="static/favicon-32x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="static/favicon-16x16.png">
  <script src="static/promise.min.js" type="text/javascript" charset="utf-8"></script>
  <script src="static/fetch.umd.js" type="text/javascript" charset="utf-8"></script>
  <script src="static/fetch-compat.js" type="text/javascript" charset="utf-8"></script>
  <script src="static/v/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body class="theme_boot">
<div class="splash">
  Loading...
  <!--
    <i class="fas fa-spinner fa-spin"></i>
  -->
</div>
<!-- v-if="show" class="toaster" -->
<div id="toaster" :class="['toaster', show ? '' : 'hide']">{{message}}</div>
<!-- Custom pages used by components -->
<div id="custom-pages" class="pages">
  <!--
    confirmation dialog
  -->
  <app-dialog id="confirmation" title="Confirm">
    <template slot="bar-right">
      <button v-on:click="app.closeDialog()"><i class="fa fa-window-close"></i></button>
    </template>
    <page-article>
      <p>{{ message }}</p>
      <button v-on:click="onConfirm()"><i class="fas fa-check"></i>&nbsp;Confirm</button>
      <button v-on:click="app.closeDialog()"><i class="fas fa-times"></i>&nbsp;Cancel</button>
    </page-article>
  </app-dialog>
  <!--
    prompt dialog
  -->
  <app-dialog id="prompt" title="Prompt">
    <template slot="bar-right">
      <button v-on:click="app.closeDialog()"><i class="fa fa-window-close"></i></button>
    </template>
    <page-article>
      <p>{{ message }}</p>
      <template v-if="schema">
        <json name="Input" :obj="value" :schema="schema"></json>
        <button v-on:click="onConfirm()"><i class="fas fa-check"></i>&nbsp;Confirm</button>
        <button v-on:click="app.closeDialog()"><i class="fas fa-times"></i>&nbsp;Cancel</button>
      </template>
    </page-article>
  </app-dialog>
  <!--
    default menu
  -->
  <app-menu id="menu" title="Menu" home-page="home">
    <article class="content">
      <ul>
        <li v-for="page in sortedPages" v-on:click="app.toPage(page.id)">
          <i class="fas fa-angle-right" v-if="app.page === page.id"></i>
          <label>{{ page.name }}</label>
        </li>
      </ul>
    </article>
  </app-menu>
  <!--
    properties
  -->
  <app-page id="properties" title="Properties">
    <template slot="bar-right">
      <input v-if="filter" v-model="query" type="text" placeholder="Type to filter">
      <button v-on:click="toggleFilter(event)"><i class="fas fa-search"></i></button>
    </template>
    <page-article>
      <table style="border-spacing: 0.5rem 0; width: 100%;">
        <thead>
          <tr>
            <th class="show-xl">Extension</th>
            <th>Thing</th>
            <th class="show-m">Property</th>
            <th>Value</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="property in filteredProperties">
            <td class="show-xl"><span :title="property.extension.description">{{ property.extension.name }}</span></td>
            <td><span :title="property.thing.description">{{ property.thing.title }}</span></td>
            <td class="show-m"><span :title="property.description + ' (' + property.name + ')'">{{ property.title }}</span></td>
            <td><span>{{ property.value }}</span></td>
          </tr>
        </tbody>
      </table>
    </page-article>
  </app-page>
  <!--
    things
  -->
  <app-page id="things" title="Things">
    <template slot="bar-right">
      <input v-if="filter" v-model="query" type="text" placeholder="Type to filter">
      <button v-on:click="toggleFilter(event)"><i class="fas fa-search"></i></button>
      <button v-if="app.canConfigure" v-on:click="app.toPage('addThings')"><i class="fa fa-plus"></i></button>
      <button v-if="edit" v-on:click="onSave" title="Save"><i class="far fa-save"></i></button>
      <button v-if="app.canConfigure" v-on:click="edit = !edit" title="Edit"><i :class="['fas', edit ? 'fa-eye' : 'fa-edit']"></i></button>
    </template>
    <article class="cards">
      <div class="card" v-for="thing in filteredThings">
        <div class="bar">
          <div>
            <p>{{ thing.title + (thing.extensionId in extensionsById ? (' (' + extensionsById[thing.extensionId].name + ')') : '') }}</p>
          </div>
          <div>
            <button v-on:click="app.toPage('thing', thing.thingId)"><i class="fas fa-info"></i>&nbsp;Details</button>
          </div>
        </div>
        <p>{{ thing.description }}</p>
        <div class="bar">
          <div><p v-if="edit">
            <label class="switch"><input type="checkbox" v-model="thing.archiveData"/><span class="slider"></span></label>&nbsp;Archive Data
          </p></div>
          <div>
            <p>{{ (thing.thingId in propertiesById ? (propertiesById[thing.thingId].value + ' ' + propertiesById[thing.thingId].unit) : '') }}</p>
          </div>
        </div>
      </div>
      <section v-if="edit">
        <!-- fas fa-history fas fa-database -->
        <button v-on:click="onArchiveAll()"><i class="fas fa-history"></i>&nbsp;Archive All</button>
        <button v-on:click="onRemoveAll()"><i class="fa fa-trash"></i>&nbsp;Disable All</button>
      </section>
      <section v-else>
        <button v-if="app.canConfigure" v-on:click="app.toPage('addThings')"><i class="fa fa-plus"></i>&nbsp;Add</button>
      </section>
    </article>
  </app-page>
  <app-page id="thing" title="Thing">
    <template slot="bar-right">
      <button v-if="edit" v-on:click="onSave()" title="Apply"><i class="far fa-save"></i></button>
      <button v-on:click="refresh()" title="Refresh"><i class="fas fa-sync"></i></button>
      <button v-on:click="disableThing().then(function(){ app.back(); })" title="Disable"><i class="fa fa-trash"></i></button>
      <button v-on:click="toggleEdit()" title="Edit"><i :class="['fas', edit ? 'fa-eye' : 'fa-edit']"></i></button>
    </template>
    <article class="cards">
      <div class="card" v-if="edit">
        <p><span>Title</span> <input v-model="editThing.title" type="text" placeholder="Thing Title"></p>
        <p><span>Description</span> <input v-model="editThing.description" type="text" placeholder="Thing Description"></p>
      </div>
      <div class="card" v-else>
        <p>{{ thing.title }}</p>
        <p>{{ thing.description }}</p>
      </div>
      <div class="card" v-for="(property, name) in thing.properties">
        <div class="bar">
          <p>{{ property.title }}</p>
          <div>
            <div v-if="!edit || property.readOnly">
              <p v-if="name in properties"><b>{{ properties[name] }}</b>&nbsp;<span><i>{{ property.unit }}</i></span></p>
              <p v-else><i>No value</i></p>
            </div>
            <div v-else>
              <template v-if="property.type === 'string'">
                <select v-if="isArrayWithItems(property.enum)" v-model="editProps[name]">
                  <option v-for="ev in property.enum" :value="ev">{{ev}}</option>
                </select>
                <input v-else v-model="editProps[name]" type="text" placeholder="String Value">
              </template>
              <input v-if="(property.type === 'number') || (property.type === 'integer')" v-model="editProps[name]" number type="number" placeholder="Number Value">
              <label v-if="property.type === 'boolean'" class="switch"><input type="checkbox" v-model="editProps[name]"/><span class="slider"></span></label>
            </div>
          </div>
          <div>
            <!-- TODO also check thing.archiveData -->
            <button v-if="!property.configuration" v-on:click="openHistoricalData(name)"><i class="fas fa-chart-line"></i>&nbsp;History</button>
          </div>
        </div>
        <p>{{ property.description }}</p>
      </div>
      <section v-if="edit">
        <button v-on:click="onSave()"><i class="far fa-save"></i>&nbsp;Apply</button>
        <button v-on:click="toggleEdit()">Cancel</button>
      </section>
    </article>
  </app-page>
  <app-page id="addThings" title="Add Things">
    <template slot="bar-right">
      <button v-on:click="onSave().then(function(){ app.back(); })" title="Enable Selected Things"><i class="far fa-save"></i></button>
      <button v-on:click="onShow()" title="Refresh"><i class="fas fa-sync"></i></button>
      <button v-on:click="onSelectAll()" title="Select All"><i class="fas fa-check"></i></button>
    </template>
    <article class="cards">
      <div class="card" v-for="thing in things">
        <div class="bar">
          <p>{{ thing.title + (thing.extensionId in extensionsById ? (' (' + extensionsById[thing.extensionId].name + ')') : '') }}</p>
          <label class="switch" title="Enable"><input type="checkbox" v-model="thing.toAdd"/><span class="slider"></span></label>
        </div>
        <p>{{ thing.description }}</p>
      </div>
      <section>
        <button v-on:click="onSave().then(function(){ app.back(); })"><i class="fa fa-plus"></i>&nbsp;Enable Selected</button>
        <button v-on:click="app.back()">Cancel</button>
      </section>
    </article>
  </app-page>
  <!--
    extensions
  -->
  <app-page id="extensions" title="Extensions">
    <template slot="bar-right">
      <input v-if="filter" v-model="query" type="text" placeholder="Type to filter">
      <button v-on:click="toggleFilter(event)"><i class="fas fa-search"></i></button>
      <button v-if="app.canConfigure" v-on:click="app.toPage('addExtensions')" title="Add"><i class="fa fa-plus"></i></button>
    </template>
    <article class="cards">
      <div class="card" v-for="extension in filteredExtensions" v-if="extension.active">
        <div class="bar">
          <p>{{ extension.name }}</p>
          <div>
            <button v-on:click="app.toPage('extension-info', extension.id)"><i class="fas fa-info"></i>&nbsp;Infos</button>
            <button v-on:click="pollExtension(extension)"><i class="far fa-bell"></i>&nbsp;Poll</button>
            <button v-on:click="app.toPage('extension', extension.id)"><i class="fas fa-cog"></i>&nbsp;Settings</button>
          </div>
        </div>
        <p>{{ extension.description }}</p>
      </div>
      <section>
        <button v-if="app.canConfigure" v-on:click="app.toPage('addExtensions')"><i class="fa fa-plus"></i>&nbsp;Add</button>
      </section>
    </article>
  </app-page>
  <app-page id="extension" title="Extension">
    <template slot="bar-right">
      <button v-on:click="app.toPage('extension-info', extensionId)"><i class="fas fa-info"></i></button>
    </template>
    <article class="content">
      <section>
        <p>{{ info.name }}</p>
        <p>{{ info.description }}</p>
        <button v-on:click="onReload"><i class="fas fa-redo"></i>&nbsp;Reload</button>
        <button v-on:click="onRefreshThings"><i class="fas fa-recycle"></i>&nbsp;Refresh Things</button>
        <button v-on:click="onDisable().then(function(){ app.back(); })"><i class="fa fa-trash"></i>&nbsp;Disable</button>
      </section>
      <section v-if="actions.length > 0">
        <p>Action</p>
        <button v-for="(action, index) in actions" :title="action.description" v-on:click="triggerAction(index)">{{ action.name }}</button>
      </section>
      <section v-if="schema">
        <json name="Configuration" :obj="config" :schema="schema"></json>
        <button v-on:click="onSave()"><i class="far fa-save"></i>&nbsp;Save</button>
      </section>
    </article>
  </app-page>
  <app-page id="extension-info" title="Extension Info">
    <template slot="bar-right">
      <button v-on:click="app.back()" title="Close"><i class="fa fa-window-close"></i></button>
    </template>
    <page-article>
      <section>
        <p>{{ info.name }}</p>
        <p>{{ info.description }}</p>
        <p>Version: {{ info.version }}</p>
      </section>
      <hr v-if="readme"/>
      <div v-if="readme" v-html="readme">
      </div>
    </page-article>
  </app-page>
  <app-page id="addExtensions" title="Add Extensions">
    <article class="cards">
      <div class="card" v-for="extension in extensions" v-if="! extension.active">
        <div class="bar">
          <p>{{ extension.name }}</p>
          <div>
            <button v-on:click="app.toPage('extension-info', extension.id)"><i class="fas fa-info"></i>&nbsp;Infos</button>
            <button v-on:click="app.toPage('addExtension', extension.id)"><i class="fa fa-plus"></i>&nbsp;Add...</button>
          </div>
        </div>
        <p>{{ extension.description }}</p>
      </div>
      <section>
        <button v-on:click="app.back()">Cancel</button>
      </section>
    </article>
  </app-page>
  <app-page id="addExtension" title="Add Extension">
    <template slot="bar-right">
      <button v-on:click="app.toPage('extension-info', extensionId)"><i class="fas fa-info"></i></button>
    </template>
    <article class="content">
      <section v-if="actions.length > 0">
        <p>Action</p>
        <button v-for="(action, index) in actions" v-if="action.active === false && !action.arguments" :title="action.description" v-on:click="triggerAction(index)">{{ action.name }}</button>
      </section>
      <section>
        <p>{{ info.name }}</p>
        <p>{{ info.description }}</p>
        <json v-if="schema" name="Configuration" :obj="config" :schema="schema"></json>
      </section>
      <section>
        <button v-on:click="onAdd().then(function(){ app.back(); })"><i class="fa fa-plus"></i>&nbsp;Add Extension</button>
        <button v-on:click="app.back()">Cancel</button>
      </section>
    </article>
  </app-page>
  <!--
    Server Info
  -->
  <app-page id="engineInfo" title="Server Info">
    <template slot="bar-right">
      <button v-on:click="onShow()" title="Refresh"><i class="fas fa-sync"></i></button>
    </template>
    <page-article>
      <p>Information</p>
      <dl>
        <template v-for="(value, name) in infos">
          <dt><label>{{ name }}</label></dt>
          <dd><span>{{ value }}</span></dd>
        </template>
      </dl>
    </page-article>
  </app-page>
  <!--
    Engine Configuration
  -->
  <app-page id="engineSettings" title="Server Configuration" transition-class="hideTop">
    <template slot="bar-right">
      <button v-on:click="stopServer()" title="Stop the Server"><i class="fas fa-power-off"></i></button>
      <button v-on:click="app.toPage('engineInfo')" title="Server Information"><i class="fas fa-info"></i></button>
      <button v-on:click="app.back()" title="Close"><i class="fa fa-window-close"></i></button>
    </template>
    <article class="content">
      <section>
        <p>Backup and Restore</p>
        <button v-on:click="backup" :disabled="working"><i class="fas fa-box"></i>&nbsp;Create Backup</button>
        <a v-if="filename" :href="'/engine/tmp/' + filename" download>{{filename}}</a>
        <button v-on:click="selectFile" :disabled="working"><i class="fas fa-box-open"></i>&nbsp;Deploy Backup</button>
        <input v-on:change="uploadThenDeploy" type="file" accept=".zip" ref="uploadInput" style="display: none;"/>
        <button v-on:click="stopServer()" :disabled="working"><i class="fas fa-power-off"></i>&nbsp;Stop the Server</button>
      </section>
      <section>
        <json name="Configuration" :obj="config" :schema="schema"></json>
        <button v-on:click="onSave()"><i class="far fa-save"></i>&nbsp;Save</button>
      </section>
    </article>
  </app-page>
  <!--
    Main
  -->
  <app-page id="home" :title="title" hide-back="true">
    <template slot="bar-right">
      <button v-if="app.canAdminister" v-on:click="app.toPage('engineSettings')" title="Configuration"><i class="fas fa-cog"></i></button>
      <button v-on:click="nextTheme()" title="Next theme"><i class="fas fa-brush"></i></button>
      <button v-on:click="toggleFullScreen()" title="Fullscreen"><i class="fas fa-expand-alt"></i></button>
      <button v-on:click="app.hideMenu = !app.hideMenu" title="Hide Menu"><i class="fa fa-chevron-up"></i></button>
    </template>
    <article class="tiles">
      <div class="tile" v-for="tile in sortedTiles" v-on:click="onTile(tile)">
        <span>{{ tile.name }}</span>
        <p class="tile-value" v-if="tile.icon"><i :class="['fas', 'fa-' + tile.icon]"></i></p>
      </div>
    </article>
  </app-page>
</div>
<!-- Simple pages loaded automatically -->
<div id="pages" class="pages">
  <app-page id="first" title="First">
    <page-article>
      <p>First content</p>
    </page-article>
  </app-page>
</div>
<div id="app"></div>
</body>
<script type="text/x-template" id="json-item-template">
  <li class="json">
    <div v-if="!isOfSchema" class="hover-container">
      <span>
        <i v-if="hasContent" :class="['fa', open ? 'fa-chevron-down' : 'fa-chevron-right']" v-on:click.exact="toggle()" v-on:click.alt.exact="toggleAll()" title="Use the alt key to toggle all"></i>
        <select v-if="hasOfSchema" v-model="ofIndex" style="width: unset; border-color: lightgray;">
          <option v-for="(name, i) in ofSchemaLabels" :value="i">{{name}}</option>
        </select>
        <span v-else-if="schema.deprecated"><s>{{ label }}</s></span>
        <span v-else v-on:click.exact="toggle()">{{ label }}</span>
        <span class="required" v-if="schema.required" title="The value is required">*</span>
      </span>
      <span class="hover-visible" v-if="isListItem">
        <i class="fa fa-plus" v-on:click="insertItem" title="Insert"></i>
        <i class="fa fa-trash" v-on:click="removeItem" title="Remove"></i>
        <i class="fas fa-caret-up" v-if="canMove(-1)" v-on:click="moveItem(-1)" title="Move Up"></i>
        <i class="fas fa-caret-down" v-if="canMove(1)" v-on:click="moveItem(1)" title="Move Down"></i>
      </span>
    </div>
    <div v-if="typeof schema.description === 'string'" v-show="open">
      <i>{{ schema.description }}</i>
    </div>
    <json-item v-if="hasOfSchema" :schema="ofSchema" :key="ofKey" :name="name" :pobj="pobj" :obj="obj" :rootSchema="rootSchema" v-show="open"></json-item>
    <select v-else-if="hasEnumValues" v-model="value">
      <option v-for="ev in enumValues" :value="ev.const">{{ev.title}}</option>
    </select>
    <template v-else-if="schema.type === 'string'">
      <textarea v-if="schema.contentMediaType && schema.contentMediaType.startsWith('text/')" v-model="value" v-on:keydown.tab.prevent="insertTab"
        spellcheck="false" wrap="off" placeholder="Text Value" :readonly="schema.readOnly"></textarea>
      <input v-else v-model="value" :readonly="schema.readOnly" :type="schema.writeOnly ? 'password' : 'text'" placeholder="String Value">
    </template>
    <input v-else-if="schema.type === 'number' || schema.type === 'integer'" v-model="value" :readonly="schema.readOnly" type="number" placeholder="Number Value">
    <label v-else-if="schema.type === 'boolean'" class="switch big">
      <input type="checkbox" v-model="value"/>
      <span class="slider"></span>
    </label>
    <ul v-else-if="isProperties" class="json-properties" v-show="open">
      <li is="json-item" v-for="n in propertyNames" :key="n" :name="n" :pobj="obj" :obj="obj[n]" :schema="unrefSchema(rootSchema, schema.properties[n])" :rootSchema="rootSchema"></li>
      <!-- TODO hasAdditionalProperties -->
    </ul>
    <ul v-else-if="isList" class="json-items" v-show="open">
      <li v-if="hasList" is="json-item" v-for="(so, i) in obj" :key="i" :name="String(i + 1)" :pobj="obj" :obj="so" :schema="unrefSchema(rootSchema, getArraySchema(schema, i))" :rootSchema="rootSchema"></li>
      <li v-if="canAddItem">
        <button v-on:click="addItem" title="Add Item"><i class="fa fa-plus"></i>&nbsp;Add {{ label }} Item</button>
      </li>
    </ul>
    <span v-else>unsupported schema</span>
  </li>
</script>
<script type="text/x-template" id="json-template">
  <ul class="json-root">
    <json-item :name="name" :pobj="false" :obj="obj" :schema="unrefSchema(schema, schema)" :rootSchema="schema"></json-item>
  </ul>
</script>
<script type="text/x-template" id="dialog-template" tabindex="-1">
  <section v-bind:id="id" class="page dialog" v-bind:class="{ hide: app.dialog !== id }">
    <header>
      <div/>
      <h1>{{ title }}</h1>
      <div>
        <slot name="bar-right">
          <button v-on:click="app.dialog = ''"><i class="fa fa-window-close"></i></button>
        </slot>
      </div>
    </header>
    <slot>Article</slot>
  </section>
</script>
<script type="text/x-template" id="menu-template" tabindex="-1">
  <section v-bind:id="id" class="menu" v-bind:class="{ hideLeft: app.menu !== id }">
    <header>
      <div>
        <button v-on:click="app.menu = ''"><i class="fa fa-window-close"></i></button>
        <button v-on:click="app.toPage(homePage)" v-if="homePage && (app.page !== homePage)"><i class="fas fa-home"></i></button>
      </div>
      <h1>{{ title }}</h1><div/>
    </header>
    <slot>Article</slot>
  </section>
</script>
<script type="text/x-template" id="page-template">
  <section v-bind:id="id" v-bind:class="[{page: true, hideMenu: app.hideMenu}, app.page === id ? '' : transitionClass]" tabindex="-1">
    <header>
      <div>
        <slot name="bar-left">
          <button v-on:click="app.menu = menu" v-if="menu"><i class="fa fa-bars"></i></button>
          <button v-on:click="app.toPage(homePage)" v-if="homePage && (app.page !== homePage)"><i class="fas fa-home"></i></button>
        </slot>
      </div>
      <slot name="bar-middle">  
        <h1>{{ title }}</h1>
      </slot>
      <div>
        <slot name="bar-right"></slot>
        <template v-if="app.getPage('user')">
          <button v-on:click="app.toPage('user')" v-if="app.user && app.user.logged" :title="app.user.name"><i class="fa fa-user"></i></button>
          <button v-on:click="app.toPage('user')" v-else title="Not logged"><i class="fa fa-user-alt-slash"></i></button>
        </template>
      </div>
    </header>
    <div class="showMenu" v-if="app.hideMenu">
      <button v-on:click="app.hideMenu = false"><i class="fa fa-chevron-down"></i></button>
    </div>
    <slot>Article</slot>
  </section>
</script>
<script src="amdimpl.js" type="text/javascript" charset="utf-8"></script>
<script src="app/utils.js" type="text/javascript" charset="utf-8"></script>
<script src="app/app.js" type="text/javascript" charset="utf-8"></script>
<script src="app/json.js" type="text/javascript" charset="utf-8"></script>
<script src="app/extensions.js" type="text/javascript" charset="utf-8"></script>
<script src="app/things.js" type="text/javascript" charset="utf-8"></script>
<script src="app/properties.js" type="text/javascript" charset="utf-8"></script>
<script src="app/boot.js" type="text/javascript" charset="utf-8"></script>
</html>