webapp: introduced CardElement and replace cards with it

This commit is contained in:
Thomas Basler 2022-12-24 20:20:22 +01:00
parent 20083ecba5
commit 1677f7dd03
22 changed files with 850 additions and 895 deletions

View File

@ -0,0 +1,20 @@
<template>
<div :class="['card', addSpace ? 'mt-5' : '' ]">
<div :class="['card-header', textVariant]">{{ text }}</div>
<div :class="['card-body', centerContent ? 'text-center' : '']">
<slot />
</div>
</div>
</template>
<script lang="ts">
import {defineComponent} from 'vue';
export default defineComponent({
props: {
'text': String,
'textVariant': String,
'addSpace': Boolean,
'centerContent': Boolean,
},
});
</script>

View File

@ -1,69 +1,68 @@
<template> <template>
<div class="card"> <CardElement :text="$t('firmwareinfo.FirmwareInformation')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary"> <div class="table-responsive">
{{ $t('firmwareinfo.FirmwareInformation') }} <table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('firmwareinfo.Hostname') }}</th>
<td>{{ systemStatus.hostname }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.SdkVersion') }}</th>
<td>{{ systemStatus.sdkversion }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.ConfigVersion') }}</th>
<td>{{ systemStatus.config_version }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.FirmwareVersion') }}</th>
<td><a :href="'https://github.com/tbnobody/OpenDTU/commits/' + systemStatus.git_hash?.substring(1)"
target="_blank" v-tooltip :title="$t('firmwareinfo.FirmwareVersionHint')">
{{ systemStatus.git_hash?.substring(1) }}
</a></td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.FirmwareUpdate') }}</th>
<td><a :href="systemStatus.update_url" target="_blank" v-tooltip
:title="$t('firmwareinfo.FirmwareUpdateHint')">
<span class="badge" :class="systemStatus.update_status">
{{ systemStatus.update_text }}
</span>
</a></td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.ResetReason0') }}</th>
<td>{{ systemStatus.resetreason_0 }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.ResetReason1') }}</th>
<td>{{ systemStatus.resetreason_1 }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.ConfigSaveCount') }}</th>
<td>{{ systemStatus.cfgsavecount }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.Uptime') }}</th>
<td>{{ timeInHours(systemStatus.uptime) }}</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="card-body"> </CardElement>
<div class="table-responsive">
<table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('firmwareinfo.Hostname') }}</th>
<td>{{ systemStatus.hostname }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.SdkVersion') }}</th>
<td>{{ systemStatus.sdkversion }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.ConfigVersion') }}</th>
<td>{{ systemStatus.config_version }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.FirmwareVersion') }}</th>
<td><a :href="'https://github.com/tbnobody/OpenDTU/commits/' + systemStatus.git_hash?.substring(1)"
target="_blank" v-tooltip :title="$t('firmwareinfo.FirmwareVersionHint')">
{{ systemStatus.git_hash?.substring(1) }}
</a></td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.FirmwareUpdate') }}</th>
<td><a :href="systemStatus.update_url" target="_blank" v-tooltip
:title="$t('firmwareinfo.FirmwareUpdateHint')">
<span class="badge" :class="systemStatus.update_status">
{{ systemStatus.update_text }}
</span>
</a></td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.ResetReason0') }}</th>
<td>{{ systemStatus.resetreason_0 }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.ResetReason1') }}</th>
<td>{{ systemStatus.resetreason_1 }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.ConfigSaveCount') }}</th>
<td>{{ systemStatus.cfgsavecount }}</td>
</tr>
<tr>
<th>{{ $t('firmwareinfo.Uptime') }}</th>
<td>{{ timeInHours(systemStatus.uptime) }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, type PropType } from 'vue'; import { defineComponent, type PropType } from 'vue';
import type { SystemStatus } from '@/types/SystemStatus'; import type { SystemStatus } from '@/types/SystemStatus';
import { timestampToString } from '@/utils'; import { timestampToString } from '@/utils';
import CardElement from '@/components/CardElement.vue';
export default defineComponent({ export default defineComponent({
components: {
CardElement,
},
props: { props: {
systemStatus: { type: Object as PropType<SystemStatus>, required: true }, systemStatus: { type: Object as PropType<SystemStatus>, required: true },
}, },

View File

@ -1,40 +1,39 @@
<template> <template>
<div class="card"> <CardElement :text="$t('hardwareinfo.HardwareInformation')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary"> <div class="table-responsive">
{{ $t('hardwareinfo.HardwareInformation') }} <table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('hardwareinfo.ChipModel') }}</th>
<td>{{ systemStatus.chipmodel }}</td>
</tr>
<tr>
<th>{{ $t('hardwareinfo.ChipRevision') }}</th>
<td>{{ systemStatus.chiprevision }}</td>
</tr>
<tr>
<th>{{ $t('hardwareinfo.ChipCores') }}</th>
<td>{{ systemStatus.chipcores }}</td>
</tr>
<tr>
<th>{{ $t('hardwareinfo.CpuFrequency') }}</th>
<td>{{ systemStatus.cpufreq }} {{ $t('hardwareinfo.Mhz') }}</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="card-body"> </CardElement>
<div class="table-responsive">
<table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('hardwareinfo.ChipModel') }}</th>
<td>{{ systemStatus.chipmodel }}</td>
</tr>
<tr>
<th>{{ $t('hardwareinfo.ChipRevision') }}</th>
<td>{{ systemStatus.chiprevision }}</td>
</tr>
<tr>
<th>{{ $t('hardwareinfo.ChipCores') }}</th>
<td>{{ systemStatus.chipcores }}</td>
</tr>
<tr>
<th>{{ $t('hardwareinfo.CpuFrequency') }}</th>
<td>{{ systemStatus.cpufreq }} {{ $t('hardwareinfo.Mhz') }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import type { SystemStatus } from '@/types/SystemStatus'; import type { SystemStatus } from '@/types/SystemStatus';
import { defineComponent, type PropType } from 'vue'; import { defineComponent, type PropType } from 'vue';
import CardElement from '@/components/CardElement.vue';
export default defineComponent({ export default defineComponent({
components: {
CardElement,
},
props: { props: {
systemStatus: { type: Object as PropType<SystemStatus>, required: true }, systemStatus: { type: Object as PropType<SystemStatus>, required: true },
}, },

View File

@ -1,32 +1,31 @@
<template> <template>
<div class="card"> <CardElement :text="$t('interfaceapinfo.NetworkInterface')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary"> <div class="table-responsive">
{{ $t('interfaceapinfo.NetworkInterface') }} <table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('interfaceapinfo.IpAddress') }}</th>
<td>{{ networkStatus.ap_ip }}</td>
</tr>
<tr>
<th>{{ $t('interfaceapinfo.MacAddress') }}</th>
<td>{{ networkStatus.ap_mac }}</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="card-body"> </CardElement>
<div class="table-responsive">
<table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('interfaceapinfo.IpAddress') }}</th>
<td>{{ networkStatus.ap_ip }}</td>
</tr>
<tr>
<th>{{ $t('interfaceapinfo.MacAddress') }}</th>
<td>{{ networkStatus.ap_mac }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import type { NetworkStatus } from '@/types/NetworkStatus'; import type { NetworkStatus } from '@/types/NetworkStatus';
import { defineComponent, type PropType } from 'vue'; import { defineComponent, type PropType } from 'vue';
import CardElement from '@/components/CardElement.vue';
export default defineComponent({ export default defineComponent({
components: {
CardElement,
},
props: { props: {
networkStatus: { type: Object as PropType<NetworkStatus>, required: true }, networkStatus: { type: Object as PropType<NetworkStatus>, required: true },
}, },

View File

@ -1,52 +1,53 @@
<template> <template>
<div class="card"> <CardElement :text="$t('interfacenetworkinfo.NetworkInterface', { iface: networkStatus.network_mode })"
<div class="card-header text-bg-primary"> textVariant="text-bg-primary"
{{ $t('interfacenetworkinfo.NetworkInterface', { iface: networkStatus.network_mode }) }} >
<div class="table-responsive">
<table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('interfacenetworkinfo.Hostname') }}</th>
<td>{{ networkStatus.network_hostname }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.IpAddress') }}</th>
<td>{{ networkStatus.network_ip }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.Netmask') }}</th>
<td>{{ networkStatus.network_netmask }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.DefaultGateway') }}</th>
<td>{{ networkStatus.network_gateway }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.Dns', { num: 1 }) }}</th>
<td>{{ networkStatus.network_dns1 }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.Dns', { num: 2 }) }}</th>
<td>{{ networkStatus.network_dns2 }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.MacAddress') }}</th>
<td>{{ networkStatus.network_mac }}</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="card-body"> </CardElement>
<div class="table-responsive">
<table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('interfacenetworkinfo.Hostname') }}</th>
<td>{{ networkStatus.network_hostname }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.IpAddress') }}</th>
<td>{{ networkStatus.network_ip }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.Netmask') }}</th>
<td>{{ networkStatus.network_netmask }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.DefaultGateway') }}</th>
<td>{{ networkStatus.network_gateway }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.Dns', { num: 1 }) }}</th>
<td>{{ networkStatus.network_dns1 }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.Dns', { num: 2 }) }}</th>
<td>{{ networkStatus.network_dns2 }}</td>
</tr>
<tr>
<th>{{ $t('interfacenetworkinfo.MacAddress') }}</th>
<td>{{ networkStatus.network_mac }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import type { NetworkStatus } from '@/types/NetworkStatus'; import type { NetworkStatus } from '@/types/NetworkStatus';
import { defineComponent, type PropType } from 'vue'; import { defineComponent, type PropType } from 'vue';
import CardElement from '@/components/CardElement.vue';
export default defineComponent({ export default defineComponent({
components: {
CardElement,
},
props: { props: {
networkStatus: { type: Object as PropType<NetworkStatus>, required: true }, networkStatus: { type: Object as PropType<NetworkStatus>, required: true },
}, },

View File

@ -1,39 +1,38 @@
<template> <template>
<div class="card"> <CardElement :text="$t('memoryinfo.MemoryInformation')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('memoryinfo.MemoryInformation') }}</div> <div class="table-responsive">
<div class="card-body"> <table class="table table-hover table-condensed">
<div class="table-responsive"> <thead>
<table class="table table-hover table-condensed"> <tr>
<thead> <th>{{ $t('memoryinfo.Type') }}</th>
<tr> <th>{{ $t('memoryinfo.Usage') }}</th>
<th>{{ $t('memoryinfo.Type') }}</th> <th class="rightCell">{{ $t('memoryinfo.Free') }}</th>
<th>{{ $t('memoryinfo.Usage') }}</th> <th class="rightCell">{{ $t('memoryinfo.Used') }}</th>
<th class="rightCell">{{ $t('memoryinfo.Free') }}</th> <th class="rightCell">{{ $t('memoryinfo.Size') }}</th>
<th class="rightCell">{{ $t('memoryinfo.Used') }}</th> </tr>
<th class="rightCell">{{ $t('memoryinfo.Size') }}</th> </thead>
</tr> <tbody>
</thead> <FsInfo :name="$t('memoryinfo.Heap')" :total="systemStatus.heap_total"
<tbody> :used="systemStatus.heap_used" />
<FsInfo :name="$t('memoryinfo.Heap')" :total="systemStatus.heap_total" <FsInfo :name="$t('memoryinfo.LittleFs')" :total="systemStatus.littlefs_total"
:used="systemStatus.heap_used" /> :used="systemStatus.littlefs_used" />
<FsInfo :name="$t('memoryinfo.LittleFs')" :total="systemStatus.littlefs_total" <FsInfo :name="$t('memoryinfo.Sketch')" :total="systemStatus.sketch_total"
:used="systemStatus.littlefs_used" /> :used="systemStatus.sketch_used" />
<FsInfo :name="$t('memoryinfo.Sketch')" :total="systemStatus.sketch_total" </tbody>
:used="systemStatus.sketch_used" /> </table>
</tbody>
</table>
</div>
</div> </div>
</div> </CardElement>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, type PropType } from 'vue'; import { defineComponent, type PropType } from 'vue';
import type { SystemStatus } from '@/types/SystemStatus'; import type { SystemStatus } from '@/types/SystemStatus';
import CardElement from '@/components/CardElement.vue';
import FsInfo from "@/components/FsInfo.vue"; import FsInfo from "@/components/FsInfo.vue";
export default defineComponent({ export default defineComponent({
components: { components: {
CardElement,
FsInfo, FsInfo,
}, },
props: { props: {

View File

@ -1,48 +1,47 @@
<template> <template>
<div class="card"> <CardElement :text="$t('radioinfo.RadioInformation')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary"> <div class="table-responsive">
{{ $t('radioinfo.RadioInformation') }} <table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('radioinfo.ChipStatus') }}</th>
<td class="badge" :class="{
'text-bg-danger': !systemStatus.radio_connected,
'text-bg-success': systemStatus.radio_connected,
}">
<span v-if="systemStatus.radio_connected">{{ $t('radioinfo.Connected') }}</span>
<span v-else>{{ $t('radioinfo.NotConnected') }}</span>
</td>
</tr>
<tr>
<th>{{ $t('radioinfo.ChipType') }}</th>
<td class="badge" :class="{
'text-bg-danger': systemStatus.radio_connected && !systemStatus.radio_pvariant,
'text-bg-success': systemStatus.radio_connected && systemStatus.radio_pvariant,
'text-bg-secondary': !systemStatus.radio_connected,
}">
<span
v-if="systemStatus.radio_connected && systemStatus.radio_pvariant">nRF24L01+</span>
<span
v-else-if="systemStatus.radio_connected && !systemStatus.radio_pvariant">nRF24L01</span>
<span v-else>{{ $t('radioinfo.Unknown') }}</span>
</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="card-body"> </CardElement>
<div class="table-responsive">
<table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('radioinfo.ChipStatus') }}</th>
<td class="badge" :class="{
'text-bg-danger': !systemStatus.radio_connected,
'text-bg-success': systemStatus.radio_connected,
}">
<span v-if="systemStatus.radio_connected">{{ $t('radioinfo.Connected') }}</span>
<span v-else>{{ $t('radioinfo.NotConnected') }}</span>
</td>
</tr>
<tr>
<th>{{ $t('radioinfo.ChipType') }}</th>
<td class="badge" :class="{
'text-bg-danger': systemStatus.radio_connected && !systemStatus.radio_pvariant,
'text-bg-success': systemStatus.radio_connected && systemStatus.radio_pvariant,
'text-bg-secondary': !systemStatus.radio_connected,
}">
<span
v-if="systemStatus.radio_connected && systemStatus.radio_pvariant">nRF24L01+</span>
<span
v-else-if="systemStatus.radio_connected && !systemStatus.radio_pvariant">nRF24L01</span>
<span v-else>{{ $t('radioinfo.Unknown') }}</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, type PropType } from 'vue'; import { defineComponent, type PropType } from 'vue';
import type { SystemStatus } from '@/types/SystemStatus'; import type { SystemStatus } from '@/types/SystemStatus';
import CardElement from '@/components/CardElement.vue';
export default defineComponent({ export default defineComponent({
components: {
CardElement,
},
props: { props: {
systemStatus: { type: Object as PropType<SystemStatus>, required: true }, systemStatus: { type: Object as PropType<SystemStatus>, required: true },
}, },

View File

@ -1,42 +1,41 @@
<template> <template>
<div class="card"> <CardElement :text="$t('wifiapinfo.WifiApInfo')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary"> <div class="table-responsive">
{{ $t('wifiapinfo.WifiApInfo') }} <table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('wifiapinfo.Status') }}</th>
<td class="badge" :class="{
'text-bg-danger': !networkStatus.ap_status,
'text-bg-success': networkStatus.ap_status,
}">
<span v-if="networkStatus.ap_status">{{ $t('wifiapinfo.Enabled') }}</span>
<span v-else>{{ $t('wifiapinfo.Disabled') }}</span>
</td>
</tr>
<tr>
<th>{{ $t('wifiapinfo.Ssid') }}</th>
<td>{{ networkStatus.ap_ssid }}</td>
</tr>
<tr>
<th>{{ $t('wifiapinfo.Stations') }}</th>
<td>{{ networkStatus.ap_stationnum }}</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="card-body"> </CardElement>
<div class="table-responsive">
<table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('wifiapinfo.Status') }}</th>
<td class="badge" :class="{
'text-bg-danger': !networkStatus.ap_status,
'text-bg-success': networkStatus.ap_status,
}">
<span v-if="networkStatus.ap_status">{{ $t('wifiapinfo.Enabled') }}</span>
<span v-else>{{ $t('wifiapinfo.Disabled') }}</span>
</td>
</tr>
<tr>
<th>{{ $t('wifiapinfo.Ssid') }}</th>
<td>{{ networkStatus.ap_ssid }}</td>
</tr>
<tr>
<th>{{ $t('wifiapinfo.Stations') }}</th>
<td>{{ networkStatus.ap_stationnum }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import type { NetworkStatus } from '@/types/NetworkStatus'; import type { NetworkStatus } from '@/types/NetworkStatus';
import { defineComponent, type PropType } from 'vue'; import { defineComponent, type PropType } from 'vue';
import CardElement from '@/components/CardElement.vue';
export default defineComponent({ export default defineComponent({
components: {
CardElement,
},
props: { props: {
networkStatus: { type: Object as PropType<NetworkStatus>, required: true }, networkStatus: { type: Object as PropType<NetworkStatus>, required: true },
}, },

View File

@ -1,46 +1,45 @@
<template> <template>
<div class="card"> <CardElement :text="$t('wifistationinfo.WifiStationInfo')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary"> <div class="table-responsive">
{{ $t('wifistationinfo.WifiStationInfo') }} <table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('wifistationinfo.Status') }}</th>
<td class="badge" :class="{
'text-bg-danger': !networkStatus.sta_status,
'text-bg-success': networkStatus.sta_status,
}">
<span v-if="networkStatus.sta_status">{{ $t('wifistationinfo.Enabled') }}</span>
<span v-else>{{ $t('wifistationinfo.Disabled') }}</span>
</td>
</tr>
<tr>
<th>{{ $t('wifistationinfo.Ssid') }}</th>
<td>{{ networkStatus.sta_ssid }}</td>
</tr>
<tr>
<th>{{ $t('wifistationinfo.Quality') }}</th>
<td>{{ getRSSIasQuality(networkStatus.sta_rssi) }} %</td>
</tr>
<tr>
<th>{{ $t('wifistationinfo.Rssi') }}</th>
<td>{{ networkStatus.sta_rssi }}</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="card-body"> </CardElement>
<div class="table-responsive">
<table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('wifistationinfo.Status') }}</th>
<td class="badge" :class="{
'text-bg-danger': !networkStatus.sta_status,
'text-bg-success': networkStatus.sta_status,
}">
<span v-if="networkStatus.sta_status">{{ $t('wifistationinfo.Enabled') }}</span>
<span v-else>{{ $t('wifistationinfo.Disabled') }}</span>
</td>
</tr>
<tr>
<th>{{ $t('wifistationinfo.Ssid') }}</th>
<td>{{ networkStatus.sta_ssid }}</td>
</tr>
<tr>
<th>{{ $t('wifistationinfo.Quality') }}</th>
<td>{{ getRSSIasQuality(networkStatus.sta_rssi) }} %</td>
</tr>
<tr>
<th>{{ $t('wifistationinfo.Rssi') }}</th>
<td>{{ networkStatus.sta_rssi }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import type { NetworkStatus } from '@/types/NetworkStatus'; import type { NetworkStatus } from '@/types/NetworkStatus';
import { defineComponent, type PropType } from 'vue'; import { defineComponent, type PropType } from 'vue';
import CardElement from '@/components/CardElement.vue';
export default defineComponent({ export default defineComponent({
components: {
CardElement,
},
props: { props: {
networkStatus: { type: Object as PropType<NetworkStatus>, required: true }, networkStatus: { type: Object as PropType<NetworkStatus>, required: true },
}, },

View File

@ -4,74 +4,63 @@
{{ alertMessage }} {{ alertMessage }}
</BootstrapAlert> </BootstrapAlert>
<div class="card"> <CardElement :text="$t('configadmin.BackupHeader')" textVariant="text-bg-primary" center-content>
<div class="card-header text-bg-primary">{{ $t('configadmin.BackupHeader') }}</div> {{ $t('configadmin.BackupConfig') }}
<div class="card-body text-center"> <button class="btn btn-primary" @click="downloadConfig">{{ $t('configadmin.Backup') }}
{{ $t('configadmin.BackupConfig') }} </button>
<button class="btn btn-primary" @click="downloadConfig">{{ $t('configadmin.Backup') }} </CardElement>
<CardElement :text="$t('configadmin.RestoreHeader')" textVariant="text-bg-primary" center-content add-space>
<div v-if="!uploading && UploadError != ''">
<p class="h1 mb-2">
<BIconExclamationCircleFill />
</p>
<span style="vertical-align: middle" class="ml-2">
{{ UploadError }}
</span>
<br />
<br />
<button class="btn btn-light" @click="clear">
<BIconArrowLeft /> {{ $t('configadmin.Back') }}
</button> </button>
</div> </div>
</div>
<div class="card mt-5"> <div v-else-if="!uploading && UploadSuccess">
<div class="card-header text-bg-primary">{{ $t('configadmin.RestoreHeader') }}</div> <span class="h1 mb-2">
<div class="card-body text-center"> <BIconCheckCircle />
</span>
<div v-if="!uploading && UploadError != ''"> <span> {{ $t('configadmin.UploadSuccess') }} </span>
<p class="h1 mb-2"> <br />
<BIconExclamationCircleFill /> <br />
</p> <button class="btn btn-primary" @click="clear">
<span style="vertical-align: middle" class="ml-2"> <BIconArrowLeft /> {{ $t('configadmin.Back') }}
{{ UploadError }}
</span>
<br />
<br />
<button class="btn btn-light" @click="clear">
<BIconArrowLeft /> {{ $t('configadmin.Back') }}
</button>
</div>
<div v-else-if="!uploading && UploadSuccess">
<span class="h1 mb-2">
<BIconCheckCircle />
</span>
<span> {{ $t('configadmin.UploadSuccess') }} </span>
<br />
<br />
<button class="btn btn-primary" @click="clear">
<BIconArrowLeft /> {{ $t('configadmin.Back') }}
</button>
</div>
<div v-else-if="!uploading">
<div class="form-group pt-2 mt-3">
<input class="form-control" type="file" ref="file" accept=".json" @change="uploadConfig" />
</div>
</div>
<div v-else-if="uploading">
<div class="progress">
<div class="progress-bar" role="progressbar" :style="{ width: progress + '%' }"
v-bind:aria-valuenow="progress" aria-valuemin="0" aria-valuemax="100">
{{ progress }}%
</div>
</div>
</div>
<div class="alert alert-danger mt-3" role="alert" v-html="$t('configadmin.RestoreHint')"></div>
</div>
</div>
<div class="card mt-5">
<div class="card-header text-bg-primary">{{ $t('configadmin.ResetHeader') }}</div>
<div class="card-body text-center">
<button class="btn btn-danger" @click="onFactoryResetModal">{{ $t('configadmin.FactoryResetButton') }}
</button> </button>
<div class="alert alert-danger mt-3" role="alert" v-html="$t('configadmin.ResetHint')"></div>
</div> </div>
</div>
<div v-else-if="!uploading">
<div class="form-group pt-2 mt-3">
<input class="form-control" type="file" ref="file" accept=".json" @change="uploadConfig" />
</div>
</div>
<div v-else-if="uploading">
<div class="progress">
<div class="progress-bar" role="progressbar" :style="{ width: progress + '%' }"
v-bind:aria-valuenow="progress" aria-valuemin="0" aria-valuemax="100">
{{ progress }}%
</div>
</div>
</div>
<div class="alert alert-danger mt-3" role="alert" v-html="$t('configadmin.RestoreHint')"></div>
</CardElement>
<CardElement :text="$t('configadmin.ResetHeader')" textVariant="text-bg-primary" center-content add-space>
<button class="btn btn-danger" @click="onFactoryResetModal">{{ $t('configadmin.FactoryResetButton') }}
</button>
<div class="alert alert-danger mt-3" role="alert" v-html="$t('configadmin.ResetHint')"></div>
</CardElement>
</BasePage> </BasePage>
<div class="modal" id="factoryReset" tabindex="-1"> <div class="modal" id="factoryReset" tabindex="-1">
@ -106,6 +95,7 @@ import {
} from 'bootstrap-icons-vue'; } from 'bootstrap-icons-vue';
import * as bootstrap from 'bootstrap'; import * as bootstrap from 'bootstrap';
import BootstrapAlert from "@/components/BootstrapAlert.vue"; import BootstrapAlert from "@/components/BootstrapAlert.vue";
import CardElement from '@/components/CardElement.vue';
import { handleResponse, authHeader, isLoggedIn } from '@/utils/authentication'; import { handleResponse, authHeader, isLoggedIn } from '@/utils/authentication';
export default defineComponent({ export default defineComponent({
@ -115,6 +105,7 @@ export default defineComponent({
BIconArrowLeft, BIconArrowLeft,
BIconCheckCircle, BIconCheckCircle,
BootstrapAlert, BootstrapAlert,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -1,41 +1,40 @@
<template> <template>
<BasePage :title="$t('console.Console')" :isLoading="dataLoading"> <BasePage :title="$t('console.Console')" :isLoading="dataLoading">
<div class="card"> <CardElement :text="$t('console.VirtualDebugConsole')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('console.VirtualDebugConsole') }}</div> <div class="row g-3 align-items-center">
<div class="card-body"> <div class="col">
<div class="row g-3 align-items-center"> <div class="form-check form-switch">
<div class="col"> <input class="form-check-input" type="checkbox" role="switch" id="autoScroll"
<div class="form-check form-switch"> v-model="isAutoScroll">
<input class="form-check-input" type="checkbox" role="switch" id="autoScroll" <label class="form-check-label" for="autoScroll">
v-model="isAutoScroll"> {{ $t('console.EnableAutoScroll') }}
<label class="form-check-label" for="autoScroll"> </label>
{{ $t('console.EnableAutoScroll') }} </div>
</label> </div>
</div> <div class="col text-end">
</div> <div class="btn-group" role="group">
<div class="col text-end"> <button type="button" class="btn btn-primary" :onClick="clearConsole">
<div class="btn-group" role="group"> {{ $t('console.ClearConsole') }}</button>
<button type="button" class="btn btn-primary" :onClick="clearConsole"> <button type="button" class="btn btn-secondary" :onClick="copyConsole">
{{ $t('console.ClearConsole') }}</button> {{ $t('console.CopyToClipboard') }}</button>
<button type="button" class="btn btn-secondary" :onClick="copyConsole">
{{ $t('console.CopyToClipboard') }}</button>
</div>
</div> </div>
</div> </div>
<textarea id="console" class="form-control" rows="24" v-model="consoleBuffer" readonly></textarea>
</div> </div>
</div> <textarea id="console" class="form-control" rows="24" v-model="consoleBuffer" readonly></textarea>
</CardElement>
</BasePage> </BasePage>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import CardElement from '@/components/CardElement.vue';
import { authUrl } from '@/utils/authentication'; import { authUrl } from '@/utils/authentication';
export default defineComponent({ export default defineComponent({
components: { components: {
BasePage, BasePage,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -5,35 +5,31 @@
</BootstrapAlert> </BootstrapAlert>
<form @submit="saveDtuConfig"> <form @submit="saveDtuConfig">
<div class="card"> <CardElement :text="$t('dtuadmin.DtuConfiguration')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('dtuadmin.DtuConfiguration') }}</div> <InputElement :label="$t('dtuadmin.Serial')"
<div class="card-body"> v-model="dtuConfigList.dtu_serial"
type="number" min="1" max="199999999999"
:tooltip="$t('dtuadmin.SerialHint')"/>
<InputElement :label="$t('dtuadmin.Serial')" <InputElement :label="$t('dtuadmin.PollInterval')"
v-model="dtuConfigList.dtu_serial" v-model="dtuConfigList.dtu_pollinterval"
type="number" min="1" max="199999999999" type="number" min="1" max="86400"
:tooltip="$t('dtuadmin.SerialHint')"/> :postfix="$t('dtuadmin.Seconds')"/>
<InputElement :label="$t('dtuadmin.PollInterval')" <div class="row mb-3">
v-model="dtuConfigList.dtu_pollinterval" <label for="inputTimezone" class="col-sm-2 col-form-label">
type="number" min="1" max="86400" {{ $t('dtuadmin.PaLevel') }}
:postfix="$t('dtuadmin.Seconds')"/> <BIconInfoCircle v-tooltip :title="$t('dtuadmin.PaLevelHint')" />
</label>
<div class="row mb-3"> <div class="col-sm-10">
<label for="inputTimezone" class="col-sm-2 col-form-label"> <select class="form-select" v-model="dtuConfigList.dtu_palevel">
{{ $t('dtuadmin.PaLevel') }} <option v-for="palevel in palevelList" :key="palevel.key" :value="palevel.key">
<BIconInfoCircle v-tooltip :title="$t('dtuadmin.PaLevelHint')" /> {{ palevel.value }}
</label> </option>
<div class="col-sm-10"> </select>
<select class="form-select" v-model="dtuConfigList.dtu_palevel">
<option v-for="palevel in palevelList" :key="palevel.key" :value="palevel.key">
{{ palevel.value }}
</option>
</select>
</div>
</div> </div>
</div> </div>
</div> </CardElement>
<button type="submit" class="btn btn-primary mb-3">{{ $t('dtuadmin.Save') }}</button> <button type="submit" class="btn btn-primary mb-3">{{ $t('dtuadmin.Save') }}</button>
</form> </form>
</BasePage> </BasePage>
@ -44,6 +40,7 @@ import { defineComponent } from 'vue';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import BootstrapAlert from "@/components/BootstrapAlert.vue"; import BootstrapAlert from "@/components/BootstrapAlert.vue";
import InputElement from '@/components/InputElement.vue'; import InputElement from '@/components/InputElement.vue';
import CardElement from '@/components/CardElement.vue';
import { handleResponse, authHeader } from '@/utils/authentication'; import { handleResponse, authHeader } from '@/utils/authentication';
import type { DtuConfig } from "@/types/DtuConfig"; import type { DtuConfig } from "@/types/DtuConfig";
import { import {
@ -56,6 +53,7 @@ export default defineComponent({
BootstrapAlert, BootstrapAlert,
BIconInfoCircle, BIconInfoCircle,
InputElement, InputElement,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -8,68 +8,66 @@
</div> </div>
</div> </div>
<div v-if="!loading && !uploading && OTAError != ''" class="card"> <CardElement :text="$t('firmwareupgrade.OtaError')" textVariant="text-bg-danger" center-content
<div class="card-header text-bg-danger">{{ $t('firmwareupgrade.OtaError') }}</div> v-if="!loading && !uploading && OTAError != ''"
<div class="card-body text-center"> >
<p class="h1 mb-2"> <p class="h1 mb-2">
<BIconExclamationCircleFill /> <BIconExclamationCircleFill />
</p> </p>
<span style="vertical-align: middle" class="ml-2"> <span style="vertical-align: middle" class="ml-2">
{{ OTAError }} {{ OTAError }}
</span> </span>
<br /> <br />
<br /> <br />
<button class="btn btn-light" @click="clear"> <button class="btn btn-light" @click="clear">
<BIconArrowLeft /> {{ $t('firmwareupgrade.Back') }} <BIconArrowLeft /> {{ $t('firmwareupgrade.Back') }}
</button> </button>
<button class="btn btn-primary" @click="retryOTA"> <button class="btn btn-primary" @click="retryOTA">
<BIconArrowRepeat /> {{ $t('firmwareupgrade.Retry') }} <BIconArrowRepeat /> {{ $t('firmwareupgrade.Retry') }}
</button> </button>
</CardElement>
<CardElement :text="$t('firmwareupgrade.OtaStatus')" textVariant="text-bg-success" center-content
v-else-if="!loading && !uploading && OTASuccess"
>
<span class="h1 mb-2">
<BIconCheckCircle />
</span>
<span> {{ $t('firmwareupgrade.OtaSuccess') }} </span>
<br />
<br />
<button class="btn btn-primary" @click="clear">
<BIconArrowLeft /> {{ $t('firmwareupgrade.Back') }}
</button>
</CardElement>
<CardElement :text="$t('firmwareupgrade.FirmwareUpload')" textVariant="text-bg-primary" center-content
v-else-if="!loading && !uploading"
>
<div class="form-group pt-2 mt-3">
<input class="form-control" type="file" ref="file" accept=".bin,.bin.gz" @change="uploadOTA" />
</div> </div>
</div> </CardElement>
<div v-else-if="!loading && !uploading && OTASuccess" class="card"> <CardElement :text="$t('firmwareupgrade.UploadProgress')" textVariant="text-bg-primary" center-content
<div class="card-header text-bg-success">{{ $t('firmwareupgrade.OtaStatus') }}</div> v-else-if="!loading && uploading"
<div class="card-body text-center"> >
<span class="h1 mb-2"> <div class="progress">
<BIconCheckCircle /> <div class="progress-bar" role="progressbar" :style="{ width: progress + '%' }"
</span> v-bind:aria-valuenow="progress" aria-valuemin="0" aria-valuemax="100">
<span> {{ $t('firmwareupgrade.OtaSuccess') }} </span> {{ progress }}%
<br />
<br />
<button class="btn btn-primary" @click="clear">
<BIconArrowLeft /> {{ $t('firmwareupgrade.Back') }}
</button>
</div>
</div>
<div v-else-if="!loading && !uploading" class="card">
<div class="card-header text-bg-primary">{{ $t('firmwareupgrade.FirmwareUpload') }}</div>
<div class="card-body text-center">
<div class="form-group pt-2 mt-3">
<input class="form-control" type="file" ref="file" accept=".bin,.bin.gz" @change="uploadOTA" />
</div> </div>
</div> </div>
</div> </CardElement>
<div v-else-if="!loading && uploading" class="card">
<div class="card-header text-bg-primary">{{ $t('firmwareupgrade.UploadProgress') }}</div>
<div class="card-body text-center">
<div class="progress">
<div class="progress-bar" role="progressbar" :style="{ width: progress + '%' }"
v-bind:aria-valuenow="progress" aria-valuemin="0" aria-valuemax="100">
{{ progress }}%
</div>
</div>
</div>
</div>
</BasePage> </BasePage>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import CardElement from '@/components/CardElement.vue';
import SparkMD5 from "spark-md5"; import SparkMD5 from "spark-md5";
import { import {
BIconExclamationCircleFill, BIconExclamationCircleFill,
@ -82,6 +80,7 @@ import { authHeader, isLoggedIn } from '@/utils/authentication';
export default defineComponent({ export default defineComponent({
components: { components: {
BasePage, BasePage,
CardElement,
BIconExclamationCircleFill, BIconExclamationCircleFill,
BIconArrowLeft, BIconArrowLeft,
BIconArrowRepeat, BIconArrowRepeat,

View File

@ -4,60 +4,54 @@
{{ alert.message }} {{ alert.message }}
</BootstrapAlert> </BootstrapAlert>
<div class="card"> <CardElement :text="$t('inverteradmin.AddInverter')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('inverteradmin.AddInverter') }}</div> <form class="form-inline" v-on:submit.prevent="onSubmit">
<div class="card-body"> <div class="form-group">
<form class="form-inline" v-on:submit.prevent="onSubmit"> <label>{{ $t('inverteradmin.Serial') }}</label>
<div class="form-group"> <input v-model="newInverterData.serial" type="number" class="form-control ml-sm-2 mr-sm-4 my-2"
<label>{{ $t('inverteradmin.Serial') }}</label> required />
<input v-model="newInverterData.serial" type="number" class="form-control ml-sm-2 mr-sm-4 my-2"
required />
</div>
<div class="form-group">
<label>{{ $t('inverteradmin.Name') }}</label>
<input v-model="newInverterData.name" type="text" class="form-control ml-sm-2 mr-sm-4 my-2"
maxlength="31" required />
</div>
<div class="ml-auto text-right">
<button type="submit" class="btn btn-primary my-2">{{ $t('inverteradmin.Add') }}</button>
</div>
<div class="alert alert-secondary" role="alert" v-html="$t('inverteradmin.AddHint')"></div>
</form>
</div>
</div>
<div class="card mt-5">
<div class="card-header text-bg-primary">{{ $t('inverteradmin.InverterList') }}</div>
<div class="card-body">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">{{ $t('inverteradmin.Serial') }}</th>
<th>{{ $t('inverteradmin.Name') }}</th>
<th>{{ $t('inverteradmin.Type') }}</th>
<th>{{ $t('inverteradmin.Action') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="inverter in sortedInverters" v-bind:key="inverter.id">
<td>{{ inverter.serial }}</td>
<td>{{ inverter.name }}</td>
<td>{{ inverter.type }}</td>
<td>
<a href="#" class="icon text-danger" :title="$t('inverteradmin.DeleteInverter')">
<BIconTrash v-on:click="onOpenModal(modalDelete, inverter)" />
</a>&nbsp;
<a href="#" class="icon" :title="$t('inverteradmin.EditInverter')">
<BIconPencil v-on:click="onOpenModal(modal, inverter)" />
</a>
</td>
</tr>
</tbody>
</table>
</div> </div>
<div class="form-group">
<label>{{ $t('inverteradmin.Name') }}</label>
<input v-model="newInverterData.name" type="text" class="form-control ml-sm-2 mr-sm-4 my-2"
maxlength="31" required />
</div>
<div class="ml-auto text-right">
<button type="submit" class="btn btn-primary my-2">{{ $t('inverteradmin.Add') }}</button>
</div>
<div class="alert alert-secondary" role="alert" v-html="$t('inverteradmin.AddHint')"></div>
</form>
</CardElement>
<CardElement :text="$t('inverteradmin.InverterList')" textVariant="text-bg-primary" add-space>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">{{ $t('inverteradmin.Serial') }}</th>
<th>{{ $t('inverteradmin.Name') }}</th>
<th>{{ $t('inverteradmin.Type') }}</th>
<th>{{ $t('inverteradmin.Action') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="inverter in sortedInverters" v-bind:key="inverter.id">
<td>{{ inverter.serial }}</td>
<td>{{ inverter.name }}</td>
<td>{{ inverter.type }}</td>
<td>
<a href="#" class="icon text-danger" :title="$t('inverteradmin.DeleteInverter')">
<BIconTrash v-on:click="onOpenModal(modalDelete, inverter)" />
</a>&nbsp;
<a href="#" class="icon" :title="$t('inverteradmin.EditInverter')">
<BIconPencil v-on:click="onOpenModal(modal, inverter)" />
</a>
</td>
</tr>
</tbody>
</table>
</div> </div>
</div> </CardElement>
</BasePage> </BasePage>
<div class="modal" id="inverterEdit" tabindex="-1"> <div class="modal" id="inverterEdit" tabindex="-1">
@ -163,6 +157,7 @@ import {
} from 'bootstrap-icons-vue'; } from 'bootstrap-icons-vue';
import * as bootstrap from 'bootstrap'; import * as bootstrap from 'bootstrap';
import BootstrapAlert from "@/components/BootstrapAlert.vue"; import BootstrapAlert from "@/components/BootstrapAlert.vue";
import CardElement from '@/components/CardElement.vue';
import { handleResponse, authHeader } from '@/utils/authentication'; import { handleResponse, authHeader } from '@/utils/authentication';
declare interface Channel { declare interface Channel {
@ -189,6 +184,7 @@ export default defineComponent({
components: { components: {
BasePage, BasePage,
BootstrapAlert, BootstrapAlert,
CardElement,
BIconTrash, BIconTrash,
BIconPencil, BIconPencil,
BIconInfoCircle, BIconInfoCircle,

View File

@ -4,31 +4,27 @@
{{ alertMessage }} {{ alertMessage }}
</BootstrapAlert> </BootstrapAlert>
<div class="card"> <CardElement :text="$t('login.SystemLogin')" textVariant="text-bg-danger">
<div class="card-header text-bg-danger">{{ $t('login.SystemLogin') }}</div> <form @submit.prevent="handleSubmit">
<div class="card-body"> <div class="form-group">
<label for="username">{{ $t('login.Username') }}</label>
<form @submit.prevent="handleSubmit"> <input type="text" v-model="username" name="username" class="form-control"
<div class="form-group"> :class="{ 'is-invalid': submitted && !username }" />
<label for="username">{{ $t('login.Username') }}</label> <div v-show="submitted && !username" class="invalid-feedback">{{ $t('login.UsernameRequired') }}
<input type="text" v-model="username" name="username" class="form-control"
:class="{ 'is-invalid': submitted && !username }" />
<div v-show="submitted && !username" class="invalid-feedback">{{ $t('login.UsernameRequired') }}
</div>
</div> </div>
<div class="form-group"> </div>
<label htmlFor="password">{{ $t('login.Password') }}</label> <div class="form-group">
<input type="password" v-model="password" name="password" class="form-control" <label htmlFor="password">{{ $t('login.Password') }}</label>
:class="{ 'is-invalid': submitted && !password }" /> <input type="password" v-model="password" name="password" class="form-control"
<div v-show="submitted && !password" class="invalid-feedback"> :class="{ 'is-invalid': submitted && !password }" />
{{ $t('login.PasswordRequired') }}</div> <div v-show="submitted && !password" class="invalid-feedback">
</div> {{ $t('login.PasswordRequired') }}</div>
<div class="form-group"> </div>
<button class="btn btn-primary" :disabled="dataLoading">{{ $t('login.LoginButton') }}</button> <div class="form-group">
</div> <button class="btn btn-primary" :disabled="dataLoading">{{ $t('login.LoginButton') }}</button>
</form> </div>
</div> </form>
</div> </CardElement>
</BasePage> </BasePage>
</template> </template>
@ -37,12 +33,14 @@ import { defineComponent } from 'vue';
import router from '@/router'; import router from '@/router';
import { login } from '@/utils'; import { login } from '@/utils';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import CardElement from '@/components/CardElement.vue';
import BootstrapAlert from "@/components/BootstrapAlert.vue"; import BootstrapAlert from "@/components/BootstrapAlert.vue";
export default defineComponent({ export default defineComponent({
components: { components: {
BasePage, BasePage,
BootstrapAlert, BootstrapAlert,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -4,16 +4,12 @@
{{ alertMessage }} {{ alertMessage }}
</BootstrapAlert> </BootstrapAlert>
<div class="card mt-5"> <CardElement :text="$t('maintenancereboot.PerformReboot')" textVariant="text-bg-primary" center-content>
<div class="card-header text-bg-primary">{{ $t('maintenancereboot.PerformReboot') }}</div> <button class="btn btn-danger" @click="onOpenModal(performReboot)">{{ $t('maintenancereboot.Reboot') }}
<div class="card-body text-center"> </button>
<button class="btn btn-danger" @click="onOpenModal(performReboot)">{{ $t('maintenancereboot.Reboot') }} <div class="alert alert-danger mt-3" role="alert" v-html="$t('maintenancereboot.RebootHint')"></div>
</button> </CardElement>
<div class="alert alert-danger mt-3" role="alert" v-html="$t('maintenancereboot.RebootHint')"></div>
</div>
</div>
</BasePage> </BasePage>
<div class="modal" id="performReboot" tabindex="-1"> <div class="modal" id="performReboot" tabindex="-1">
@ -42,12 +38,14 @@ import { defineComponent } from 'vue';
import * as bootstrap from 'bootstrap'; import * as bootstrap from 'bootstrap';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import BootstrapAlert from "@/components/BootstrapAlert.vue"; import BootstrapAlert from "@/components/BootstrapAlert.vue";
import CardElement from '@/components/CardElement.vue';
import { handleResponse, authHeader, isLoggedIn } from '@/utils/authentication'; import { handleResponse, authHeader, isLoggedIn } from '@/utils/authentication';
export default defineComponent({ export default defineComponent({
components: { components: {
BasePage, BasePage,
BootstrapAlert, BootstrapAlert,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -5,114 +5,102 @@
</BootstrapAlert> </BootstrapAlert>
<form @submit="saveMqttConfig"> <form @submit="saveMqttConfig">
<div class="card"> <CardElement :text="$t('mqttadmin.MqttConfiguration')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('mqttadmin.MqttConfiguration') }}</div> <InputElement :label="$t('mqttadmin.EnableMqtt')"
<div class="card-body"> v-model="mqttConfigList.mqtt_enabled"
type="checkbox" wide/>
<InputElement :label="$t('mqttadmin.EnableMqtt')" <InputElement v-show="mqttConfigList.mqtt_enabled"
v-model="mqttConfigList.mqtt_enabled" :label="$t('mqttadmin.EnableHass')"
type="checkbox" wide/> v-model="mqttConfigList.mqtt_hass_enabled"
type="checkbox" wide/>
</CardElement>
<InputElement v-show="mqttConfigList.mqtt_enabled" <CardElement :text="$t('mqttadmin.MqttBrokerParameter')" textVariant="text-bg-primary" add-space
:label="$t('mqttadmin.EnableHass')" v-show="mqttConfigList.mqtt_enabled"
v-model="mqttConfigList.mqtt_hass_enabled" >
type="checkbox" wide/> <InputElement :label="$t('mqttadmin.Hostname')"
</div> v-model="mqttConfigList.mqtt_hostname"
</div> type="text" maxlength="128"
:placeholder="$t('mqttadmin.HostnameHint')"/>
<div class="card mt-5" v-show="mqttConfigList.mqtt_enabled"> <InputElement :label="$t('mqttadmin.Port')"
<div class="card-header text-bg-primary"> v-model="mqttConfigList.mqtt_port"
{{ $t('mqttadmin.MqttBrokerParameter') }} type="number" min="1" max="65535"/>
</div>
<div class="card-body">
<InputElement :label="$t('mqttadmin.Hostname')" <InputElement :label="$t('mqttadmin.Username')"
v-model="mqttConfigList.mqtt_hostname" v-model="mqttConfigList.mqtt_username"
type="text" maxlength="128" type="text" maxlength="64"
:placeholder="$t('mqttadmin.HostnameHint')"/> :placeholder="$t('mqttadmin.UsernameHint')"/>
<InputElement :label="$t('mqttadmin.Port')" <InputElement :label="$t('mqttadmin.Password')"
v-model="mqttConfigList.mqtt_port" v-model="mqttConfigList.mqtt_password"
type="number" min="1" max="65535"/> type="password" maxlength="64"
:placeholder="$t('mqttadmin.PasswordHint')"/>
<InputElement :label="$t('mqttadmin.Username')" <InputElement :label="$t('mqttadmin.BaseTopic')"
v-model="mqttConfigList.mqtt_username" v-model="mqttConfigList.mqtt_topic"
type="text" maxlength="64" type="text" maxlength="32"
:placeholder="$t('mqttadmin.UsernameHint')"/> :placeholder="$t('mqttadmin.BaseTopicHint')"/>
<InputElement :label="$t('mqttadmin.Password')" <InputElement :label="$t('mqttadmin.PublishInterval')"
v-model="mqttConfigList.mqtt_password" v-model="mqttConfigList.mqtt_publish_interval"
type="password" maxlength="64" type="number" min="5" max="86400"
:placeholder="$t('mqttadmin.PasswordHint')"/> :postfix="$t('mqttadmin.Seconds')"/>
<InputElement :label="$t('mqttadmin.BaseTopic')" <InputElement :label="$t('mqttadmin.EnableRetain')"
v-model="mqttConfigList.mqtt_topic" v-model="mqttConfigList.mqtt_retain"
type="text" maxlength="32" type="checkbox"/>
:placeholder="$t('mqttadmin.BaseTopicHint')"/>
<InputElement :label="$t('mqttadmin.PublishInterval')" <InputElement :label="$t('mqttadmin.EnableTls')"
v-model="mqttConfigList.mqtt_publish_interval" v-model="mqttConfigList.mqtt_tls"
type="number" min="5" max="86400" type="checkbox"/>
:postfix="$t('mqttadmin.Seconds')"/>
<InputElement :label="$t('mqttadmin.EnableRetain')" <InputElement v-show="mqttConfigList.mqtt_tls"
v-model="mqttConfigList.mqtt_retain" :label="$t('mqttadmin.RootCa')"
type="checkbox"/> v-model="mqttConfigList.mqtt_root_ca_cert"
type="textarea" maxlength="2048" rows="10"/>
</CardElement>
<InputElement :label="$t('mqttadmin.EnableTls')" <CardElement :text="$t('mqttadmin.LwtParameters')" textVariant="text-bg-primary" add-space
v-model="mqttConfigList.mqtt_tls" v-show="mqttConfigList.mqtt_enabled"
type="checkbox"/> >
<InputElement :label="$t('mqttadmin.LwtTopic')"
v-model="mqttConfigList.mqtt_lwt_topic"
type="text" maxlength="32" :prefix="mqttConfigList.mqtt_topic"
:placeholder="$t('mqttadmin.LwtTopicHint')"/>
<InputElement v-show="mqttConfigList.mqtt_tls" <InputElement :label="$t('mqttadmin.LwtOnline')"
:label="$t('mqttadmin.RootCa')" v-model="mqttConfigList.mqtt_lwt_online"
v-model="mqttConfigList.mqtt_root_ca_cert" type="text" maxlength="20"
type="textarea" maxlength="2048" rows="10"/> :placeholder="$t('mqttadmin.LwtOnlineHint')"/>
</div>
</div>
<div class="card mt-5" v-show="mqttConfigList.mqtt_enabled"> <InputElement :label="$t('mqttadmin.LwtOffline')"
<div class="card-header text-bg-primary">{{ $t('mqttadmin.LwtParameters') }}</div> v-model="mqttConfigList.mqtt_lwt_offline"
<div class="card-body"> type="text" maxlength="20"
:placeholder="$t('mqttadmin.LwtOfflineHint')"/>
</CardElement>
<InputElement :label="$t('mqttadmin.LwtTopic')" <CardElement :text="$t('mqttadmin.HassParameters')" textVariant="text-bg-primary" add-space
v-model="mqttConfigList.mqtt_lwt_topic" v-show="mqttConfigList.mqtt_enabled && mqttConfigList.mqtt_hass_enabled"
type="text" maxlength="32" :prefix="mqttConfigList.mqtt_topic" >
:placeholder="$t('mqttadmin.LwtTopicHint')"/> <InputElement :label="$t('mqttadmin.HassPrefixTopic')"
v-model="mqttConfigList.mqtt_hass_topic"
type="text" maxlength="32"
:placeholder="$t('mqttadmin.HassPrefixTopicHint')"/>
<InputElement :label="$t('mqttadmin.LwtOnline')" <InputElement :label="$t('mqttadmin.HassRetain')"
v-model="mqttConfigList.mqtt_lwt_online" v-model="mqttConfigList.mqtt_hass_retain"
type="text" maxlength="20" type="checkbox"/>
:placeholder="$t('mqttadmin.LwtOnlineHint')"/>
<InputElement :label="$t('mqttadmin.LwtOffline')" <InputElement :label="$t('mqttadmin.HassExpire')"
v-model="mqttConfigList.mqtt_lwt_offline" v-model="mqttConfigList.mqtt_hass_expire"
type="text" maxlength="20" type="checkbox"/>
:placeholder="$t('mqttadmin.LwtOfflineHint')"/>
</div>
</div>
<div class="card mt-5" v-show="mqttConfigList.mqtt_enabled && mqttConfigList.mqtt_hass_enabled"> <InputElement :label="$t('mqttadmin.HassIndividual')"
<div class="card-header text-bg-primary">{{ $t('mqttadmin.HassParameters') }}</div> v-model="mqttConfigList.mqtt_hass_individualpanels"
<div class="card-body"> type="checkbox"/>
</CardElement>
<InputElement :label="$t('mqttadmin.HassPrefixTopic')"
v-model="mqttConfigList.mqtt_hass_topic"
type="text" maxlength="32"
:placeholder="$t('mqttadmin.HassPrefixTopicHint')"/>
<InputElement :label="$t('mqttadmin.HassRetain')"
v-model="mqttConfigList.mqtt_hass_retain"
type="checkbox"/>
<InputElement :label="$t('mqttadmin.HassExpire')"
v-model="mqttConfigList.mqtt_hass_expire"
type="checkbox"/>
<InputElement :label="$t('mqttadmin.HassIndividual')"
v-model="mqttConfigList.mqtt_hass_individualpanels"
type="checkbox"/>
</div>
</div>
<button type="submit" class="btn btn-primary mb-3">{{ $t('mqttadmin.Save') }}</button> <button type="submit" class="btn btn-primary mb-3">{{ $t('mqttadmin.Save') }}</button>
</form> </form>
@ -124,6 +112,7 @@ import { defineComponent } from 'vue';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import BootstrapAlert from "@/components/BootstrapAlert.vue"; import BootstrapAlert from "@/components/BootstrapAlert.vue";
import InputElement from '@/components/InputElement.vue'; import InputElement from '@/components/InputElement.vue';
import CardElement from '@/components/CardElement.vue';
import { handleResponse, authHeader } from '@/utils/authentication'; import { handleResponse, authHeader } from '@/utils/authentication';
import type { MqttConfig } from "@/types/MqttConfig"; import type { MqttConfig } from "@/types/MqttConfig";
@ -132,6 +121,7 @@ export default defineComponent({
BasePage, BasePage,
BootstrapAlert, BootstrapAlert,
InputElement, InputElement,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -1,149 +1,140 @@
<template> <template>
<BasePage :title="$t('mqttinfo.MqttInformation')" :isLoading="dataLoading"> <BasePage :title="$t('mqttinfo.MqttInformation')" :isLoading="dataLoading">
<div class="card"> <CardElement :text="$t('mqttinfo.ConfigurationSummary')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('mqttinfo.ConfigurationSummary') }}</div> <div class="table-responsive">
<div class="card-body"> <table class="table table-hover table-condensed">
<div class="table-responsive"> <tbody>
<table class="table table-hover table-condensed"> <tr>
<tbody> <th>{{ $t('mqttinfo.Status') }}</th>
<tr> <td class="badge" :class="{
<th>{{ $t('mqttinfo.Status') }}</th> 'text-bg-danger': !mqttDataList.mqtt_enabled,
<td class="badge" :class="{ 'text-bg-success': mqttDataList.mqtt_enabled,
'text-bg-danger': !mqttDataList.mqtt_enabled, }">
'text-bg-success': mqttDataList.mqtt_enabled, <span v-if="mqttDataList.mqtt_enabled">{{ $t('mqttinfo.Enabled') }}</span>
}"> <span v-else>{{ $t('mqttinfo.Disabled') }}</span>
<span v-if="mqttDataList.mqtt_enabled">{{ $t('mqttinfo.Enabled') }}</span> </td>
<span v-else>{{ $t('mqttinfo.Disabled') }}</span> </tr>
</td> <tr>
</tr> <th>{{ $t('mqttinfo.Server') }}</th>
<tr> <td>{{ mqttDataList.mqtt_hostname }}</td>
<th>{{ $t('mqttinfo.Server') }}</th> </tr>
<td>{{ mqttDataList.mqtt_hostname }}</td> <tr>
</tr> <th>{{ $t('mqttinfo.Port') }}</th>
<tr> <td>{{ mqttDataList.mqtt_port }}</td>
<th>{{ $t('mqttinfo.Port') }}</th> </tr>
<td>{{ mqttDataList.mqtt_port }}</td> <tr>
</tr> <th>{{ $t('mqttinfo.Username') }}</th>
<tr> <td>{{ mqttDataList.mqtt_username }}</td>
<th>{{ $t('mqttinfo.Username') }}</th> </tr>
<td>{{ mqttDataList.mqtt_username }}</td> <tr>
</tr> <th>{{ $t('mqttinfo.BaseTopic') }}</th>
<tr> <td>{{ mqttDataList.mqtt_topic }}</td>
<th>{{ $t('mqttinfo.BaseTopic') }}</th> </tr>
<td>{{ mqttDataList.mqtt_topic }}</td> <tr>
</tr> <th>{{ $t('mqttinfo.PublishInterval') }}</th>
<tr> <td>{{ $t('mqttinfo.Seconds', { sec: mqttDataList.mqtt_publish_interval }) }}</td>
<th>{{ $t('mqttinfo.PublishInterval') }}</th> </tr>
<td>{{ $t('mqttinfo.Seconds', { sec: mqttDataList.mqtt_publish_interval }) }}</td> <tr>
</tr> <th>{{ $t('mqttinfo.Retain') }}</th>
<tr> <td class="badge" :class="{
<th>{{ $t('mqttinfo.Retain') }}</th> 'text-bg-danger': !mqttDataList.mqtt_retain,
<td class="badge" :class="{ 'text-bg-success': mqttDataList.mqtt_retain,
'text-bg-danger': !mqttDataList.mqtt_retain, }">
'text-bg-success': mqttDataList.mqtt_retain, <span v-if="mqttDataList.mqtt_retain">{{ $t('mqttinfo.Enabled') }}</span>
}"> <span v-else>{{ $t('mqttinfo.Disabled') }}</span>
<span v-if="mqttDataList.mqtt_retain">{{ $t('mqttinfo.Enabled') }}</span> </td>
<span v-else>{{ $t('mqttinfo.Disabled') }}</span> </tr>
</td> <tr>
</tr> <th>{{ $t('mqttinfo.Tls') }}</th>
<tr> <td class="badge" :class="{
<th>{{ $t('mqttinfo.Tls') }}</th> 'text-bg-danger': !mqttDataList.mqtt_tls,
<td class="badge" :class="{ 'text-bg-success': mqttDataList.mqtt_tls,
'text-bg-danger': !mqttDataList.mqtt_tls, }">
'text-bg-success': mqttDataList.mqtt_tls, <span v-if="mqttDataList.mqtt_tls">{{ $t('mqttinfo.Enabled') }}</span>
}"> <span v-else>{{ $t('mqttinfo.Disabled') }}</span>
<span v-if="mqttDataList.mqtt_tls">{{ $t('mqttinfo.Enabled') }}</span> </td>
<span v-else>{{ $t('mqttinfo.Disabled') }}</span> </tr>
</td> <tr v-show="mqttDataList.mqtt_tls">
</tr> <th>{{ $t('mqttinfo.RootCertifcateInfo') }}</th>
<tr v-show="mqttDataList.mqtt_tls"> <td>{{ mqttDataList.mqtt_root_ca_cert_info }}</td>
<th>{{ $t('mqttinfo.RootCertifcateInfo') }}</th> </tr>
<td>{{ mqttDataList.mqtt_root_ca_cert_info }}</td> </tbody>
</tr> </table>
</tbody>
</table>
</div>
</div> </div>
</div> </CardElement>
<div class="card mt-5"> <CardElement :text="$t('mqttinfo.HassSummary')" textVariant="text-bg-primary" add-space>
<div class="card-header text-bg-primary">{{ $t('mqttinfo.HassSummary') }}</div> <div class="table-responsive">
<div class="card-body"> <table class="table table-hover table-condensed">
<div class="table-responsive"> <tbody>
<table class="table table-hover table-condensed"> <tr>
<tbody> <th>{{ $t('mqttinfo.Status') }}</th>
<tr> <td class="badge" :class="{
<th>{{ $t('mqttinfo.Status') }}</th> 'text-bg-danger': !mqttDataList.mqtt_hass_enabled,
<td class="badge" :class="{ 'text-bg-success': mqttDataList.mqtt_hass_enabled,
'text-bg-danger': !mqttDataList.mqtt_hass_enabled, }">
'text-bg-success': mqttDataList.mqtt_hass_enabled, <span v-if="mqttDataList.mqtt_hass_enabled">{{ $t('mqttinfo.Enabled') }}</span>
}"> <span v-else>{{ $t('mqttinfo.Disabled') }}</span>
<span v-if="mqttDataList.mqtt_hass_enabled">{{ $t('mqttinfo.Enabled') }}</span> </td>
<span v-else>{{ $t('mqttinfo.Disabled') }}</span> </tr>
</td> <tr>
</tr> <th>{{ $t('mqttinfo.BaseTopic') }}</th>
<tr> <td>{{ mqttDataList.mqtt_hass_topic }}</td>
<th>{{ $t('mqttinfo.BaseTopic') }}</th> </tr>
<td>{{ mqttDataList.mqtt_hass_topic }}</td> <tr>
</tr> <th>{{ $t('mqttinfo.Retain') }}</th>
<tr> <td class="badge" :class="{
<th>{{ $t('mqttinfo.Retain') }}</th> 'text-bg-danger': !mqttDataList.mqtt_hass_retain,
<td class="badge" :class="{ 'text-bg-success': mqttDataList.mqtt_hass_retain,
'text-bg-danger': !mqttDataList.mqtt_hass_retain, }">
'text-bg-success': mqttDataList.mqtt_hass_retain, <span v-if="mqttDataList.mqtt_hass_retain">{{ $t('mqttinfo.Enabled') }}</span>
}"> <span v-else>{{ $t('mqttinfo.Disabled') }}</span>
<span v-if="mqttDataList.mqtt_hass_retain">{{ $t('mqttinfo.Enabled') }}</span> </td>
<span v-else>{{ $t('mqttinfo.Disabled') }}</span> </tr>
</td> <tr>
</tr> <th>{{ $t('mqttinfo.Expire') }}</th>
<tr> <td class="badge" :class="{
<th>{{ $t('mqttinfo.Expire') }}</th> 'text-bg-danger': !mqttDataList.mqtt_hass_expire,
<td class="badge" :class="{ 'text-bg-success': mqttDataList.mqtt_hass_expire,
'text-bg-danger': !mqttDataList.mqtt_hass_expire, }">
'text-bg-success': mqttDataList.mqtt_hass_expire, <span v-if="mqttDataList.mqtt_hass_expire">{{ $t('mqttinfo.Enabled') }}</span>
}"> <span v-else>{{ $t('mqttinfo.Disabled') }}</span>
<span v-if="mqttDataList.mqtt_hass_expire">{{ $t('mqttinfo.Enabled') }}</span> </td>
<span v-else>{{ $t('mqttinfo.Disabled') }}</span> </tr>
</td> <tr>
</tr> <th>{{ $t('mqttinfo.IndividualPanels') }}</th>
<tr> <td class="badge" :class="{
<th>{{ $t('mqttinfo.IndividualPanels') }}</th> 'text-bg-danger': !mqttDataList.mqtt_hass_individualpanels,
<td class="badge" :class="{ 'text-bg-success': mqttDataList.mqtt_hass_individualpanels,
'text-bg-danger': !mqttDataList.mqtt_hass_individualpanels, }">
'text-bg-success': mqttDataList.mqtt_hass_individualpanels, <span v-if="mqttDataList.mqtt_hass_individualpanels">{{ $t('mqttinfo.Enabled')
}"> }}</span>
<span v-if="mqttDataList.mqtt_hass_individualpanels">{{ $t('mqttinfo.Enabled') <span v-else>{{ $t('mqttinfo.Disabled') }}</span>
}}</span> </td>
<span v-else>{{ $t('mqttinfo.Disabled') }}</span> </tr>
</td> </tbody>
</tr> </table>
</tbody>
</table>
</div>
</div> </div>
</div> </CardElement>
<div class="card mt-5"> <CardElement :text="$t('mqttinfo.RuntimeSummary')" textVariant="text-bg-primary" add-space>
<div class="card-header text-bg-primary">{{ $t('mqttinfo.RuntimeSummary') }}</div> <div class="table-responsive">
<div class="card-body"> <table class="table table-hover table-condensed">
<div class="table-responsive"> <tbody>
<table class="table table-hover table-condensed"> <tr>
<tbody> <th>{{ $t('mqttinfo.ConnectionStatus') }}</th>
<tr> <td class="badge" :class="{
<th>{{ $t('mqttinfo.ConnectionStatus') }}</th> 'text-bg-danger': !mqttDataList.mqtt_connected,
<td class="badge" :class="{ 'text-bg-success': mqttDataList.mqtt_connected,
'text-bg-danger': !mqttDataList.mqtt_connected, }">
'text-bg-success': mqttDataList.mqtt_connected, <span v-if="mqttDataList.mqtt_connected">{{ $t('mqttinfo.Connected') }}</span>
}"> <span v-else>{{ $t('mqttinfo.Disconnected') }}</span>
<span v-if="mqttDataList.mqtt_connected">{{ $t('mqttinfo.Connected') }}</span> </td>
<span v-else>{{ $t('mqttinfo.Disconnected') }}</span> </tr>
</td> </tbody>
</tr> </table>
</tbody>
</table>
</div>
</div> </div>
</div> </CardElement>
</BasePage> </BasePage>
</template> </template>
@ -151,11 +142,13 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { handleResponse, authHeader } from '@/utils/authentication'; import { handleResponse, authHeader } from '@/utils/authentication';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import CardElement from '@/components/CardElement.vue';
import type { MqttStatus } from '@/types/MqttStatus'; import type { MqttStatus } from '@/types/MqttStatus';
export default defineComponent({ export default defineComponent({
components: { components: {
BasePage, BasePage,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -5,58 +5,51 @@
</BootstrapAlert> </BootstrapAlert>
<form @submit="saveNetworkConfig"> <form @submit="saveNetworkConfig">
<div class="card"> <CardElement :text="$t('networkadmin.WifiConfiguration')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('networkadmin.WifiConfiguration') }}</div> <InputElement :label="$t('networkadmin.WifiSsid')"
<div class="card-body"> v-model="networkConfigList.ssid"
type="text" maxlength="32"/>
<InputElement :label="$t('networkadmin.WifiSsid')" <InputElement :label="$t('networkadmin.WifiPassword')"
v-model="networkConfigList.ssid" v-model="networkConfigList.password"
type="text" maxlength="32"/> type="password" maxlength="64"/>
<InputElement :label="$t('networkadmin.WifiPassword')" <InputElement :label="$t('networkadmin.Hostname')"
v-model="networkConfigList.password" v-model="networkConfigList.hostname"
type="password" maxlength="64"/> type="text" maxlength="32"
>
<div class="alert alert-secondary" role="alert" v-html="$t('networkadmin.HostnameHint')"></div>
</InputElement>
<InputElement :label="$t('networkadmin.Hostname')" <InputElement :label="$t('networkadmin.EnableDhcp')"
v-model="networkConfigList.hostname" v-model="networkConfigList.dhcp"
type="text" maxlength="32" type="checkbox"/>
> </CardElement>
<div class="alert alert-secondary" role="alert" v-html="$t('networkadmin.HostnameHint')"></div>
</InputElement>
<InputElement :label="$t('networkadmin.EnableDhcp')" <CardElement :text="$t('networkadmin.StaticIpConfiguration')" textVariant="text-bg-primary" add-space
v-model="networkConfigList.dhcp" v-show="!networkConfigList.dhcp"
type="checkbox"/> >
</div> <InputElement :label="$t('networkadmin.IpAddress')"
</div> v-model="networkConfigList.ipaddress"
type="text" maxlength="32"/>
<div class="card" v-show="!networkConfigList.dhcp"> <InputElement :label="$t('networkadmin.Netmask')"
<div class="card-header text-bg-primary"> v-model="networkConfigList.netmask"
{{ $t('networkadmin.StaticIpConfiguration') }} type="text" maxlength="32"/>
</div>
<div class="card-body">
<InputElement :label="$t('networkadmin.IpAddress')" <InputElement :label="$t('networkadmin.DefaultGateway')"
v-model="networkConfigList.ipaddress" v-model="networkConfigList.gateway"
type="text" maxlength="32"/> type="text" maxlength="32"/>
<InputElement :label="$t('networkadmin.Netmask')" <InputElement :label="$t('networkadmin.Dns', { num: 1 })"
v-model="networkConfigList.netmask" v-model="networkConfigList.dns1"
type="text" maxlength="32"/> type="text" maxlength="32"/>
<InputElement :label="$t('networkadmin.DefaultGateway')" <InputElement :label="$t('networkadmin.Dns', { num: 2 })"
v-model="networkConfigList.gateway" v-model="networkConfigList.dns2"
type="text" maxlength="32"/> type="text" maxlength="32"/>
</CardElement>
<InputElement :label="$t('networkadmin.Dns', { num: 1 })"
v-model="networkConfigList.dns1"
type="text" maxlength="32"/>
<InputElement :label="$t('networkadmin.Dns', { num: 2 })"
v-model="networkConfigList.dns2"
type="text" maxlength="32"/>
</div>
</div>
<button type="submit" class="btn btn-primary mb-3">{{ $t('networkadmin.Save') }}</button> <button type="submit" class="btn btn-primary mb-3">{{ $t('networkadmin.Save') }}</button>
</form> </form>
</BasePage> </BasePage>
@ -67,6 +60,7 @@ import { defineComponent } from 'vue';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import BootstrapAlert from "@/components/BootstrapAlert.vue"; import BootstrapAlert from "@/components/BootstrapAlert.vue";
import InputElement from '@/components/InputElement.vue'; import InputElement from '@/components/InputElement.vue';
import CardElement from '@/components/CardElement.vue';
import { handleResponse, authHeader } from '@/utils/authentication'; import { handleResponse, authHeader } from '@/utils/authentication';
import type { NetworkConfig } from "@/types/NetworkkConfig"; import type { NetworkConfig } from "@/types/NetworkkConfig";
@ -75,6 +69,7 @@ export default defineComponent({
BasePage, BasePage,
BootstrapAlert, BootstrapAlert,
InputElement, InputElement,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -5,55 +5,47 @@
</BootstrapAlert> </BootstrapAlert>
<form @submit="saveNtpConfig"> <form @submit="saveNtpConfig">
<div class="card"> <CardElement :text="$t('ntpadmin.NtpConfiguration')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('ntpadmin.NtpConfiguration') }}</div> <InputElement :label="$t('ntpadmin.TimeServer')"
<div class="card-body"> v-model="ntpConfigList.ntp_server"
type="text" maxlength="32"
:tooltip="$t('ntpadmin.TimeServerHint')"/>
<InputElement :label="$t('ntpadmin.TimeServer')" <div class="row mb-3">
v-model="ntpConfigList.ntp_server" <label for="inputTimezone" class="col-sm-2 col-form-label">{{ $t('ntpadmin.Timezone') }}</label>
type="text" maxlength="32" <div class="col-sm-10">
:tooltip="$t('ntpadmin.TimeServerHint')"/> <select class="form-select" v-model="timezoneSelect">
<option v-for="(config, name) in timezoneList" :key="name + '---' + config"
<div class="row mb-3"> :value="name + '---' + config">
<label for="inputTimezone" class="col-sm-2 col-form-label">{{ $t('ntpadmin.Timezone') }}</label> {{ name }}
<div class="col-sm-10"> </option>
<select class="form-select" v-model="timezoneSelect"> </select>
<option v-for="(config, name) in timezoneList" :key="name + '---' + config"
:value="name + '---' + config">
{{ name }}
</option>
</select>
</div>
</div> </div>
<InputElement :label="$t('ntpadmin.TimezoneConfig')"
v-model="ntpConfigList.ntp_timezone"
type="text" maxlength="32" disabled/>
</div> </div>
</div>
<InputElement :label="$t('ntpadmin.TimezoneConfig')"
v-model="ntpConfigList.ntp_timezone"
type="text" maxlength="32" disabled/>
</CardElement>
<button type="submit" class="btn btn-primary mb-3">{{ $t('ntpadmin.Save') }}</button> <button type="submit" class="btn btn-primary mb-3">{{ $t('ntpadmin.Save') }}</button>
</form> </form>
<div class="card"> <CardElement :text="$t('ntpadmin.ManualTimeSynchronization')" textVariant="text-bg-primary" add-space>
<div class="card-header text-bg-primary">{{ $t('ntpadmin.ManualTimeSynchronization') }}</div> <InputElement :label="$t('ntpadmin.CurrentOpenDtuTime')"
<div class="card-body"> v-model="mcuTime"
type="text" disabled/>
<InputElement :label="$t('ntpadmin.CurrentOpenDtuTime')" <InputElement :label="$t('ntpadmin.CurrentLocalTime')"
v-model="mcuTime" v-model="localTime"
type="text" disabled/> type="text" disabled/>
<InputElement :label="$t('ntpadmin.CurrentLocalTime')" <div class="text-center mb-3">
v-model="localTime" <button type="button" class="btn btn-danger" @click="setCurrentTime()">
type="text" disabled/> {{ $t('ntpadmin.SynchronizeTime') }}
</button>
<div class="text-center mb-3">
<button type="button" class="btn btn-danger" @click="setCurrentTime()">
{{ $t('ntpadmin.SynchronizeTime') }}
</button>
</div>
<div class="alert alert-secondary" role="alert" v-html="$t('ntpadmin.SynchronizeTimeHint')"></div>
</div> </div>
</div> <div class="alert alert-secondary" role="alert" v-html="$t('ntpadmin.SynchronizeTimeHint')"></div>
</CardElement>
</BasePage> </BasePage>
</template> </template>
@ -62,6 +54,7 @@ import { defineComponent } from 'vue';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import BootstrapAlert from "@/components/BootstrapAlert.vue"; import BootstrapAlert from "@/components/BootstrapAlert.vue";
import InputElement from '@/components/InputElement.vue'; import InputElement from '@/components/InputElement.vue';
import CardElement from '@/components/CardElement.vue';
import { handleResponse, authHeader } from '@/utils/authentication'; import { handleResponse, authHeader } from '@/utils/authentication';
import type { NtpConfig } from "@/types/NtpConfig"; import type { NtpConfig } from "@/types/NtpConfig";
import { import {
@ -74,6 +67,7 @@ export default defineComponent({
BootstrapAlert, BootstrapAlert,
BIconInfoCircle, BIconInfoCircle,
InputElement, InputElement,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -1,54 +1,48 @@
<template> <template>
<BasePage :title="$t('ntpinfo.NtpInformation')" :isLoading="dataLoading"> <BasePage :title="$t('ntpinfo.NtpInformation')" :isLoading="dataLoading">
<div class="card"> <CardElement :text="$t('ntpinfo.ConfigurationSummary')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('ntpinfo.ConfigurationSummary') }}</div> <div class="table-responsive">
<div class="card-body"> <table class="table table-hover table-condensed">
<div class="table-responsive"> <tbody>
<table class="table table-hover table-condensed"> <tr>
<tbody> <th>{{ $t('ntpinfo.Server') }}</th>
<tr> <td>{{ ntpDataList.ntp_server }}</td>
<th>{{ $t('ntpinfo.Server') }}</th> </tr>
<td>{{ ntpDataList.ntp_server }}</td> <tr>
</tr> <th>{{ $t('ntpinfo.Timezone') }}</th>
<tr> <td>{{ ntpDataList.ntp_timezone }}</td>
<th>{{ $t('ntpinfo.Timezone') }}</th> </tr>
<td>{{ ntpDataList.ntp_timezone }}</td> <tr>
</tr> <th>{{ $t('ntpinfo.TimezoneDescription') }}</th>
<tr> <td>{{ ntpDataList.ntp_timezone_descr }}</td>
<th>{{ $t('ntpinfo.TimezoneDescription') }}</th> </tr>
<td>{{ ntpDataList.ntp_timezone_descr }}</td> </tbody>
</tr> </table>
</tbody>
</table>
</div>
</div> </div>
</div> </CardElement>
<div class="card mt-5"> <CardElement :text="$t('ntpinfo.CurrentTime')" textVariant="text-bg-primary" add-space>
<div class="card-header text-bg-primary">{{ $t('ntpinfo.CurrentTime') }}</div> <div class="table-responsive">
<div class="card-body"> <table class="table table-hover table-condensed">
<div class="table-responsive"> <tbody>
<table class="table table-hover table-condensed"> <tr>
<tbody> <th>{{ $t('ntpinfo.Status') }}</th>
<tr> <td class="badge" :class="{
<th>{{ $t('ntpinfo.Status') }}</th> 'text-bg-danger': !ntpDataList.ntp_status,
<td class="badge" :class="{ 'text-bg-success': ntpDataList.ntp_status,
'text-bg-danger': !ntpDataList.ntp_status, }">
'text-bg-success': ntpDataList.ntp_status, <span v-if="ntpDataList.ntp_status">{{ $t('ntpinfo.Synced') }}</span>
}"> <span v-else>{{ $t('ntpinfo.NotSynced') }}</span>
<span v-if="ntpDataList.ntp_status">{{ $t('ntpinfo.Synced') }}</span> </td>
<span v-else>{{ $t('ntpinfo.NotSynced') }}</span> </tr>
</td> <tr>
</tr> <th>{{ $t('ntpinfo.LocalTime') }}</th>
<tr> <td>{{ ntpDataList.ntp_localtime }}</td>
<th>{{ $t('ntpinfo.LocalTime') }}</th> </tr>
<td>{{ ntpDataList.ntp_localtime }}</td> </tbody>
</tr> </table>
</tbody>
</table>
</div>
</div> </div>
</div> </CardElement>
</BasePage> </BasePage>
</template> </template>
@ -56,11 +50,13 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { handleResponse, authHeader } from '@/utils/authentication'; import { handleResponse, authHeader } from '@/utils/authentication';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import CardElement from '@/components/CardElement.vue';
import type { NtpStatus } from "@/types/NtpStatus"; import type { NtpStatus } from "@/types/NtpStatus";
export default defineComponent({ export default defineComponent({
components: { components: {
BasePage, BasePage,
CardElement,
}, },
data() { data() {
return { return {

View File

@ -5,31 +5,23 @@
</BootstrapAlert> </BootstrapAlert>
<form @submit="savePasswordConfig"> <form @submit="savePasswordConfig">
<div class="card"> <CardElement :text="$t('securityadmin.AdminPassword')" textVariant="text-bg-primary">
<div class="card-header text-bg-primary">{{ $t('securityadmin.AdminPassword') }}</div> <InputElement :label="$t('securityadmin.Password')"
<div class="card-body"> v-model="securityConfigList.password"
type="password" maxlength="64"/>
<InputElement :label="$t('securityadmin.Password')" <InputElement :label="$t('securityadmin.RepeatPassword')"
v-model="securityConfigList.password" v-model="passwordRepeat"
type="password" maxlength="64"/> type="password" maxlength="64"/>
<InputElement :label="$t('securityadmin.RepeatPassword')" <div class="alert alert-secondary" role="alert" v-html="$t('securityadmin.PasswordHint')"></div>
v-model="passwordRepeat" </CardElement>
type="password" maxlength="64"/>
<div class="alert alert-secondary" role="alert" v-html="$t('securityadmin.PasswordHint')"></div> <CardElement :text="$t('securityadmin.Permissions')" textVariant="text-bg-primary" add-space>
</div> <InputElement :label="$t('securityadmin.ReadOnly')"
</div> v-model="securityConfigList.allow_readonly"
type="checkbox" wide/>
<div class="card mt-5"> </CardElement>
<div class="card-header text-bg-primary">{{ $t('securityadmin.Permissions') }}</div>
<div class="card-body">
<InputElement :label="$t('securityadmin.ReadOnly')"
v-model="securityConfigList.allow_readonly"
type="checkbox" wide/>
</div>
</div>
<button type="submit" class="btn btn-primary mb-3">{{ $t('securityadmin.Save') }}</button> <button type="submit" class="btn btn-primary mb-3">{{ $t('securityadmin.Save') }}</button>
</form> </form>
@ -41,6 +33,7 @@ import { defineComponent } from 'vue';
import BasePage from '@/components/BasePage.vue'; import BasePage from '@/components/BasePage.vue';
import BootstrapAlert from "@/components/BootstrapAlert.vue"; import BootstrapAlert from "@/components/BootstrapAlert.vue";
import InputElement from '@/components/InputElement.vue'; import InputElement from '@/components/InputElement.vue';
import CardElement from '@/components/CardElement.vue';
import { handleResponse, authHeader } from '@/utils/authentication'; import { handleResponse, authHeader } from '@/utils/authentication';
import type { SecurityConfig } from '@/types/SecurityConfig'; import type { SecurityConfig } from '@/types/SecurityConfig';
@ -49,6 +42,7 @@ export default defineComponent({
BasePage, BasePage,
BootstrapAlert, BootstrapAlert,
InputElement, InputElement,
CardElement,
}, },
data() { data() {
return { return {