blob: 341a1ccff556c0efd811f2e71cb50fe787133246 [file]
<!--
Copyright (c) 2025 Silicon Labs.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
-->
<template>
<div class="column fit">
<q-toolbar class="bg-transparent q-px-sm border-bottom">
<div class="text-h6">Validation</div>
<q-space />
<q-btn
flat
dense
icon="refresh"
label="Refresh"
no-caps
data-cy="btn-validation-refresh"
:loading="loading"
@click="refreshValidation"
/>
</q-toolbar>
<q-scroll-area class="col">
<div class="q-pa-sm">
<div v-if="!validationReport" class="text-grey q-pa-md text-body2">
No validation results yet. Click Refresh or choose Validate on the
toolbar to run a full check.
</div>
<template v-else>
<div class="text-body2 q-mb-md">
<span
v-if="validationReport.summary.errors > 0"
class="text-negative"
>
{{ validationReport.summary.errors }} error(s)
</span>
<span
v-if="validationReport.summary.errors === 0"
class="text-positive"
>
No validation issues found.
</span>
<span class="text-caption q-ml-sm text-grey">
Checked {{ validationReport.summary.attributes }} attribute(s),
{{ validationReport.summary.endpoints }} endpoint(s),
{{ validationReport.summary.clusters }} cluster check(s).
</span>
</div>
<q-expansion-item
v-if="validationReport.endpoints.length > 0"
default-opened
icon="settings_input_component"
label="Endpoints"
header-class="text-subtitle1"
>
<q-table
flat
dense
:rows="validationReport.endpoints"
:columns="endpointIssueColumns"
row-key="endpointDbId"
>
<template #body-cell-issues="props">
<q-td :props="props">
<div v-if="props.row.issues.endpointId.length">
<strong>Endpoint ID:</strong>
{{ props.row.issues.endpointId.join('; ') }}
</div>
<div v-if="props.row.issues.networkId.length">
<strong>Network ID:</strong>
{{ props.row.issues.networkId.join('; ') }}
</div>
</q-td>
</template>
</q-table>
</q-expansion-item>
<q-expansion-item
v-if="validationReport.attributes.length > 0"
default-opened
icon="tune"
label="Attributes"
header-class="text-subtitle1"
>
<q-table
flat
dense
wrap-cells
:rows="validationReport.attributes"
:columns="attributeIssueColumns"
:row-key="attributeRowKey"
>
<template #body-cell-issues="props">
<q-td :props="props">
{{ props.row.issues.join('; ') }}
</q-td>
</template>
</q-table>
</q-expansion-item>
<q-expansion-item
v-if="validationReport.conformance.length > 0"
default-opened
icon="rule_folder"
label="Conformance"
header-class="text-subtitle1"
>
<q-table
flat
dense
wrap-cells
:rows="validationReport.conformance"
:columns="conformanceIssueColumns"
:row-key="conformanceRowKey"
>
<template #body-cell-warnings="props">
<q-td :props="props">
<ul class="q-ma-none">
<li v-for="(w, i) in props.row.warnings" :key="i">
{{ w }}
</li>
</ul>
</q-td>
</template>
</q-table>
</q-expansion-item>
</template>
</div>
</q-scroll-area>
</div>
</template>
<script>
import commonMixin from '../util/common-mixin'
const restApi = require('../../src-shared/rest-api.js')
const rendApi = require('../../src-shared/rend-api.js')
export default {
name: 'ValidationPanelPage',
mixins: [commonMixin],
data() {
return {
loading: false,
endpointIssueColumns: [
{
name: 'endpointId',
label: 'Endpoint #',
field: 'endpointId',
align: 'left'
},
{
name: 'endpointDbId',
label: 'DB id',
field: 'endpointDbId',
align: 'left'
},
{
name: 'issues',
label: 'Issues',
field: 'issues',
align: 'left'
}
],
attributeIssueColumns: [
{
name: 'endpointIdentifierLabel',
label: 'Endpoint #',
field: 'endpointIdentifierLabel',
align: 'left'
},
{
name: 'clusterName',
label: 'Cluster',
field: 'clusterName',
align: 'left'
},
{
name: 'attributeName',
label: 'Attribute',
field: 'attributeName',
align: 'left'
},
{
name: 'defaultValue',
label: 'Default',
field: 'defaultValue',
align: 'left'
},
{
name: 'issues',
label: 'Issues',
field: 'issues',
align: 'left'
}
],
conformanceIssueColumns: [
{
name: 'endpointId',
label: 'Endpoint #',
field: 'endpointId',
align: 'left'
},
{
name: 'clusterName',
label: 'Cluster',
field: 'clusterName',
align: 'left'
},
{
name: 'warnings',
label: 'Issues',
field: 'warnings',
align: 'left'
}
]
}
},
computed: {
validationReport() {
return this.$store.state.zap.validationReport
}
},
methods: {
attributeRowKey(row) {
return `${row.endpointTypeId}-${row.clusterRef}-${row.attributeRef}`
},
conformanceRowKey(row) {
return `${row.endpointDbId}-${row.clusterRef}`
},
refreshValidation() {
if (this.$serverGet == null) return
this.loading = true
window[rendApi.GLOBAL_SYMBOL_EXECUTE](
rendApi.id.progressStart,
'Validating configuration...'
)
this.$serverGet(restApi.uri.validate)
.then((resp) => {
const body = resp?.data
if (body == null) {
if (this.$q && this.$q.notify) {
this.$q.notify({
type: 'negative',
message: 'Validation returned no data'
})
}
return
}
this.$store.commit('zap/setValidationReport', body)
})
.catch((err) => {
console.error(err)
if (this.$q && this.$q.notify) {
this.$q.notify({
type: 'negative',
message:
(err.response &&
err.response.data &&
err.response.data.error) ||
err.message ||
'Validation failed'
})
}
})
.finally(() => {
this.loading = false
window[rendApi.GLOBAL_SYMBOL_EXECUTE](rendApi.id.progressEnd)
})
}
}
}
</script>