231801_test_to_master #1519

Merged
alexm merged 490 commits from 231801_test_to_master into master 2023-05-12 06:29:59 +00:00
4 changed files with 229 additions and 162 deletions
Showing only changes of commit 4982fb254c - Show all commits

View File

@ -5,8 +5,8 @@ const $ = {
userName: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.name"]',
email: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.email"]',
saveButton: 'vn-client-web-access button[type=submit]',
nameValue: 'vn-client-log tbody:nth-child(2) .basic-json:nth-child(1) vn-json-value',
activeValue: 'vn-client-log tbody:nth-child(3) .basic-json:nth-child(2) vn-json-value'
nameValue: 'vn-client-log .change:nth-child(1) .basic-json:nth-child(1) vn-json-value',
activeValue: 'vn-client-log .change:nth-child(2) .basic-json:nth-child(2) vn-json-value'
};
describe('Client web access path', () => {

View File

@ -14,111 +14,105 @@
order="changedModel"
auto-load="true">
</vn-crud-model>
<vn-data-viewer model="model" class="vn-w-md">
<vn-card>
<table class="vn-table" model="model">
<thead>
<tr>
<th translate field="action" class="action">
Action
</th>
<th field="changedModel">
<span ng-if="$ctrl.showModelName" translate>Model</span>
</th>
<th translate field="creationDate" class="date">
Date
</th>
</tr>
</thead>
<tbody ng-repeat="log in $ctrl.logs">
<tr class="change-header">
<td class="user">
<span ng-if="::log.user.worker.id"
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, log.user.worker.id)">
{{::log.user.name}}
<vn-data-viewer model="model" class="vn-w-md vn-px-sm">
<div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs">
<div class="user-wrapper">
<div
class="user vn-mt-xs"
title="{{::log.user.nickname || 'System'}}">
<img
ng-if="::log.user.worker"
src="/api/Images/user/160x160/{{::log.user.worker.id}}/download?access_token={{::$ctrl.vnToken.token}}"
ng-click="$ctrl.showWorkerDescriptor($event, log.user.worker.id)">
</img>
<div
ng-if="::!log.user.worker"
ng-class="::{system: !log.user}"
ng-style="::$ctrl.userBgColor(log.user)"
class="user-icon">
{{::log.user ? log.user.name.charAt(0).toUpperCase() : 'S'}}
</div>
</div>
<div class="arrow bg-panel"></div>
<div class="line"></div>
</div>
<vn-card class="detail vn-pa-sm">
<div class="header vn-mb-sm">
<div
class="date text-secondary text-caption"
title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}">
{{::$ctrl.relativeDate(log.creationDate)}}
</div>
<span class="chip {{::$ctrl.actionsClass[log.action]}}" translate>
{{::$ctrl.actionsText[log.action]}}
</span>
</div>
<div
class="model vn-mb-sm"
title="{{::log.changedModelValue}}"
ng-if="::log.changedModel || log.changedModelValue">
<span class="model-name"
ng-if="::$ctrl.showModelName"
title="{{::log.changedModel}}">
{{::log.changedModelI18n}}
</span>
<span class="model-id"
ng-if="::log.changedModelId">
#{{::log.changedModelId}}
</span>
<span class="model-value">
{{::log.changedModelValue}}
</span>
</div>
<div class="changes {{::log.props.length ? 'props' : 'no-props'}}" vn-id="changes">
<vn-icon icon="visibility"
class="expand-button"
ng-click="$ctrl.toggleAttributes(log, changes, true)">
</vn-icon>
<vn-icon icon="visibility_off"
class="shrink-button"
ng-click="$ctrl.toggleAttributes(log, changes, false)">
</vn-icon>
<div class="changes-wrapper">
<span ng-if="::log.props.length"
class="attributes">
<span ng-if="!log.expand" ng-repeat="prop in ::log.props"
class="basic-json">
<span class="json-field"
title="{{::prop.name}}">
{{::prop.nameI18n}}:
</span>
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value><span ng-if="::!$last">,</span>
</span>
<span ng-if="::!log.user.worker.id" translate>
System
</span>
</td>
<td title="{{::log.changedModelValue}}">
<span class="model-name"
ng-if="::$ctrl.showModelName"
title="{{::log.changedModel}}">
{{::log.changedModelI18n}}
</span>
<span class="model-value">
{{::log.changedModelValue}}
</span>
<span class="model-id"
ng-if="::log.changedModelId">
#{{::log.changedModelId}}
</span>
</td>
<td class="date" title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}">
{{::$ctrl.relativeDate(log.creationDate)}}
</td>
</tr>
<tr class="change-detail">
<td class="action">
<span class="chip {{::$ctrl.actionsClass[log.action]}}" translate>
{{::$ctrl.actionsText[log.action]}}
</span>
</td>
<td colspan="2">
<div vn-id="changes" class="changes {{::log.props.length ? 'props' : 'no-props'}}">
<vn-icon icon="visibility"
class="expand-button"
ng-click="$ctrl.toggleAttributes(log, changes, true)">
</vn-icon>
<vn-icon icon="visibility_off"
class="shrink-button"
ng-click="$ctrl.toggleAttributes(log, changes, false)">
</vn-icon>
<div class="changes-wrapper">
<span ng-if="::log.props.length"
class="attributes">
<span ng-if="!log.expand" ng-repeat="prop in ::log.props"
class="basic-json">
<span class="json-field"
title="{{::prop.name}}">
{{::prop.nameI18n}}:
</span>
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value><span ng-if="::!$last">,</span>
</span>
<div ng-if="log.expand"
class="expanded-json">
<div ng-repeat="prop in ::log.props">
<span class="json-field"
title="{{::prop.name}}">
{{::prop.nameI18n}}:
</span>
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value>
<span ng-if="::log.action == 'update'">
<vn-json-value value="::prop.old"></vn-json-value>
</span>
</div>
</div>
<div ng-if="log.expand"
class="expanded-json">
<div ng-repeat="prop in ::log.props">
<span class="json-field"
title="{{::prop.name}}">
{{::prop.nameI18n}}:
</span>
<span ng-if="::!log.props.length"
class="description">
{{::log.description}}
</span>
<span ng-if="::!log.description && !log.props.length"
class="no-changes"
translate>
No changes
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value>
<span ng-if="::log.action == 'update'">
<vn-json-value value="::prop.old"></vn-json-value>
</span>
</div>
</div>
</td>
</tr>
</tbody>
</table>
<vn-pagination model="model"></vn-pagination>
</vn-card>
</span>
<span ng-if="::!log.props.length"
class="description">
{{::log.description}}
</span>
<span ng-if="::!log.description && !log.props.length"
class="no-changes"
translate>
No changes
</span>
</div>
</vn-card>
</div>
</div>
</vn-data-viewer>
<vn-pagination model="model"></vn-pagination>
<vn-side-menu side="right">
<form vn-vertical
ng-model-options="{updateOn: 'change blur'}"

