1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-19 13:19:43 +02:00

user/account store loading

This commit is contained in:
Harvey Kandola 2017-10-03 17:52:03 -04:00
parent 620fe28b27
commit f5f30d2322
27 changed files with 238 additions and 221 deletions

View file

@ -46,7 +46,7 @@ func (s Scope) Add(ctx domain.RequestContext, account account.Account) (err erro
// GetUserAccount returns the database account record corresponding to the given userID, using the client's current organizaion.
func (s Scope) GetUserAccount(ctx domain.RequestContext, userID string) (account account.Account, err error) {
err = s.Runtime.Db.Get(&account, `
SELECT a.id, a.refid, a.orgid, a.userid, a.editor, a.admin, a.active, a.created, a.revised,
SELECT a.id, a.refid, a.orgid, a.userid, a.editor, a.admin, a.users, a.active, a.created, a.revised,
b.company, b.title, b.message, b.domain
FROM account a, organization b
WHERE b.refid=a.orgid AND a.orgid=? AND a.userid=?`, ctx.OrgID, userID)
@ -61,7 +61,7 @@ func (s Scope) GetUserAccount(ctx domain.RequestContext, userID string) (account
// GetUserAccounts returns a slice of database account records, for all organizations that the userID is a member of, in organization title order.
func (s Scope) GetUserAccounts(ctx domain.RequestContext, userID string) (t []account.Account, err error) {
err = s.Runtime.Db.Select(&t, `
SELECT a.id, a.refid, a.orgid, a.userid, a.editor, a.admin, a.active, a.created, a.revised,
SELECT a.id, a.refid, a.orgid, a.userid, a.editor, a.admin, a.users, a.active, a.created, a.revised,
b.company, b.title, b.message, b.domain
FROM account a, organization b
WHERE a.userid=? AND a.orgid=b.refid AND a.active=1 ORDER BY b.title`, userID)
@ -76,7 +76,7 @@ func (s Scope) GetUserAccounts(ctx domain.RequestContext, userID string) (t []ac
// GetAccountsByOrg returns a slice of database account records, for all users in the client's organization.
func (s Scope) GetAccountsByOrg(ctx domain.RequestContext) (t []account.Account, err error) {
err = s.Runtime.Db.Select(&t,
`SELECT a.id, a.refid, a.orgid, a.userid, a.editor, a.admin, a.active, a.created, a.revised,
`SELECT a.id, a.refid, a.orgid, a.userid, a.editor, a.admin, a.users, a.active, a.created, a.revised,
b.company, b.title, b.message, b.domain
FROM account a, organization b
WHERE a.orgid=b.refid AND a.orgid=? AND a.active=1`, ctx.OrgID)

View file

@ -136,7 +136,7 @@ func (h *Handler) SetSpacePermissions(w http.ResponseWriter, r *http.Request) {
// Only persist if there is a role!
if permission.HasAnyPermission(perm) {
// identify publically shared spaces
if len(perm.UserID) == 0 {
if perm.UserID == "0" {
hasEveryoneRole = true
}
@ -156,7 +156,7 @@ func (h *Handler) SetSpacePermissions(w http.ResponseWriter, r *http.Request) {
if _, isExisting := previousRoleUsers[perm.UserID]; !isExisting {
// we skip 'everyone' (user id != empty string)
if len(perm.UserID) > 0 {
if perm.UserID != "0" {
existingUser, err := h.Store.User.Get(ctx, perm.UserID)
if err != nil {
response.WriteServerError(w, method, err)

View file

@ -59,11 +59,11 @@ func (s Scope) AddPermissions(ctx domain.RequestContext, r permission.Permission
func (s Scope) GetUserSpacePermissions(ctx domain.RequestContext, spaceID string) (r []permission.Permission, err error) {
err = s.Runtime.Db.Select(&r, `
SELECT id, orgid, who, whoid, action, scope, location, refid
FROM permission WHERE orgid=? AND location='space' AND refid=? AND who='user' AND (whoid=? OR whoid='')
FROM permission WHERE orgid=? AND location='space' AND refid=? AND who='user' AND (whoid=? OR whoid='0')
UNION ALL
SELECT p.id, p.orgid, p.who, p.whoid, p.action, p.scope, p.location, p.refid
FROM permission p LEFT JOIN rolemember r ON p.whoid=r.roleid WHERE p.orgid=? AND p.location='space' AND refid=?
AND p.who='role' AND (r.userid=? OR r.userid='')`,
AND p.who='role' AND (r.userid=? OR r.userid='0')`,
ctx.OrgID, spaceID, ctx.UserID, ctx.OrgID, spaceID, ctx.OrgID)
if err == sql.ErrNoRows {

View file

@ -278,7 +278,6 @@ func (h *Handler) GetSpaceUsers(w http.ResponseWriter, r *http.Request) {
}
// Get user account as we need to know if user can see all users.
// account.users == false means we restrict viewing to just space users
account, err := h.Store.Account.GetUserAccount(ctx, ctx.UserID)
if err != nil && err != sql.ErrNoRows {
response.WriteJSON(w, u)
@ -286,6 +285,7 @@ func (h *Handler) GetSpaceUsers(w http.ResponseWriter, r *http.Request) {
return
}
// account.users == false means we restrict viewing to just space users
if account.Users {
// can see all users
u, err = h.Store.User.GetActiveUsersForOrganization(ctx)

View file

@ -109,9 +109,11 @@ func (s Scope) GetBySerial(ctx domain.RequestContext, serial string) (u user.Use
// identified in the Persister.
func (s Scope) GetActiveUsersForOrganization(ctx domain.RequestContext) (u []user.User, err error) {
err = s.Runtime.Db.Select(&u,
`SELECT u.id, u.refid, u.firstname, u.lastname, u.email, u.initials, u.password, u.salt, u.reset, u.created, u.revised
FROM user u
WHERE u.refid IN (SELECT userid FROM account WHERE orgid = ? AND active=1) ORDER BY u.firstname,u.lastname`,
`SELECT u.id, u.refid, u.firstname, u.lastname, u.email, u.initials, u.password, u.salt, u.reset, u.created, u.revised,
u.global, a.active, a.editor, a.admin, a.users as viewusers
FROM user u, account a
WHERE u.refid=a.userid AND a.orgid=? AND a.active=1
ORDER BY u.firstname,u.lastname`,
ctx.OrgID)
if err != nil {
@ -125,9 +127,11 @@ func (s Scope) GetActiveUsersForOrganization(ctx domain.RequestContext) (u []use
// identified in the Persister.
func (s Scope) GetUsersForOrganization(ctx domain.RequestContext) (u []user.User, err error) {
err = s.Runtime.Db.Select(&u,
`SELECT id, refid, firstname, lastname, email, initials, password, salt, reset, created, revised
FROM user WHERE refid IN (SELECT userid FROM account where orgid = ?)
ORDER BY firstname,lastname`, ctx.OrgID)
`SELECT u.id, u.refid, u.firstname, u.lastname, u.email, u.initials, u.password, u.salt, u.reset, u.created, u.revised,
u.global, a.active, a.editor, a.admin, a.users as viewusers
FROM user u, account a
WHERE u.refid=a.userid AND a.orgid=?
ORDER BY u.firstname, u.lastname`, ctx.OrgID)
if err != nil {
err = errors.Wrap(err, fmt.Sprintf(" get users for org %s", ctx.OrgID))

View file

@ -11,11 +11,12 @@
import Ember from 'ember';
import AuthProvider from '../../mixins/auth';
import DropdownMixin from '../../mixins/dropdown';
export default Ember.Component.extend(AuthProvider, {
export default Ember.Component.extend(AuthProvider, DropdownMixin, {
editUser: null,
deleteUser: null,
drop: null,
dropdown: null,
password: {},
filter: '',
filteredUsers: [],
@ -23,20 +24,22 @@ export default Ember.Component.extend(AuthProvider, {
hasSelectedUsers: false,
didReceiveAttrs() {
this.users.forEach(user => {
this._super(...arguments);
let users = this.get('users');
users.forEach(user => {
user.set('me', user.get('id') === this.get('session.session.authenticated.user.id'));
user.set('selected', false);
});
this.set('filteredUsers', this.users);
this.set('users', users);
this.set('filteredUsers', users);
},
willDestroyElement() {
let drop = this.get('drop');
if (is.not.null(drop)) {
drop.destroy();
}
this._super(...arguments);
this.destroyDropdown();
},
onKeywordChange: function () {
@ -109,6 +112,8 @@ export default Ember.Component.extend(AuthProvider, {
$(".edit-user-dialog").css("display", "block");
$("input").removeClass("error");
this.closeDropdown();
let drop = new Drop({
target: $(".edit-button-" + id)[0],
content: $(".edit-user-dialog")[0],
@ -122,7 +127,7 @@ export default Ember.Component.extend(AuthProvider, {
remove: false
});
self.set('drop', drop);
self.set('dropdown', drop);
drop.on('open', function () {
self.$("#edit-firstname").focus();
@ -134,6 +139,8 @@ export default Ember.Component.extend(AuthProvider, {
this.set('deleteUser', user);
$(".delete-user-dialog").css("display", "block");
this.closeDropdown();
let drop = new Drop({
target: $(".delete-button-" + id)[0],
content: $(".delete-user-dialog")[0],
@ -147,12 +154,11 @@ export default Ember.Component.extend(AuthProvider, {
remove: false
});
this.set('drop', drop);
this.set('dropdown', drop);
},
cancel() {
let drop = this.get('drop');
drop.close();
this.closeDropdown();
},
save() {
@ -172,8 +178,7 @@ export default Ember.Component.extend(AuthProvider, {
return;
}
let drop = this.get('drop');
drop.close();
this.closeDropdown();
this.attrs.onSave(user);

View file

@ -10,9 +10,9 @@
// https://documize.com
import Ember from 'ember';
import tocUtil from '../../utils/toc';
import NotifierMixin from '../../mixins/notifier';
import TooltipMixin from '../../mixins/tooltip';
import tocUtil from '../../utils/toc';
export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
document: {},
@ -30,7 +30,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
return this.get('pages.length') === 0;
}),
didReceiveAttrs: function () {
didReceiveAttrs() {
this._super(...arguments);
this.set('showToc', is.not.undefined(this.get('pages')) && this.get('pages').get('length') > 0);
@ -40,7 +40,7 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
}
},
didRender: function () {
didRender() {
this._super(...arguments);
if (this.session.authenticated) {

View file

@ -0,0 +1,50 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import Ember from 'ember';
import NotifierMixin from '../../mixins/notifier';
import TooltipMixin from '../../mixins/tooltip';
export default Ember.Component.extend(NotifierMixin, TooltipMixin, {
tab: 'index',
didRender() {
this._super(...arguments);
if (this.get('permissions.documentEdit')) {
this.addTooltip(document.getElementById("document-index-button"));
this.addTooltip(document.getElementById("document-activity-button"));
}
},
willDestroyElement() {
this._super(...arguments);
this.destroyTooltips();
},
actions: {
onTabSwitch(tab) {
this.set('tab', tab);
},
onPageSequenceChange(changes) {
this.attrs.onPageSequenceChange(changes);
},
onPageLevelChange(changes) {
this.attrs.onPageLevelChange(changes);
},
onGotoPage(id) {
this.attrs.onGotoPage(id);
}
}
});

View file

@ -54,7 +54,7 @@ export default Ember.Component.extend(NotifierMixin, {
let u = {
orgId: this.get('folder.orgId'),
folderId: this.get('folder.id'),
userId: '',
userId: '0',
fullname: ' Everyone',
spaceView: false,
spaceManage: false,
@ -95,7 +95,7 @@ export default Ember.Component.extend(NotifierMixin, {
let payload = { Message: message, Permissions: permissions };
let hasEveryone = _.find(permissions, function (permission) {
return permission.get('userId') === "" &&
return permission.get('userId') === "0" &&
(permission.get('spaceView') || permission.get('documentAdd') || permission.get('documentEdit') || permission.get('documentDelete') ||
permission.get('documentMove') || permission.get('documentCopy') || permission.get('documentTemplate'));
});

View file

@ -39,6 +39,14 @@ export default Ember.Component.extend(NotifierMixin, TooltipMixin, AuthMixin, {
this.set('selectedDocuments', []);
},
didRender() {
this._super(...arguments);
if (this.get('rootDocCount') > 0) {
this.addTooltip(document.getElementById("uncategorized-button"));
}
},
willDestroyElement() {
this._super(...arguments);

View file

@ -18,7 +18,7 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
global: Ember.inject.service('global'),
appMeta: Ember.inject.service(),
beforeModel: function () {
beforeModel () {
if (!this.session.isAdmin) {
this.transitionTo('auth.login');
}
@ -33,14 +33,14 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
});
});
} else {
this.get('userService').getComplete().then((users) =>{
this.get('userService').getComplete().then((users) => {
resolve(users);
});
}
});
},
activate: function () {
activate() {
document.title = "Users | Documize";
}
});

View file

@ -11,8 +11,9 @@
import Ember from 'ember';
import NotifierMixin from '../../../mixins/notifier';
import TooltipMixin from '../../../mixins/tooltip';
export default Ember.Controller.extend(NotifierMixin, {
export default Ember.Controller.extend(NotifierMixin, TooltipMixin, {
documentService: Ember.inject.service('document'),
templateService: Ember.inject.service('template'),
sectionService: Ember.inject.service('section'),
@ -25,10 +26,6 @@ export default Ember.Controller.extend(NotifierMixin, {
tab: 'index',
actions: {
toggleSidebar() {
this.set('toggled', !this.get('toggled'));
},
onSaveDocument(doc) {
this.get('documentService').save(doc);
this.showNotification('Saved');

View file

@ -1,15 +1,15 @@
{{#layout/zone-container}}
{{#layout/zone-sidebar}}
{{document/document-index
{{document/document-sidebar tab=tab
document=model.document folder=model.folder pages=model.pages page=model.page permissions=model.permissions
onPageSequenceChange=(action 'onPageSequenceChange') onPageLevelChange=(action 'onPageLevelChange')
onGotoPage=(action 'onGotoPage')}}
{{/layout/zone-sidebar}}
{{#layout/zone-content}}
<div id="zone-document-content" class="zone-document-content">
<div id="zone-document-content" class="zone-document-content">
<div class="document-header-zone">
<div class="pull-left">
{{document/space-category document=model.document folder=model.folder folders=model.folders permissions=model.permissions}}
@ -39,8 +39,8 @@
onSavePage=(action 'onSavePage') onInsertSection=(action 'onInsertSection')
onSavePageAsBlock=(action 'onSavePageAsBlock') onDeleteBlock=(action 'onDeleteBlock') onGotoPage=(action 'onGotoPage')
onCopyPage=(action 'onCopyPage') onMovePage=(action 'onMovePage') onDeletePage=(action 'onPageDeleted')}}
</div>
{{/layout/zone-content}}
{{/layout/zone-container}}

View file

@ -46,8 +46,5 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, {
});
model.rootDocCount = rootDocCount;
console.log('afterModel');
}
});

View file

@ -13,7 +13,6 @@
@import "mixins.scss";
@import "base.scss";
@import "widget/widget.scss";
@import "view/layout-navigation.scss";
@import "view/layout-sidebar.scss";
@import "view/page-search.scss";
@import "view/page-profile.scss";

View file

@ -38,15 +38,30 @@ $color-border: #f3f5f8;
$color-checkbox: #0092d3;
// lightblue sidebar
$color-sidebar: #f2faff;
$color-sidebar-border: #dff0f9;
// gray sidebar
$color-sidebar: #f5f5f5;
$color-sidebar-border: #e1e1e1;
$color-sidebar-text: $color-black;
$color-sidebar-link: $color-link;
$color-nav-button: $color-sidebar;
$color-nav-button: #f2faff;
$color-nav-button-text: #2667af;
$color-nav-button-border: #dff0f9;
$color-selected-item: $color-sidebar;
$color-sidebar-navigation: #f2faff;
$color-sidebar-navigation-border: #dff0f9;
$color-sidebar-toolbar: $color-sidebar-border;
// lightblue sidebar
// $color-sidebar: #f2faff;
// $color-sidebar-border: #dff0f9;
// $color-sidebar-text: $color-black;
// $color-sidebar-link: $color-link;
// $color-nav-button: $color-sidebar;
// $color-nav-button-text: #2667af;
// $color-nav-button-border: #dff0f9;
// $color-selected-item: $color-sidebar;
// $color-sidebar-navigation: $color-gray;
// $color-sidebar-toolbar: $color-sidebar-border;
// black sidebar
// $color-sidebar: $color-off-black;

View file

@ -1,121 +0,0 @@
.zone-navigation {
position: fixed;
top: 0;
right: 0;
width: 60px;
min-height: 100%;
height: 100%;
margin: 0;
padding: 0;
z-index: 999;
overflow-x: hidden;
background: $color-toolbar;
> .bottom-zone,
> .top-zone {
position: absolute;
padding: 0;
width: 100%;
> li {
cursor: pointer;
margin: 0;
padding: 10px 0;
width: 100%;
text-align: center;
}
.round-button-mono {
> .material-icons {
color: $color-gray;
@include ease-in();
}
&:hover {
> .material-icons {
color: $color-link;
}
}
}
.profile-link {
color: $color-primary;
text-align: center;
font-size: 1rem;
font-style: normal;
font-family: $font-regular;
vertical-align: top;
}
.selected {
.round-button-mono {
background-color: $color-link !important;
border: 1px solid $color-link !important;
> .material-icons {
color: $color-white !important;
}
> a {
> .material-icons {
color: $color-white !important;
}
}
}
}
}
> .top-zone {
top: 0;
padding-top: 30px;
}
> .bottom-zone {
bottom: 0;
padding-bottom: 30px;
}
.pinned-zone {
position: relative;
top: 200px;
padding: 0;
margin: 0;
width: 80px;
overflow-x: hidden;
overflow-y: scroll;
> .pin {
cursor: pointer;
margin: 20px 0 20px 9px;
padding: 14px 3px;
height: 40px;
width: 40px;
text-align: center;
overflow: hidden;
@include ease-in();
@include border-radius(3px);
font-family: $font-semibold;
font-size: 12px;
letter-spacing: -1px;
background-color: $color-gray;
color: $color-white;
> .key {
width: 30px;
text-align: center;
display: inline-block;
overflow: hidden;
}
&:hover {
background-color: $color-link;
color: $color-white;
}
}
> .sortable-ghost {
background-color: $color-gray;
color: $color-off-white;
}
}
}

View file

@ -98,15 +98,16 @@ $sidebar-width: 400px;
> .title {
color: $color-primary;
font-size: 1.1rem;
margin-bottom: 30px;
font-size: 1.2rem;
margin-bottom: 30px;
font-weight: bold;
}
.document-sidebar-form-wrapper {
padding: 20px;
border: 1px solid $color-stroke;
@include border-radius(3px);
background-color: $color-white;
@include border-radius(3px);
}
}
@ -120,8 +121,11 @@ $sidebar-width: 400px;
}
.navigation {
margin: 15px 0 0 0;
text-align: center;
margin: 0 0 0 0;
padding: 10px 0;
text-align: center;
background-color: $color-sidebar-navigation;
border-bottom: 1px solid $color-sidebar-navigation-border;
.round-button-mono {
> .material-icons {
@ -145,3 +149,42 @@ $sidebar-width: 400px;
vertical-align: top;
}
}
.document-sidebar-toolbar {
margin: 10px 0 0 0;
padding: 10px 0;
text-align: center;
// background-color: $color-sidebar-toolbar;
> .round-button-mono {
background-color: $color-white;
border-color: $color-sidebar-border;
> .material-icons {
color: $color-gray;
@include ease-in();
}
&:hover {
> .material-icons {
color: $color-link;
}
}
}
> .selected {
background-color: $color-primary;
border-color: $color-primary;
> .material-icons {
color: $color-off-white;
@include ease-in();
}
&:hover {
> .material-icons {
color: $color-white;
}
}
}
}

View file

@ -29,34 +29,30 @@
</tr>
</thead>
<tbody>
{{#each filteredUsers as |user|}}
{{#each users as |user|}}
<tr>
<td class="{{unless user.active 'inactive-user'}} {{if user.admin 'admin-user'}}">
<div class="selector pull-left">
{{#unless user.me}}
{{#if user.selected}}
<i class="material-icons checkbox" {{action 'toggleSelect' user}}>check_box</i>
{{else}}
<i class="material-icons checkbox" {{action 'toggleSelect' user}}>check_box_outline_blank</i>
{{/if}}
{{/unless}}
{{#if user.selected}}
<i class="material-icons checkbox" {{action 'toggleSelect' user}}>check_box</i>
{{else if user.me}}
<i class="material-icons color-gray">check_box_outline_blank</i>
{{else}}
<i class="material-icons checkbox" {{action 'toggleSelect' user}}>check_box_outline_blank</i>
{{/if}}
</div>
<div class="name">{{ user.fullname }}</div>
<div class="email">{{ user.email }}</div>
</td>
<td class="no-width text-center">
{{#if user.me}}
<i class="material-icons color-gray">check_box</i>
{{else if user.editor}}
{{#if user.editor}}
<i class="material-icons checkbox" {{action 'toggleEditor' user.id}}>check_box</i>
{{else}}
<i class="material-icons checkbox" {{action 'toggleEditor' user.id}}>check_box_outline_blank</i>
{{/if}}
</td>
<td class="no-width text-center">
{{#if user.me}}
<i class="material-icons color-gray">check_box</i>
{{else if user.viewUsers}}
{{#if user.viewUsers}}
<i class="material-icons checkbox" {{action 'toggleUsers' user.id}}>check_box</i>
{{else}}
<i class="material-icons checkbox" {{action 'toggleUsers' user.id}}>check_box_outline_blank</i>

View file

@ -0,0 +1,18 @@
<div class="sidebar-wrapper">
<div class="sidebar-panel">
<div class="title">Activity</div>
<div class="document-sidebar-view-activity">
<ul class="items">
{{#each activity as |a|}}
<li class="item">
<div class="avatar-box">
<div class="avatar">{{user-initials a.firstname a.lastname}}</div>
</div>
<div class="name">{{a.firstname}} {{a.lastname}}</div>
<div class="detail {{a.activityColor}}">{{a.activityLabel}}, {{time-ago a.created}}</div>
</li>
{{/each}}
</ul>
</div>
</div>
</div>

View file

@ -1,5 +1,6 @@
<div class="sidebar-wrapper">
<div class="sidebar-panel">
<div class="title">Index</div>
<div class="document-sidebar-view-index">
<div class="structure">
{{#if session.authenticated}}

View file

@ -0,0 +1,27 @@
{{#if permissions.documentEdit}}
<div class="document-sidebar-toolbar">
<div class="round-button-mono button-white {{if (eq tab 'index') 'selected'}}" id="document-index-button" data-tooltip="Index" data-tooltip-position="bottom center" {{action 'onTabSwitch' 'index'}}>
<i class="material-icons">view_headline</i>
</div>
<div class="button-gap" />
<div class="round-button-mono button-white {{if (eq tab 'activity') 'selected'}}" id="document-activity-button" data-tooltip="Activity" data-tooltip-position="bottom center" {{action 'onTabSwitch' 'activity'}}>
<i class="material-icons">timeline</i>
</div>
</div>
{{/if}}
{{#if (is-equal tab 'index')}}
{{document/document-index
document=document
folder=folder
pages=pages
page=page
permissions=permissions
onPageSequenceChange=(action 'onPageSequenceChange')
onPageLevelChange=(action 'onPageLevelChange')
onGotoPage=(action 'onGotoPage')}}
{{/if}}
{{#if (is-equal tab 'activity')}}
{{document/document-activity document=document pages=pages permissions=permissions}}
{{/if}}

View file

@ -1,10 +1,3 @@
{{#if (is-equal tab 'activitysdsd')}}
{{document/sidebar-view-activity document=document pages=pages permissions=permissions}}
{{/if}}
<div class="document-toolbar">
<div class="round-button-mono" id="document-more-button">
<i class="material-icons">more_vert</i>

View file

@ -1,16 +0,0 @@
<div class="sidebar-panel">
<div class="title">Activity</div>
<div class="document-sidebar-view-activity">
<ul class="items">
{{#each activity as |a|}}
<li class="item">
<div class="avatar-box">
<div class="avatar">{{user-initials a.firstname a.lastname}}</div>
</div>
<div class="name">{{a.firstname}} {{a.lastname}}</div>
<div class="detail {{a.activityColor}}">{{a.activityLabel}}, {{time-ago a.created}}</div>
</li>
{{/each}}
</ul>
</div>
</div>

View file

@ -41,6 +41,7 @@
{{/if}}
{{else}}
{{#link-to 'auth.login'}}
<div class="button-gap" />
<div class="round-button-mono button-white">
<i class="material-icons">lock_open</i>
</div>