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

clone space!

This commit is contained in:
Harvey Kandola 2017-08-21 17:51:06 +01:00
parent 866b4eba8a
commit bf390ed0b9
18 changed files with 302 additions and 108 deletions

View file

@ -12,6 +12,7 @@
package mysql package mysql
import ( import (
"database/sql"
"fmt" "fmt"
"time" "time"
@ -199,6 +200,11 @@ func (s Scope) TemplatesBySpace(ctx domain.RequestContext, spaceID string) (docu
ctx.OrgID, ctx.OrgID,
ctx.UserID) ctx.UserID)
if err == sql.ErrNoRows {
err = nil
documents = []doc.Document{}
}
if err != nil { if err != nil {
err = errors.Wrap(err, "select space document templates") err = errors.Wrap(err, "select space document templates")
return return
@ -241,6 +247,11 @@ func (s Scope) DocumentList(ctx domain.RequestContext) (documents []doc.Document
ctx.OrgID, ctx.OrgID,
ctx.UserID) ctx.UserID)
if err == sql.ErrNoRows {
err = nil
documents = []doc.Document{}
}
if err != nil { if err != nil {
err = errors.Wrap(err, "select documents list") err = errors.Wrap(err, "select documents list")
return return

View file

@ -13,6 +13,7 @@ package mysql
import ( import (
"fmt" "fmt"
"strings"
"time" "time"
"github.com/documize/community/core/env" "github.com/documize/community/core/env"
@ -162,15 +163,18 @@ func (s Scope) DeleteLink(ctx domain.RequestContext, id string) (rows int64, err
// SearchCandidates returns matching documents, sections and attachments using keywords. // SearchCandidates returns matching documents, sections and attachments using keywords.
func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (docs []link.Candidate, func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (docs []link.Candidate,
pages []link.Candidate, attachments []link.Candidate, err error) { pages []link.Candidate, attachments []link.Candidate, err error) {
// find matching documents // find matching documents
temp := []link.Candidate{} temp := []link.Candidate{}
likeQuery := "title LIKE '%" + keywords + "%'" keywords = strings.TrimSpace(strings.ToLower(keywords))
likeQuery := "LOWER(title) LIKE '%" + keywords + "%'"
err = s.Runtime.Db.Select(&temp, err = s.Runtime.Db.Select(&temp,
`SELECT refid as documentid, labelid as folderid,title from document WHERE orgid=? AND `+likeQuery+` AND labelid IN `SELECT d.refid as documentid, d. labelid as folderid, d.title, l.label as context
(SELECT refid from label WHERE orgid=? AND type=2 AND userid=? FROM document d LEFT JOIN label l ON d.labelid=l.refid WHERE l.orgid=? AND `+likeQuery+` AND d.labelid IN
UNION ALL SELECT refid FROM label a where orgid=? AND type=1 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) (SELECT refid FROM label WHERE orgid=? AND type=2 AND userid=?
UNION ALL SELECT refid FROM label a where orgid=? AND type=3 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=1 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1))
UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=3 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1)))
ORDER BY title`, ORDER BY title`,
ctx.OrgID, ctx.OrgID,
ctx.OrgID, ctx.OrgID,
@ -194,22 +198,22 @@ func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (doc
TargetID: r.DocumentID, TargetID: r.DocumentID,
LinkType: "document", LinkType: "document",
Title: r.Title, Title: r.Title,
Context: "", Context: r.Context,
} }
docs = append(docs, c) docs = append(docs, c)
} }
// find matching sections // find matching sections
likeQuery = "p.title LIKE '%" + keywords + "%'" likeQuery = "LOWER(p.title) LIKE '%" + keywords + "%'"
temp = []link.Candidate{} temp = []link.Candidate{}
err = s.Runtime.Db.Select(&temp, err = s.Runtime.Db.Select(&temp,
`SELECT p.refid as targetid, p.documentid as documentid, p.title as title, p.pagetype as linktype, d.title as context, d.labelid as folderid from page p `SELECT p.refid as targetid, p.documentid as documentid, p.title as title, p.pagetype as linktype, d.title as context, d.labelid as folderid
LEFT JOIN document d ON d.refid=p.documentid WHERE p.orgid=? AND `+likeQuery+` AND d.labelid IN FROM page p LEFT JOIN document d ON d.refid=p.documentid WHERE p.orgid=? AND `+likeQuery+` AND d.labelid IN
(SELECT refid from label WHERE orgid=? AND type=2 AND userid=? (SELECT refid FROM label WHERE orgid=? AND type=2 AND userid=?
UNION ALL SELECT refid FROM label a where orgid=? AND type=1 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=1 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1))
UNION ALL SELECT refid FROM label a where orgid=? AND type=3 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=3 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1)))
ORDER BY p.title`, ORDER BY p.title`,
ctx.OrgID, ctx.OrgID,
ctx.OrgID, ctx.OrgID,
@ -240,15 +244,15 @@ func (s Scope) SearchCandidates(ctx domain.RequestContext, keywords string) (doc
} }
// find matching attachments // find matching attachments
likeQuery = "a.filename LIKE '%" + keywords + "%'" likeQuery = "LOWER(a.filename) LIKE '%" + keywords + "%'"
temp = []link.Candidate{} temp = []link.Candidate{}
err = s.Runtime.Db.Select(&temp, err = s.Runtime.Db.Select(&temp,
`SELECT a.refid as targetid, a.documentid as documentid, a.filename as title, a.extension as context, d.labelid as folderid from attachment a `SELECT a.refid as targetid, a.documentid as documentid, a.filename as title, a.extension as context, d.labelid as folderid
LEFT JOIN document d ON d.refid=a.documentid WHERE a.orgid=? AND `+likeQuery+` AND d.labelid IN FROM attachment a LEFT JOIN document d ON d.refid=a.documentid WHERE a.orgid=? AND `+likeQuery+` AND d.labelid IN
(SELECT refid from label WHERE orgid=? AND type=2 AND userid=? (SELECT refid FROM label WHERE orgid=? AND type=2 AND userid=?
UNION ALL SELECT refid FROM label a where orgid=? AND type=1 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1)) UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=1 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid='' AND (canedit=1 OR canview=1))
UNION ALL SELECT refid FROM label a where orgid=? AND type=3 AND refid IN (SELECT labelid from labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1))) UNION ALL SELECT refid FROM label a WHERE orgid=? AND type=3 AND refid IN (SELECT labelid FROM labelrole WHERE orgid=? AND userid=? AND (canedit=1 OR canview=1)))
ORDER BY a.filename`, ORDER BY a.filename`,
ctx.OrgID, ctx.OrgID,
ctx.OrgID, ctx.OrgID,