View File

@ -23,7 +23,7 @@ export default class Controller extends Section {
include: [{
relation: 'user',
scope: {
fields: ['name'],
fields: ['nickname'],
include: {
relation: 'worker',
scope: {
@ -200,6 +200,17 @@ export default class Controller extends Section {
]}
}
}
userBgColor(user) {
if (!user) return;
const name = user.name || '';
let hash = 0;
for (let i = 0; i < name.length; i++)
hash += name.charCodeAt(i);
return {
backgroundColor: '#'+ colors[hash % colors.length]
};
}
}
ngModule.vnComponent('vnLog', {
@ -213,3 +224,29 @@ ngModule.vnComponent('vnLog', {
url: '@'
}
});
const colors = [
'e2553d', // Coral
'FFA07A', // Salmon
'FFDAB9', // Peach
'a17077', // Pink
'bf0e99', // Pink light
'52a500', // Green chartreuse
'00aeae', // Cian
'b754cf', // Purple middle
'8a69cd', // Blue lavender
'1fa8a1', // Green ocean
'DC143C', // Red crimson
'5681cf', // Blue steel
'FF1493', // Ping intense
'00d700', // Green lime
'1E90FF', // Blue sky
'8B008B', // Purple dark
'cc7000', // Orange bright
'00b5b8', // Turquoise
'8B0000', // Red dark
'008080', // Green bluish
'2F4F4F', // Gray board
'7e7e7e', // Gray
'5d5d5d', // Gray dark
];

View File

@ -1,79 +1,116 @@
@import "variables";
vn-log {
.vn-table {
table-layout: fixed;
.change {
display: flex;
& > thead,
& > tbody {
& > tr {
td, th {
&:first-child {
padding-left: 16px;
}
&:last-child {
padding-right: 16px;
& > .user-wrapper {
position: relative;
padding-right: 10px;
& > .user {
border-radius: 50%;
height: 36px;
width: 36px;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
& > * {
width: 100%;
height: 100%;
}
img {
display: block;
cursor: pointer;
}
.user-icon {
font-size: 22px;
display: flex;
align-items: center;
justify-content: center;
&.system {
background-color: $color-main;
}
}
}
}
& > thead > tr > th {
max-width: initial;
}
& > tbody {
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
&:last-child {
border-bottom: none;
& > .arrow {
height: 8px;
width: 8px;
position: absolute;
transform: rotateY(0deg) rotate(45deg);
top: 18px;
right: -4px;
z-index: 1;
}
& > tr {
border-bottom: none;
height: initial;
& > .line {
position: absolute;
background-color: $color-main;
width: 2px;
left: 17px;
z-index: -1;
top: 44px;
bottom: -8px;
}
}
&:last-child > .user-wrapper > .line {
display: none;
}
.detail {
position: relative;
flex-grow: 1;
width: 100%;
border-radius: 2px;
overflow: hidden;
& > td {
padding-top: 16px;
padding-bottom: 16px;
& > .header {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
&.action > .chip {
display: inline-block;
& > .chip {
padding: 2px 4px;
border-radius: 4px;
display: inline-block;
color: $color-font-bg;
&.notice {
background-color: $color-notice-medium;
}
&.date {
color: $color-font-secondary;
text-transform: capitalize;
font-style: italic;
font-size: .9em;
&.success {
background-color: $color-success-medium;
}
&.warning {
background-color: $color-main-medium;
}
&.alert {
background-color: lighten($color-alert, 5%);
}
}
&.change-header > td {
padding-bottom: 0;
.date {
float: right;
}
&.change-detail > td {
padding-top: 6px;
vertical-align: top;
}
& > .model {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
& > .model-name {
text-transform: capitalize;
}
& > .model-value {
font-style: italic;
color: #c7bd2b;
}
& > .model-id {
color: $color-font-secondary;
font-size: .9em;
}
}
}
th, td {
&.action,
&.user {
width: 90px;
}
&.date {
width: 115px;
text-align: right;
}
}
}
.model-name {
text-transform: capitalize;
}
.model-value {
font-style: italic;
color: #c7bd2b;
}
.model-id {
color: $color-font-secondary;
font-size: .9em;
}
.changes {
overflow: hidden;
@ -133,5 +170,4 @@ vn-log {
}
}
}
.filter {}
}