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

View File

@ -14,111 +14,105 @@
order="changedModel" order="changedModel"
auto-load="true"> auto-load="true">
</vn-crud-model> </vn-crud-model>
<vn-data-viewer model="model" class="vn-w-md"> <vn-data-viewer model="model" class="vn-w-md vn-px-sm">
<vn-card> <div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs">
<table class="vn-table" model="model"> <div class="user-wrapper">
<thead> <div
<tr> class="user vn-mt-xs"
<th translate field="action" class="action"> title="{{::log.user.nickname || 'System'}}">
Action <img
</th> ng-if="::log.user.worker"
<th field="changedModel"> src="/api/Images/user/160x160/{{::log.user.worker.id}}/download?access_token={{::$ctrl.vnToken.token}}"
<span ng-if="$ctrl.showModelName" translate>Model</span> ng-click="$ctrl.showWorkerDescriptor($event, log.user.worker.id)">
</th> </img>
<th translate field="creationDate" class="date"> <div
Date ng-if="::!log.user.worker"
</th> ng-class="::{system: !log.user}"
</tr> ng-style="::$ctrl.userBgColor(log.user)"
</thead> class="user-icon">
<tbody ng-repeat="log in $ctrl.logs"> {{::log.user ? log.user.name.charAt(0).toUpperCase() : 'S'}}
<tr class="change-header"> </div>
<td class="user"> </div>
<span ng-if="::log.user.worker.id" <div class="arrow bg-panel"></div>
class="link" <div class="line"></div>
ng-click="$ctrl.showWorkerDescriptor($event, log.user.worker.id)"> </div>
{{::log.user.name}} <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>
<span ng-if="::!log.user.worker.id" translate> <div ng-if="log.expand"
System class="expanded-json">
</span> <div ng-repeat="prop in ::log.props">
</td> <span class="json-field"
<td title="{{::log.changedModelValue}}"> title="{{::prop.name}}">
<span class="model-name" {{::prop.nameI18n}}:
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>
</span> </span>
<span ng-if="::!log.props.length" <vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value>
class="description"> <span ng-if="::log.action == 'update'">
{{::log.description}} <vn-json-value value="::prop.old"></vn-json-value>
</span>
<span ng-if="::!log.description && !log.props.length"
class="no-changes"
translate>
No changes
</span> </span>
</div> </div>
</div> </div>
</td> </span>
</tr> <span ng-if="::!log.props.length"
</tbody> class="description">
</table> {{::log.description}}
<vn-pagination model="model"></vn-pagination> </span>
</vn-card> <span ng-if="::!log.description && !log.props.length"
class="no-changes"
translate>
No changes
</span>
</div>
</vn-card>
</div>
</div>
</vn-data-viewer> </vn-data-viewer>
<vn-pagination model="model"></vn-pagination>
<vn-side-menu side="right"> <vn-side-menu side="right">
<form vn-vertical <form vn-vertical
ng-model-options="{updateOn: 'change blur'}" ng-model-options="{updateOn: 'change blur'}"

View File

@ -23,7 +23,7 @@ export default class Controller extends Section {
include: [{ include: [{
relation: 'user', relation: 'user',
scope: { scope: {
fields: ['name'], fields: ['nickname'],
include: { include: {
relation: 'worker', relation: 'worker',
scope: { 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', { ngModule.vnComponent('vnLog', {
@ -213,3 +224,29 @@ ngModule.vnComponent('vnLog', {
url: '@' 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"; @import "variables";
vn-log { vn-log {
.vn-table { .change {
table-layout: fixed; display: flex;
& > thead, & > .user-wrapper {
& > tbody { position: relative;
& > tr { padding-right: 10px;
td, th {
&:first-child { & > .user {
padding-left: 16px; border-radius: 50%;
} height: 36px;
&:last-child { width: 36px;
padding-right: 16px; 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;
} }
} }
} }
} & > .arrow {
& > thead > tr > th { height: 8px;
max-width: initial; width: 8px;
} position: absolute;
& > tbody { transform: rotateY(0deg) rotate(45deg);
border-bottom: 1px solid rgba(0, 0, 0, 0.3); top: 18px;
right: -4px;
&:last-child { z-index: 1;
border-bottom: none;
} }
& > tr { & > .line {
border-bottom: none; position: absolute;
height: initial; 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 { & > .header {
padding-top: 16px; overflow: hidden;
padding-bottom: 16px; text-overflow: ellipsis;
white-space: nowrap;
&.action > .chip { & > .chip {
display: inline-block; padding: 2px 4px;
border-radius: 4px;
display: inline-block;
color: $color-font-bg;
&.notice {
background-color: $color-notice-medium;
} }
&.date { &.success {
color: $color-font-secondary; background-color: $color-success-medium;
text-transform: capitalize; }
font-style: italic; &.warning {
font-size: .9em; background-color: $color-main-medium;
}
&.alert {
background-color: lighten($color-alert, 5%);
} }
} }
&.change-header > td { .date {
padding-bottom: 0; float: right;
} }
&.change-detail > td { }
padding-top: 6px; & > .model {
vertical-align: top; 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 { .changes {
overflow: hidden; overflow: hidden;
@ -133,5 +170,4 @@ vn-log {
} }
} }
} }
.filter {}
} }