View file

@ -32,8 +32,11 @@ import (
"github.com/documize/community/domain/mail" "github.com/documize/community/domain/mail"
"github.com/documize/community/model/account" "github.com/documize/community/model/account"
"github.com/documize/community/model/audit" "github.com/documize/community/model/audit"
"github.com/documize/community/model/doc"
"github.com/documize/community/model/page"
"github.com/documize/community/model/space" "github.com/documize/community/model/space"
"github.com/documize/community/model/user" "github.com/documize/community/model/user"
uuid "github.com/nu7hatch/gouuid"
) )
// Handler contains the runtime information such as logging and database. // Handler contains the runtime information such as logging and database.
@ -65,15 +68,17 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
return return
} }
var sp = space.Space{} var model = space.NewSpaceRequest{}
err = json.Unmarshal(body, &sp) err = json.Unmarshal(body, &model)
if err != nil { if err != nil {
response.WriteServerError(w, method, err) response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err) h.Runtime.Log.Error(method, err)
return return
} }
if len(sp.Name) == 0 { model.Name = strings.TrimSpace(model.Name)
model.CloneID = strings.TrimSpace(model.CloneID)
if len(model.Name) == 0 {
response.WriteMissingDataError(w, method, "name") response.WriteMissingDataError(w, method, "name")
return return
} }
@ -85,6 +90,8 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
return return
} }
var sp space.Space
sp.Name = model.Name
sp.RefID = uniqueid.Generate() sp.RefID = uniqueid.Generate()
sp.OrgID = ctx.OrgID sp.OrgID = ctx.OrgID
sp.Type = space.ScopePrivate sp.Type = space.ScopePrivate
@ -118,8 +125,135 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
h.Store.Audit.Record(ctx, audit.EventTypeSpaceAdd) h.Store.Audit.Record(ctx, audit.EventTypeSpaceAdd)
// Get back new space
sp, _ = h.Store.Space.Get(ctx, sp.RefID) sp, _ = h.Store.Space.Get(ctx, sp.RefID)
fmt.Println(model)
// clone existing space?
if model.CloneID != "" && (model.CopyDocument || model.CopyPermission || model.CopyTemplate) {
ctx.Transaction, err = h.Runtime.Db.Beginx()
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
spCloneRoles, err := h.Store.Space.GetRoles(ctx, model.CloneID)
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
if model.CopyPermission {
for _, r := range spCloneRoles {
r.RefID = uniqueid.Generate()
r.LabelID = sp.RefID
err = h.Store.Space.AddRole(ctx, r)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
}
}
toCopy := []doc.Document{}
spCloneTemplates, err := h.Store.Document.TemplatesBySpace(ctx, model.CloneID)
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
toCopy = append(toCopy, spCloneTemplates...)
if model.CopyDocument {
docs, err := h.Store.Document.GetBySpace(ctx, model.CloneID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
toCopy = append(toCopy, docs...)
}
if len(toCopy) > 0 {
for _, t := range toCopy {
origID := t.RefID
documentID := uniqueid.Generate()
t.RefID = documentID
t.LabelID = sp.RefID
err = h.Store.Document.Add(ctx, t)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
pages, _ := h.Store.Page.GetPages(ctx, origID)
for _, p := range pages {
meta, err2 := h.Store.Page.GetPageMeta(ctx, p.RefID)
if err2 != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
p.DocumentID = documentID
pageID := uniqueid.Generate()
p.RefID = pageID
meta.PageID = pageID
meta.DocumentID = documentID
model := page.NewPage{}
model.Page = p
model.Meta = meta
err = h.Store.Page.Add(ctx, model)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
}
newUUID, _ := uuid.NewV4()
attachments, _ := h.Store.Attachment.GetAttachmentsWithData(ctx, origID)
for _, a := range attachments {
attachmentID := uniqueid.Generate()
a.RefID = attachmentID
a.DocumentID = documentID
a.Job = newUUID.String()
random := secrets.GenerateSalt()
a.FileID = random[0:9]
err = h.Store.Attachment.Add(ctx, a)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
}
}
}
ctx.Transaction.Commit()
}
response.WriteJSON(w, sp) response.WriteJSON(w, sp)
} }

View file

@ -24,9 +24,10 @@ export default Ember.Component.extend(TooltipMixin, NotifierMixin, AuthMixin, {
hasPrivateFolders: false, hasPrivateFolders: false,
newFolder: '', newFolder: '',
copyTemplate: true, copyTemplate: true,
copyBlock: true,
copyPermission: true, copyPermission: true,
copyDocument: false, copyDocument: false,
clonedSpace: { id: "" },
showSpace: false,
didReceiveAttrs() { didReceiveAttrs() {
let folders = this.get('folders'); let folders = this.get('folders');
@ -60,17 +61,42 @@ export default Ember.Component.extend(TooltipMixin, NotifierMixin, AuthMixin, {
}, },
actions: { actions: {
addFolder() { onToggleNewSpace() {
var folderName = this.get('newFolder'); let val = !this.get('showSpace');
this.set('showSpace', val);
if (val) {
Ember.run.schedule('afterRender', () => {
$("#new-folder-name").focus();
});
}
},
onCloneSpaceSelect(sp) {
this.set('clonedSpace', sp)
},
onAdd() {
let folderName = this.get('newFolder');
let clonedId = this.get('clonedSpace.id');
if (is.empty(folderName)) { if (is.empty(folderName)) {
$("#new-folder-name").addClass("error").focus(); $("#new-folder-name").addClass("error").focus();
return false; return false;
} }
this.attrs.onFolderAdd(folderName); let payload = {
name: folderName,
CloneID: clonedId,
copyTemplate: this.get('copyTemplate'),
copyPermission: this.get('copyPermission'),
copyDocument: this.get('copyDocument'),
}
this.attrs.onAddSpace(payload);
this.set('showSpace', false);
this.set('newFolder', ''); this.set('newFolder', '');
return true; return true;
} }
} }

View file

@ -51,13 +51,13 @@ export default Ember.Component.extend(TooltipMixin, NotifierMixin, AuthMixin, {
let folder = this.get('folder'); let folder = this.get('folder');
this.set('pinState.pinId', this.get('pinned').isSpacePinned(folder.get('id'))); this.set('pinState.pinId', this.get('pinned').isSpacePinned(folder.get('id')));
this.set('pinState.isPinned', this.get('pinState.pinId') !== ''); this.set('pinState.isPinned', this.get('pinState.pinId') !== '');
this.set('pinState.newName', folder.get('name').substring(0,3).toUpperCase()); this.set('pinState.newName', folder.get('name').substring(0,3).toUpperCase());
} }
}, },
actions: { actions: {
onFolderAdd(folderName) { onAddSpace(m) {
this.attrs.onFolderAdd(folderName); this.attrs.onAddSpace(m);
return true; return true;
}, },

View file

@ -62,11 +62,11 @@ export default Ember.Controller.extend(NotifierMixin, {
}); });
}, },
onFolderAdd(folder) { onAddSpace(payload) {
let self = this; let self = this;
this.showNotification("Added"); this.showNotification("Added");
this.get('folderService').add({ name: folder }).then(function (newFolder) { this.get('folderService').add(payload).then(function (newFolder) {
self.get('folderService').setCurrentFolder(newFolder); self.get('folderService').setCurrentFolder(newFolder);
self.transitionToRoute('folder', newFolder.get('id'), newFolder.get('slug')); self.transitionToRoute('folder', newFolder.get('id'), newFolder.get('slug'));
}); });

View file

@ -2,7 +2,7 @@
{{#layout/zone-container}} {{#layout/zone-container}}
{{#layout/zone-sidebar}} {{#layout/zone-sidebar}}
{{folder/sidebar-zone folders=model.folders folder=model.folder isFolderOwner=model.isFolderOwner isEditor=model.isEditor tab=tab {{folder/sidebar-zone folders=model.folders folder=model.folder isFolderOwner=model.isFolderOwner isEditor=model.isEditor tab=tab
onFolderAdd=(action 'onFolderAdd')}} onAddSpace=(action 'onAddSpace')}}
{{/layout/zone-sidebar}} {{/layout/zone-sidebar}}
{{#layout/zone-content}} {{#layout/zone-content}}
{{folder/folder-heading folder=model.folder isFolderOwner=model.isFolderOwner isEditor=model.isEditor}} {{folder/folder-heading folder=model.folder isFolderOwner=model.isFolderOwner isEditor=model.isEditor}}

View file

@ -16,11 +16,11 @@ export default Ember.Controller.extend(NotifierMixin, {
folderService: Ember.inject.service('folder'), folderService: Ember.inject.service('folder'),
actions: { actions: {
onFolderAdd(folder) { onAddSpace(m) {
let self = this; let self = this;
this.showNotification("Added"); this.showNotification("Added");
this.get('folderService').add({ name: folder }).then(function (newFolder) { this.get('folderService').add(m).then(function (newFolder) {
self.get('folderService').setCurrentFolder(newFolder); self.get('folderService').setCurrentFolder(newFolder);
self.transitionToRoute('folder', newFolder.get('id'), newFolder.get('slug')); self.transitionToRoute('folder', newFolder.get('id'), newFolder.get('slug'));
}); });

View file

@ -2,7 +2,7 @@
{{#layout/zone-container}} {{#layout/zone-container}}
{{#layout/zone-sidebar}} {{#layout/zone-sidebar}}
{{folder/sidebar-zone folders=model noFolder=true isFolderOwner=false isEditor=false {{folder/sidebar-zone folders=model noFolder=true isFolderOwner=false isEditor=false
onFolderAdd=(action 'onFolderAdd')}} onAddSpace=(action 'onAddSpace')}}
{{/layout/zone-sidebar}} {{/layout/zone-sidebar}}
{{#layout/zone-content}} {{#layout/zone-content}}
{{/layout/zone-content}} {{/layout/zone-content}}

View file

@ -29,10 +29,10 @@ export default BaseService.extend({
canEditCurrentFolder: false, canEditCurrentFolder: false,
// Add a new folder. // Add a new folder.
add(folder) { add(payload) {
return this.get('ajax').post(`folders`, { return this.get('ajax').post(`folders`, {
contentType: 'json', contentType: 'json',
data: JSON.stringify(folder) data: JSON.stringify(payload)
}).then((folder) => { }).then((folder) => {
let data = this.get('store').normalize('folder', folder); let data = this.get('store').normalize('folder', folder);
return this.get('store').push(data); return this.get('store').push(data);

View file

@ -5,7 +5,7 @@
.content-linker-dialog { .content-linker-dialog {
width: 350px; width: 350px;
height: 350px; height: 450px;
overflow-y: auto; overflow-y: auto;
.link-list { .link-list {

View file

@ -7,10 +7,9 @@
margin: 0 0 5px 0; margin: 0 0 5px 0;
> .material-icons { > .material-icons {
font-size: 1.4rem; font-size: 1rem;
color: $color-gray; color: $color-gray;
vertical-align: top; vertical-align: top;
margin-right: 5px;
} }
> .selected { > .selected {
@ -20,6 +19,13 @@
&:hover { &:hover {
color: $color-link; color: $color-link;
} }
> .text {
display: inline-block;
font-size: 0.9rem;
vertical-align: text-top;
color: $color-off-black;
}
} }
.ui-checkbox-selected { .ui-checkbox-selected {

View file

@ -189,6 +189,7 @@
pointer-events: none; pointer-events: none;
font-weight: bold; font-weight: bold;
color: $color-off-black; color: $color-off-black;
@extend .no-select;
} }
> .tip { > .tip {
@ -198,6 +199,7 @@
padding: 0; padding: 0;
font-family: $font-light; font-family: $font-light;
text-align: left; text-align: left;
@extend .no-select;
} }
} }

View file

@ -43,7 +43,7 @@
{{#each matches.documents as |m|}} {{#each matches.documents as |m|}}
<li class="link-item" {{ action 'setSelection' m }}> <li class="link-item" {{ action 'setSelection' m }}>
{{#ui/ui-selection selected=m.selected}} {{#ui/ui-selection selected=m.selected}}
{{m.title}} {{m.title}}<br/><span class="color-gray">{{m.context}}</span>
{{/ui/ui-selection}} {{/ui/ui-selection}}
</li> </li>
{{/each}} {{/each}}

View file

@ -1,74 +1,76 @@
<div class="sidebar-panel"> <div class="sidebar-panel">
<div class="folders-list"> <div class="folders-list">
{{#if session.isEditor}} {{#if session.isEditor}}
<div class="comment-box document-sidebar-form-wrapper"> {{#unless showSpace}}
<div class="input-control"> <div id="add-space-button" class="regular-button button-white" {{action "onToggleNewSpace"}}>
<label>New space</label> <i class="material-icons">add</i>
<div class="tip">A place for related documents</div> <div class="name">Space</div>
{{input type='text' id="new-folder-name" class="mousetrap" value=newFolder}}
<p>Copy existing space</p>
{{#ui/ui-checkbox selected=copyTemplate}}Templates{{/ui/ui-checkbox}}
{{#ui/ui-checkbox selected=copyBlock}}Reusable content{{/ui/ui-checkbox}}
{{#ui/ui-checkbox selected=copyPermission}}Permissions{{/ui/ui-checkbox}}
{{#ui/ui-checkbox selected=copyDocument}}Documents{{/ui/ui-checkbox}}
</div> </div>
<div class="regular-button button-blue">Add</div> {{else}}
</div> <div class="comment-box document-sidebar-form-wrapper">
<div id="add-space-button" class="regular-button button-white">
<i class="material-icons">add</i>
<div class="name">Space</div>
</div>
{{#dropdown-dialog target="add-space-button" position="bottom left" button="Add" color="flat-green" onAction=(action 'addFolder') focusOn="new-folder-name" }}
<div>
<div class="input-control"> <div class="input-control">
<label>New Space</label>
<div class="tip">Every space contains related documents</div>
{{input type='text' id="new-folder-name" class="mousetrap" value=newFolder}}
<p class="margin-top-30">Optionally, clone existing space</p>
{{ui-select id="owners-dropdown" content=folders prompt="select space" action=(action 'onCloneSpaceSelect') optionValuePath="id" optionLabelPath="name" selection=cloneSpace}}
<div class="margin-top-20" />
{{#ui/ui-checkbox selected=copyTemplate}}Templates{{/ui/ui-checkbox}}
{{#ui/ui-checkbox selected=copyPermission}}Permissions{{/ui/ui-checkbox}}
{{#ui/ui-checkbox selected=copyDocument}}Documents{{/ui/ui-checkbox}}
</div> </div>
<div class="regular-button button-blue" {{action "onAdd"}}>Add</div>
<div class="flat-button flat-gray" {{action "onToggleNewSpace"}}>Cancel</div>
</div> </div>
{{/dropdown-dialog}}
{{/if}}
<div class="section">
<div class="heading">EVERYONE</div>
{{#unless hasPublicFolders}}
<div class="message margin-left-15">No global spaces</div>
{{/unless}} {{/unless}}
<ul class="list">
{{#each publicFolders as |folder|}}
{{#link-to 'folder' folder.id folder.slug class="link" activeClass='selected' }}
<li class="item">{{ folder.name }}</li>
{{/link-to}}
{{/each}}
</ul>
</div>
{{#if session.authenticated}}
<div class="section">
<div class="heading">TEAM</div>
{{#unless hasProtectedFolders}}
<div class="message margin-left-15">No protected spaces</div>
{{/unless}}
<ul class="list">
{{#each protectedFolders as |folder|}}
{{#link-to 'folder' folder.id folder.slug class="link" activeClass='selected' }}
<li class="item">{{ folder.name }}</li>
{{/link-to}}
{{/each}}
</ul>
</div>
<div class="section">
<div class="heading">PERSONAL</div>
{{#unless hasPrivateFolders}}
<div class="message margin-left-15">No private spaces</div>
{{/unless}}
<ul class="list">
{{#each privateFolders as |folder|}}
{{#link-to 'folder' folder.id folder.slug class="link" activeClass='selected' }}
<li class="item">{{ folder.name }}</li>
{{/link-to}}
{{/each}}
</ul>
</div>
{{/if}} {{/if}}
{{#unless showSpace}}
<div class="section">
<div class="heading">EVERYONE</div>
{{#unless hasPublicFolders}}
<div class="message margin-left-15">No global spaces</div>
{{/unless}}
<ul class="list">
{{#each publicFolders as |folder|}}
{{#link-to 'folder' folder.id folder.slug class="link" activeClass='selected' }}
<li class="item">{{ folder.name }}</li>
{{/link-to}}
{{/each}}
</ul>
</div>
{{#if session.authenticated}}
<div class="section">
<div class="heading">TEAM</div>
{{#unless hasProtectedFolders}}
<div class="message margin-left-15">No protected spaces</div>
{{/unless}}
<ul class="list">
{{#each protectedFolders as |folder|}}
{{#link-to 'folder' folder.id folder.slug class="link" activeClass='selected' }}
<li class="item">{{ folder.name }}</li>
{{/link-to}}
{{/each}}
</ul>
</div>
<div class="section">
<div class="heading">PERSONAL</div>
{{#unless hasPrivateFolders}}
<div class="message margin-left-15">No private spaces</div>
{{/unless}}
<ul class="list">
{{#each privateFolders as |folder|}}
{{#link-to 'folder' folder.id folder.slug class="link" activeClass='selected' }}
<li class="item">{{ folder.name }}</li>
{{/link-to}}
{{/each}}
</ul>
</div>
{{/if}}
{{/unless}}
</div> </div>
</div> </div>

View file

@ -29,7 +29,7 @@
<li class="item" {{action 'onUnpin'}}>Unpin</li> <li class="item" {{action 'onUnpin'}}>Unpin</li>
{{else}} {{else}}
<li class="item" id="pin-space-button">Pin</li> <li class="item" id="pin-space-button">Pin</li>
{{/if}} {{/if}}
</ul> </ul>
{{/dropdown-menu}} {{/dropdown-menu}}
@ -54,14 +54,14 @@
<div class="sidebar-wrapper"> <div class="sidebar-wrapper">
{{#if (is-equal tab 'index')}} {{#if (is-equal tab 'index')}}
{{folder/sidebar-folders-list folders=folders folder=folder isFolderOwner=isFolderOwner onFolderAdd=(action 'onFolderAdd')}} {{folder/sidebar-folders-list folders=folders folder=folder isFolderOwner=isFolderOwner onAddSpace=(action 'onAddSpace')}}
{{/if}} {{/if}}
{{#if (is-equal tab 'share')}} {{#if (is-equal tab 'share')}}
{{folder/sidebar-share folders=folders folder=folder}} {{folder/sidebar-share folders=folders folder=folder}}
{{/if}} {{/if}}
{{#if (is-equal tab 'permissions')}} {{#if (is-equal tab 'permissions')}}
{{folder/sidebar-permissions folders=folders folder=folder}} {{folder/sidebar-permissions folders=folders folder=folder}}
{{/if}} {{/if}}
</div> </div>

View file

@ -4,5 +4,5 @@
{{else}} {{else}}
<i class="material-icons">check_box_outline_blank</i> <i class="material-icons">check_box_outline_blank</i>
{{/if}} {{/if}}
{{yield}} <div class="text">{{yield}}</div>
</div> </div>

View file

@ -91,3 +91,12 @@ type InvitationModel struct {
Message string Message string
Recipients []string Recipients []string
} }
// NewSpaceRequest details the new space to create.
type NewSpaceRequest struct {
Name string `json:"name"`
CloneID string `json:"cloneID"` // existing space to clone, empty = no cloning
CopyTemplate bool `json:"copyTemplate"` // copy templates and reusable content blocks
CopyPermission bool `json:"copyPermission"` // copy uer permissions
CopyDocument bool `json:"copyDocument"` // copy all documents!
}