231801_test_to_master #1519
|
@ -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', () => {
|
||||
|
|
|
@ -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'}"
|
||||
|
|
|
@ -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
|
||||
];
|
||||
|
|
|
@ -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 {}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue