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

Merge pull request #282 from documize/core-0619

The all new v3 is here sporting a new layout, better theming, quick-jump to spaces and content, tonnes of document view improvements, comment replies, expand/collapse doc views and much more.
This commit is contained in:
Harvey Kandola 2019-06-12 14:19:12 +01:00 committed by GitHub
commit 8f4cd755de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
153 changed files with 7479 additions and 7278 deletions

View file

@ -13,9 +13,9 @@ All you need to provide is PostgreSQL, Microsoft SQL Server or any MySQL variant
## Latest Release
[Community Edition: v2.5.1](https://github.com/documize/community/releases)
[Community Edition: v3.0.0](https://github.com/documize/community/releases)
[Enterprise Edition: v2.5.1](https://www.documize.com/downloads)
[Enterprise Edition: v3.0.0](https://www.documize.com/downloads)
> *We provide frequent product updates for both cloud and self-hosted customers.*
>

View file

@ -0,0 +1,5 @@
/* Enterprise edition */
-- Feedback feature: support threaded comments and section references
ALTER TABLE dmz_doc_comment ADD COLUMN `c_replyto` VARCHAR(20) NOT NULL DEFAULT '' COLLATE utf8_bin AFTER `c_docid`;
ALTER TABLE dmz_doc_comment ADD COLUMN `c_sectionid` VARCHAR(20) NOT NULL DEFAULT '' COLLATE utf8_bin AFTER `c_docid`;

View file

@ -0,0 +1,5 @@
/* Enterprise edition */
-- Feedback feature: support threaded comments and section references
ALTER TABLE dmz_doc_comment ADD COLUMN c_replyto VARCHAR(20) NOT NULL DEFAULT '' COLLATE ucs_basic;
ALTER TABLE dmz_doc_comment ADD COLUMN c_sectionid VARCHAR(20) NOT NULL DEFAULT '' COLLATE ucs_basic;

View file

@ -0,0 +1,5 @@
/* Enterprise edition */
-- Feedback feature: support threaded comments and section references
ALTER TABLE dmz_doc_comment ADD c_replyto NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '';
ALTER TABLE dmz_doc_comment ADD c_sectionid NVARCHAR(20) COLLATE Latin1_General_CS_AS NOT NULL DEFAULT '';

View file

@ -14,27 +14,25 @@ package attachment
import (
"bytes"
"database/sql"
"fmt"
"io"
"mime"
"net/http"
"strings"
"github.com/documize/community/domain/auth"
"github.com/documize/community/model/space"
"github.com/documize/community/core/env"
"github.com/documize/community/core/request"
"github.com/documize/community/core/response"
"github.com/documize/community/core/secrets"
"github.com/documize/community/core/uniqueid"
"github.com/documize/community/domain"
"github.com/documize/community/domain/auth"
"github.com/documize/community/domain/organization"
"github.com/documize/community/domain/permission"
indexer "github.com/documize/community/domain/search"
"github.com/documize/community/domain/store"
"github.com/documize/community/model/attachment"
"github.com/documize/community/model/audit"
"github.com/documize/community/model/space"
"github.com/documize/community/model/workflow"
uuid "github.com/nu7hatch/gouuid"
)
@ -89,7 +87,7 @@ func (h *Handler) Download(w http.ResponseWriter, r *http.Request) {
return
}
// Get the space for this attachment
// Get the space for this attachment.
sp, err := h.Store.Space.Get(ctx, doc.SpaceID)
if err == sql.ErrNoRows {
response.WriteNotFoundError(w, method, a.DocumentID)
@ -101,8 +99,7 @@ func (h *Handler) Download(w http.ResponseWriter, r *http.Request) {
return
}
// Get the organization for this request
// Get the space for this attachment
// Get the organization for this request.
org, err := h.Store.Organization.GetOrganization(ctx, ctx.OrgID)
if err == sql.ErrNoRows {
response.WriteNotFoundError(w, method, a.DocumentID)
@ -181,16 +178,20 @@ func (h *Handler) Download(w http.ResponseWriter, r *http.Request) {
typ = "application/octet-stream"
}
dataSize := len(a.Data)
w.Header().Set("Content-Type", typ)
w.Header().Set("Content-Disposition", `Attachment; filename="`+a.Filename+`" ; `+`filename*="`+a.Filename+`"`)
w.Header().Set("Content-Length", fmt.Sprintf("%d", len(a.Data)))
w.WriteHeader(http.StatusOK)
if dataSize != 0 {
w.Header().Set("Content-Length", string(dataSize))
}
_, err = w.Write(a.Data)
if err != nil {
h.Runtime.Log.Error("write attachment", err)
return
}
w.WriteHeader(http.StatusOK)
h.Store.Audit.Record(ctx, audit.EventTypeAttachmentDownload)
}

View file

@ -34,8 +34,10 @@ func (s Store) Add(ctx domain.RequestContext, a attachment.Attachment) (err erro
a.OrgID = ctx.OrgID
a.Created = time.Now().UTC()
a.Revised = time.Now().UTC()
bits := strings.Split(a.Filename, ".")
a.Extension = bits[len(bits)-1]
if len(a.Extension) == 0 {
bits := strings.Split(a.Filename, ".")
a.Extension = bits[len(bits)-1]
}
_, err = ctx.Transaction.Exec(s.Bind("INSERT INTO dmz_doc_attachment (c_refid, c_orgid, c_docid, c_sectionid, c_job, c_fileid, c_filename, c_data, c_extension, c_created, c_revised) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"),
a.RefID, a.OrgID, a.DocumentID, a.SectionID, a.Job, a.FileID, a.Filename, a.Data, a.Extension, a.Created, a.Revised)

View file

@ -733,7 +733,8 @@ func (b backerHandler) dmzDocument(files *[]backupItem) (err error) {
err = b.Runtime.Db.Select(&cm, `
SELECT c_refid AS refid, c_orgid AS orgid, c_docid AS documentid,
c_userid AS userid, c_email AS email,
c_feedback AS feedback, c_created AS created
c_feedback AS feedback, c_sectionid AS sectionid, c_replyto AS replyto,
c_created AS created
FROM dmz_doc_comment`+w)
if err != nil {
return errors.Wrap(err, "select.doccomment")

View file

@ -59,6 +59,8 @@ type comment struct {
UserID string `json:"userId"`
Email string `json:"email"`
Feedback string `json:"feedback"`
SectionID string `json:"sectionId"`
ReplyTo string `json:"replyTo"`
Created time.Time `json:"created"`
}

View file

@ -1551,15 +1551,6 @@ func (r *restoreHandler) dmzDocAttachment() (err error) {
func (r *restoreHandler) dmzDocComment() (err error) {
filename := "dmz_doc_comment.json"
type comment struct {
RefID string `json:"feedbackId"`
OrgID string `json:"orgId"`
DocumentID string `json:"documentId"`
UserID string `json:"userId"`
Email string `json:"email"`
Feedback string `json:"feedback"`
Created time.Time `json:"created"`
}
cm := []comment{}
err = r.fileJSON(filename, &cm)
if err != nil {
@ -1590,10 +1581,10 @@ func (r *restoreHandler) dmzDocComment() (err error) {
for i := range cm {
_, err = r.Context.Transaction.Exec(r.Runtime.Db.Rebind(`
INSERT INTO dmz_doc_comment
(c_refid, c_orgid, c_userid, c_docid, c_email, c_feedback, c_created)
VALUES (?, ?, ?, ?, ?, ?, ?)`),
(c_refid, c_orgid, c_userid, c_docid, c_email, c_feedback, c_replyto, c_sectionid, c_created)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`),
cm[i].RefID, r.remapOrg(cm[i].OrgID), r.remapUser(cm[i].UserID), cm[i].DocumentID,
cm[i].Email, cm[i].Feedback, cm[i].Created)
cm[i].Email, cm[i].Feedback, cm[i].ReplyTo, cm[i].SectionID, cm[i].Created)
if err != nil {
r.Context.Transaction.Rollback()
@ -1727,6 +1718,7 @@ func (r *restoreHandler) dmzUser() (err error) {
insert = true
}
if err != nil {
r.Context.Transaction.Rollback()
err = errors.Wrap(err, fmt.Sprintf("unable to check email %s", u[i].Email))
return
}

View file

@ -24,6 +24,7 @@ import (
"github.com/documize/community/core/response"
"github.com/documize/community/core/streamutil"
"github.com/documize/community/core/stringutil"
"github.com/documize/community/core/uniqueid"
"github.com/documize/community/domain"
"github.com/documize/community/domain/organization"
"github.com/documize/community/domain/permission"
@ -34,6 +35,7 @@ import (
"github.com/documize/community/model/audit"
"github.com/documize/community/model/doc"
"github.com/documize/community/model/link"
"github.com/documize/community/model/page"
pm "github.com/documize/community/model/permission"
"github.com/documize/community/model/search"
"github.com/documize/community/model/space"
@ -145,19 +147,9 @@ func (h *Handler) BySpace(w http.ResponseWriter, r *http.Request) {
return
}
// Get the space as we need to check settings.
space, err := h.Store.Space.Get(ctx, spaceID)
// Can user view drafts?
viewDrafts := permission.CanViewDrafts(ctx, *h.Store, spaceID)
// If space defaults to drfat documents, then this means
// user can view drafts as long as they have edit rights.
canEdit := permission.HasPermission(ctx, *h.Store, spaceID, pm.DocumentEdit)
if space.Lifecycle == workflow.LifecycleDraft && canEdit {
viewDrafts = true
}
// Get complete list of documents regardless of category permission
// and versioning.
documents, err := h.Store.Document.GetBySpace(ctx, spaceID)
@ -766,3 +758,229 @@ func (h *Handler) Export(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(export))
}
// Duplicate makes a copy of a document.
// Name of new document is required.
func (h *Handler) Duplicate(w http.ResponseWriter, r *http.Request) {
method := "document.Duplicate"
ctx := domain.GetRequestContext(r)
// Holds old to new ref ID values.
pageRefMap := make(map[string]string)
// Parse payload
defer streamutil.Close(r.Body)
body, err := ioutil.ReadAll(r.Body)
if err != nil {
response.WriteBadRequestError(w, method, err.Error())
h.Runtime.Log.Error(method, err)
return
}
m := doc.DuplicateModel{}
err = json.Unmarshal(body, &m)
if err != nil {
response.WriteBadRequestError(w, method, err.Error())
h.Runtime.Log.Error(method, err)
return
}
// Check permissions
if !permission.CanViewDocument(ctx, *h.Store, m.DocumentID) {
response.WriteForbiddenError(w)
return
}
if !permission.CanUploadDocument(ctx, *h.Store, m.SpaceID) {
response.WriteForbiddenError(w)
return
}
ctx.Transaction, err = h.Runtime.Db.Beginx()
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// Get document to be duplicated.
d, err := h.Store.Document.Get(ctx, m.DocumentID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// Assign new ID and remove versioning info.
d.RefID = uniqueid.Generate()
d.GroupID = ""
d.Name = m.Name
// Fetch doc attachments, links.
da, err := h.Store.Attachment.GetAttachmentsWithData(ctx, m.DocumentID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
dl, err := h.Store.Link.GetDocumentOutboundLinks(ctx, m.DocumentID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// Fetch published and unpublished sections.
pages, err := h.Store.Page.GetPages(ctx, m.DocumentID)
if err != nil && err != sql.ErrNoRows {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
if len(pages) == 0 {
pages = []page.Page{}
}
unpublished, err := h.Store.Page.GetUnpublishedPages(ctx, m.DocumentID)
if err != nil && err != sql.ErrNoRows {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
if len(unpublished) == 0 {
unpublished = []page.Page{}
}
pages = append(pages, unpublished...)
meta, err := h.Store.Page.GetDocumentPageMeta(ctx, m.DocumentID, false)
if err != nil && err != sql.ErrNoRows {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
if len(meta) == 0 {
meta = []page.Meta{}
}
// Duplicate the complete document starting with the document.
err = h.Store.Document.Add(ctx, d)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// Attachments
for i := range da {
da[i].RefID = uniqueid.Generate()
da[i].DocumentID = d.RefID
err = h.Store.Attachment.Add(ctx, da[i])
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
}
// Sections
for j := range pages {
// Create mapping between old and new section IDs.
pageRefMap[pages[j].RefID] = uniqueid.Generate()
// Get meta for section
sm := page.Meta{}
for k := range meta {
if meta[k].SectionID == pages[j].RefID {
sm = meta[k]
break
}
}
// Get attachments for section.
sa, err := h.Store.Attachment.GetSectionAttachments(ctx, pages[j].RefID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
pages[j].RefID = pageRefMap[pages[j].RefID]
pages[j].DocumentID = d.RefID
sm.DocumentID = d.RefID
sm.SectionID = pages[j].RefID
err = h.Store.Page.Add(ctx, page.NewPage{Page: pages[j], Meta: sm})
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// Now add any section attachments.
for n := range sa {
sa[n].RefID = uniqueid.Generate()
sa[n].DocumentID = d.RefID
sa[n].SectionID = pages[j].RefID
err = h.Store.Attachment.Add(ctx, sa[n])
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
}
}
// Links
for l := range dl {
// Update common meta for all links.
dl[l].RefID = uniqueid.Generate()
dl[l].SourceDocumentID = d.RefID
// Remap section ID.
if len(dl[l].SourceSectionID) > 0 && len(pageRefMap[dl[l].SourceSectionID]) > 0 {
dl[l].SourceSectionID = pageRefMap[dl[l].SourceSectionID]
}
err = h.Store.Link.Add(ctx, dl[l])
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
}
// Record activity and finish.
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
SpaceID: d.SpaceID,
DocumentID: d.RefID,
SourceType: activity.SourceTypeDocument,
ActivityType: activity.TypeCreated})
ctx.Transaction.Commit()
h.Store.Audit.Record(ctx, audit.EventTypeDocumentAdd)
// Update search index if published.
if d.Lifecycle == workflow.LifecycleLive {
a, _ := h.Store.Attachment.GetAttachments(ctx, d.RefID)
go h.Indexer.IndexDocument(ctx, d, a)
pages, _ := h.Store.Page.GetPages(ctx, d.RefID)
for i := range pages {
go h.Indexer.IndexContent(ctx, pages[i])
}
} else {
go h.Indexer.DeleteDocument(ctx, d.RefID)
}
response.WriteEmpty(w)
}

File diff suppressed because one or more lines are too long

View file

@ -76,13 +76,13 @@ func (s Store) GetDocumentOutboundLinks(ctx domain.RequestContext, documentID st
WHERE c_orgid=? AND c_sourcedocid=?`),
ctx.OrgID, documentID)
if err != nil && err != sql.ErrNoRows {
err = errors.Wrap(err, "select document oubound links")
return
}
if len(links) == 0 {
if err == sql.ErrNoRows || len(links) == 0 {
err = nil
links = []link.Link{}
}
if err != nil {
err = errors.Wrap(err, "select document oubound links")
}
return
}
@ -98,13 +98,13 @@ func (s Store) GetPageLinks(ctx domain.RequestContext, documentID, pageID string
WHERE c_orgid=? AND c_sourcedocid=? AND c_sourcesectionid=?`),
ctx.OrgID, documentID, pageID)
if err != nil && err != sql.ErrNoRows {
err = errors.Wrap(err, "get page links")
return
}
if len(links) == 0 {
if err == sql.ErrNoRows || len(links) == 0 {
err = nil
links = []link.Link{}
}
if err != nil {
err = errors.Wrap(err, "get page links")
}
return
}

View file

@ -911,16 +911,28 @@ func (h *Handler) Copy(w http.ResponseWriter, r *http.Request) {
return
}
// fetch data
// Get both source and target documents.
doc, err := h.Store.Document.Get(ctx, documentID)
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
targetDoc, err := h.Store.Document.Get(ctx, targetID)
if err != nil {
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
// workflow check
if doc.Protection == workflow.ProtectionLock || doc.Protection == workflow.ProtectionReview {
// Workflow check for target (receiving) doc.
if targetDoc.Protection == workflow.ProtectionLock || targetDoc.Protection == workflow.ProtectionReview {
response.WriteForbiddenError(w)
return
}
// Check permissions for target document and copy permission.
if !permission.CanChangeDocument(ctx, *h.Store, targetDoc.RefID) {
response.WriteForbiddenError(w)
return
}
@ -951,8 +963,9 @@ func (h *Handler) Copy(w http.ResponseWriter, r *http.Request) {
newPageID := uniqueid.Generate()
p.RefID = newPageID
p.Level = 1
p.Sequence = 0
p.Level = p.Level
// p.Sequence = p.Sequence
p.Sequence, _ = h.Store.Page.GetNextPageSequence(ctx, targetDoc.RefID)
p.DocumentID = targetID
p.UserID = ctx.UserID
pageMeta.DocumentID = targetID
@ -1003,6 +1016,33 @@ func (h *Handler) Copy(w http.ResponseWriter, r *http.Request) {
}
}
// Copy section links.
links, err := h.Store.Link.GetPageLinks(ctx, documentID, pageID)
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
for lindex := range links {
links[lindex].RefID = uniqueid.Generate()
links[lindex].SourceSectionID = newPageID
links[lindex].SourceDocumentID = targetID
err = h.Store.Link.Add(ctx, links[lindex])
if err != nil {
ctx.Transaction.Rollback()
response.WriteServerError(w, method, err)
h.Runtime.Log.Error(method, err)
return
}
}
// Update doc revised.
h.Store.Document.UpdateRevised(ctx, targetID)
// If document is published, we record activity and
// index content for search.
if doc.Lifecycle == workflow.LifecycleLive {
h.Store.Activity.RecordUserActivity(ctx, activity.UserActivity{
SpaceID: doc.SpaceID,
@ -1010,17 +1050,18 @@ func (h *Handler) Copy(w http.ResponseWriter, r *http.Request) {
SectionID: newPageID,
SourceType: activity.SourceTypePage,
ActivityType: activity.TypeCreated})
}
// Update doc revised.
h.Store.Document.UpdateRevised(ctx, targetID)
go h.Indexer.IndexContent(ctx, p)
}
ctx.Transaction.Commit()
h.Store.Audit.Record(ctx, audit.EventTypeSectionCopy)
np, _ := h.Store.Page.Get(ctx, pageID)
// Re-level all pages in document.
h.LevelizeDocument(ctx, targetID)
np, _ := h.Store.Page.Get(ctx, pageID)
response.WriteJSON(w, np)
}

View file

@ -344,13 +344,9 @@ func (h *Handler) GetSpacePermissions(w http.ResponseWriter, r *http.Request) {
records[i].Name = user.EveryoneUserName
} else {
u, err := h.Store.User.Get(ctx, records[i].WhoID)
if err != nil {
h.Runtime.Log.Info(fmt.Sprintf("user not found %s", records[i].WhoID))
h.Runtime.Log.Error(method, err)
continue
if err == nil {
records[i].Name = u.Fullname()
}
records[i].Name = u.Fullname()
}
}
}

View file

@ -39,10 +39,10 @@ func main() {
// Specify the product edition.
rt.Product = domain.Product{}
rt.Product.Major = "2"
rt.Product.Minor = "5"
rt.Product.Patch = "1"
rt.Product.Revision = "190516105625"
rt.Product.Major = "3"
rt.Product.Minor = "0"
rt.Product.Patch = "0"
rt.Product.Revision = "190611110527"
rt.Product.Version = fmt.Sprintf("%s.%s.%s", rt.Product.Major, rt.Product.Minor, rt.Product.Patch)
rt.Product.Edition = domain.CommunityEdition
rt.Product.Title = fmt.Sprintf("%s Edition", rt.Product.Edition)

File diff suppressed because one or more lines are too long

View file

@ -75,5 +75,6 @@ module.exports = {
"iziToast": true,
"Papa": true,
"Popper": true,
"ClipboardJS": true
}
};

View file

@ -9,6 +9,7 @@
//
// https://documize.com
import $ from 'jquery';
import { computed } from '@ember/object';
import { empty } from '@ember/object/computed';
import { set } from '@ember/object';
@ -169,27 +170,27 @@ export default Component.extend(ModalMixin, Notifier, {
case constants.AuthProvider.Keycloak:
if (this.get('KeycloakUrlError')) {
this.$("#keycloak-url").focus();
$("#keycloak-url").focus();
return;
}
if (this.get('KeycloakRealmError')) {
this.$("#keycloak-realm").focus();
$("#keycloak-realm").focus();
return;
}
if (this.get('KeycloakClientIdError')) {
this.$("#keycloak-clientId").focus();
$("#keycloak-clientId").focus();
return;
}
if (this.get('KeycloakPublicKeyError')) {
this.$("#keycloak-publicKey").focus();
$("#keycloak-publicKey").focus();
return;
}
if (this.get('KeycloakAdminUserError')) {
this.$("#keycloak-admin-user").focus();
$("#keycloak-admin-user").focus();
return;
}
if (this.get('KeycloakAdminPasswordError')) {
this.$("#keycloak-admin-password").focus();
$("#keycloak-admin-password").focus();
return;
}
@ -213,11 +214,11 @@ export default Component.extend(ModalMixin, Notifier, {
case constants.AuthProvider.LDAP:
if (this.get('ldapErrorServerHost')) {
this.$("#ldap-host").focus();
$("#ldap-host").focus();
return;
}
if (this.get('ldapErrorServerPort')) {
this.$("#ldap-port").focus();
$("#ldap-port").focus();
return;
}
@ -226,7 +227,7 @@ export default Component.extend(ModalMixin, Notifier, {
config.serverPort = parseInt(this.get('ldapConfig.serverPort'));
if (!_.isEmpty(config.groupFilter) && _.isEmpty(config.attributeGroupMember)) {
this.$('#ldap-attributeGroupMember').focus();
$('#ldap-attributeGroupMember').focus();
return;
}

View file

@ -53,7 +53,7 @@ export default Component.extend(Notifier, Modal, {
didInsertElement() {
this._super(...arguments);
this.$('#restore-file').on('change', function(){
$('#restore-file').on('change', function(){
var fileName = document.getElementById("restore-file").files[0].name;
$(this).next('.custom-file-label').html(fileName);
});

View file

@ -84,7 +84,7 @@ export default Component.extend(Notifier, {
actions: {
change() {
const selectEl = this.$('#maxTags')[0];
const selectEl = $('#maxTags')[0];
const selection = selectEl.selectedOptions[0].value;
this.set('maxTags', parseInt(selection));

View file

@ -63,9 +63,9 @@ export default Component.extend(AuthProvider, ModalMixin, Notifier, {
this.set('showPermExplain', !this.get('showPermExplain'));
if (this.showPermExplain) {
this.$(".perms").show();
$(".perms").show();
} else {
this.$(".perms").hide();
$(".perms").hide();
}
},

View file

@ -9,6 +9,7 @@
//
// https://documize.com
import $ from 'jquery';
import { debounce } from '@ember/runloop';
import { computed, set } from '@ember/object';
import { inject as service } from '@ember/service';
@ -83,7 +84,7 @@ export default Component.extend(ModalMixin, {
didRender() {
this._super(...arguments);
this.$('#content-linker-networklocation').removeClass('is-invalid');
$('#content-linker-networklocation').removeClass('is-invalid');
},
willDestroyElement() {
@ -149,7 +150,7 @@ export default Component.extend(ModalMixin, {
}
if (_.isNull(selection)) {
if (this.get('tab4Selected')) this.$('#content-linker-networklocation').addClass('is-invalid').focus();
if (this.get('tab4Selected')) $('#content-linker-networklocation').addClass('is-invalid').focus();
return;
}

View file

@ -17,6 +17,8 @@ import Modals from '../../mixins/modal';
import Component from '@ember/component';
export default Component.extend(Modals, {
classNames: ['document-meta-wrapper', 'non-printable'],
appMeta: service(),
documentService: service('document'),
sessionService: service('session'),
categoryService: service('category'),
@ -52,10 +54,22 @@ export default Component.extend(Modals, {
},
actions: {
onEdit() {
if (!this.get('permissions.documentEdit')) return;
this.get('router').transitionTo('document.settings');
},
onEditCategory() {
if (!this.get('permissions.documentEdit')) return;
this.get('router').transitionTo('document.settings', {queryParams: {tab: 'category'}});
},
onSelectVersion(version) {
let space = this.get('space');
this.get('router').transitionTo('document', space.get('id'), space.get('slug'), version.documentId, this.get('document.slug'));
}
}
});

View file

@ -18,17 +18,23 @@ export default Component.extend({
editMode: false,
editPage: null,
editMeta: null,
expanded: true,
didReceiveAttrs() {
this._super(...arguments);
if (this.get('isDestroyed') || this.get('isDestroying')) return;
let pageId = this.get('page.id');
if (this.get('session.authenticated')) {
this.workflow();
}
if (this.get('toEdit') === this.get('page.id') && this.get('permissions.documentEdit')) this.send('onEdit');
if (this.get('toEdit') === pageId && this.get('permissions.documentEdit')) this.send('onEdit');
// Work out if this section is expanded by default (state stored in browser local storage).
this.set('expanded', !_.includes(this.get('expandState'), pageId));
},
workflow() {

View file

@ -48,6 +48,7 @@ export default Component.extend(ModalMixin, AuthMixin, Notifier, {
this.get('permissions.documentEdit')) return true;
}),
duplicateName: '',
init() {
this._super(...arguments);
@ -57,7 +58,7 @@ export default Component.extend(ModalMixin, AuthMixin, Notifier, {
pinId: '',
newName: ''
};
this.saveTemplate = {
name: '',
description: ''
@ -88,6 +89,10 @@ export default Component.extend(ModalMixin, AuthMixin, Notifier, {
this.modalOpen("#document-template-modal", {show:true}, "#new-template-name");
},
onShowDuplicateModal() {
this.modalOpen("#document-duplicate-modal", {show:true}, "#duplicate-name");
},
onShowDeleteModal() {
this.modalOpen("#document-delete-modal", {show:true});
},
@ -99,7 +104,35 @@ export default Component.extend(ModalMixin, AuthMixin, Notifier, {
cb();
},
onPrintDocument() {
onShowPrintModal() {
let pages = this.get('pages');
// By default we select everything for print.
pages.forEach((item) => {
item.set('printSelected', true);
});
this.set('pages', pages);
this.modalOpen("#document-print-modal", {show:true});
},
onPrintSelection() {
this.modalClose('#document-print-modal');
let pages = this.get('pages');
pages.forEach((item) => {
let pageId = item.get('page.id');
let selected = item.get('printSelected');
$(`#page-${pageId}`).addClass('non-printable');
$(`#page-spacer-${pageId}`).addClass('non-printable');
if (selected) {
$(`#page-${pageId}`).removeClass('non-printable');
$(`#page-spacer-${pageId}`).removeClass('non-printable');
}
});
window.print();
},
@ -155,6 +188,25 @@ export default Component.extend(ModalMixin, AuthMixin, Notifier, {
return true;
},
onDuplicate() {
let name = this.get('duplicateName');
if (_.isEmpty(name)) {
$("#duplicate-name").addClass("is-invalid").focus();
return;
}
$("#duplicate-name").removeClass("is-invalid");
this.set('duplicateName', '');
this.get('onDuplicate')(name);
this.modalClose('#document-duplicate-modal');
return true;
},
onExport() {
let spec = {
spaceId: this.get('document.spaceId'),

View file

@ -0,0 +1,36 @@
// 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 { inject as service } from '@ember/service';
import AuthMixin from '../../mixins/auth';
import Component from '@ember/component';
export default Component.extend(AuthMixin, {
router: service(),
documentSvc: service('document'),
docs: null,
space: null,
didReceiveAttrs() {
this._super(...arguments);
this.get('documentSvc').getAllBySpace(this.get('space.id')).then((docs) => {
this.set('docs', docs);
this.classNames = ['dicon', this.get('constants').Icon.ArrowSmallDown];
});
},
actions: {
onSpace() {
this.router.transitionTo('folder.index', this.space.id, this.space.slug);
}
}
});

View file

@ -13,21 +13,22 @@ import $ from 'jquery';
import { computed, observer } from '@ember/object';
import { debounce } from '@ember/runloop';
import { inject as service } from '@ember/service';
import Notifier from '../../mixins/notifier';
import ModalMixin from '../../mixins/modal';
import tocUtil from '../../utils/toc';
import Component from '@ember/component';
export default Component.extend(ModalMixin, {
export default Component.extend(Notifier, ModalMixin, {
documentService: service('document'),
searchService: service('search'),
router: service(),
appMeta: service(),
deleteChildren: false,
blockTitle: "",
blockExcerpt: "",
// canEdit: false,
canDelete: false,
canMove: false,
docSearchFilter: '',
targetSpace: null,
targetDocs: null,
targetDoc: null,
// eslint-disable-next-line ember/no-observers
onKeywordChange: observer('docSearchFilter', function() {
@ -37,12 +38,6 @@ export default Component.extend(ModalMixin, {
emptySearch: computed('docSearchResults', function() {
return this.get('docSearchResults.length') === 0;
}),
hasMenuPermissions: computed('permissions.{documentCopy,documentTemplate}', 'userPendingItem', 'canEdit', 'canMove', 'canDelete', function() {
let permissions = this.get('permissions');
return permissions.get('documentCopy') || permissions.get('documentTemplate') ||
this.get('canEdit') || this.get('canMove') || this.get('canDelete');
}),
canEdit: computed('permissions', 'document', 'pages', function() {
let constants = this.get('constants');
let permissions = this.get('permissions');
@ -57,7 +52,7 @@ export default Component.extend(ModalMixin, {
init() {
this._super(...arguments);
this.docSearchResults = [];
this.state = {
actionablePage: false,
upDisabled: true,
@ -72,21 +67,32 @@ export default Component.extend(ModalMixin, {
this._super(...arguments);
this.modalInputFocus('#publish-page-modal-' + this.get('page.id'), '#block-title-' + this.get('page.id'));
let permissions = this.get('permissions');
// this.set('canEdit', permissions.get('documentEdit'));
this.set('canDelete', permissions.get('documentDelete'));
this.set('canMove', permissions.get('documentMove'));
this.setState(this.get('page.id'));
},
searchDocs() {
let payload = { keywords: this.get('docSearchFilter').trim(), doc: true };
if (payload.keywords.length == 0) return;
didInsertElement(){
this._super(...arguments);
this.get('searchService').find(payload).then((response)=> {
this.set('docSearchResults', response);
let pageId = this.get('page.id');
let url = this.get('appMeta.appHost') +
this.get('router').generate('document.index', {queryParams: {currentPageId: pageId}});
let self = this;
let clip = new ClipboardJS('#page-copy-link-' + pageId, {
text: function() {
self.notifySuccess('Link copied to clipboard');
return url;
}
});
this.set('clip', clip);
},
willDestroyElement() {
this._super(...arguments);
let clip = this.get('clip');
if (!_.isUndefined(clip)) clip.destroy();
},
// Controls what user can do with the toc enty for this page
@ -126,6 +132,10 @@ export default Component.extend(ModalMixin, {
this.modalClose('#delete-page-modal-' + this.get('page.id'));
},
onShowPublishModal() {
this.modalOpen('#publish-page-modal-' + this.get('page.id'), {"show": true}, '#block-title-' + this.get('page.id'));
},
onSavePageAsBlock() {
let page = this.get('page');
let titleElem = '#block-title-' + page.get('id');
@ -171,45 +181,55 @@ export default Component.extend(ModalMixin, {
});
},
onSelectSearchResult(documentId) {
let results = this.get('docSearchResults');
results.forEach((d) => {
d.set('selected', d.get('documentId') === documentId);
});
this.set('docSearchResults', results);
onShowCopyModal() {
this.send('onSelectSpace', this.get('folder'));
this.modalOpen('#copy-page-modal-' + this.get('page.id'), {show:true});
},
onShowMoveModal() {
this.send('onSelectSpace', this.get('folder'));
this.modalOpen('#move-page-modal-' + this.get('page.id'), {show:true});
},
onCopyPage() {
let item = this.get('docSearchResults').findBy('selected', true);
let documentId = !_.isUndefined(item) ? item.get('documentId') : '';
if (_.isEmpty(documentId)) return;
let targetDoc = this.get('targetDoc');
if (_.isNull(targetDoc)) return;
this.modalClose('#copy-page-modal-' + this.get('page.id'));
let cb = this.get('onCopyPage');
cb(documentId);
let refresh = this.get('refresh');
refresh();
this.get('onCopyPage')(targetDoc.get('id'));
this.get('refresh')();
},
onMovePage() {
let item = this.get('docSearchResults').findBy('selected', true);
let documentId = !_.isUndefined(item) ? item.get('documentId') : '';
if (_.isEmpty(documentId)) return;
// can't move into self
if (documentId === this.get('document.id')) return;
let targetDoc = this.get('targetDoc');
if (_.isNull(targetDoc)) return;
this.modalClose('#move-page-modal-' + this.get('page.id'));
let cb = this.get('onMovePage');
cb(documentId);
this.get('onMovePage')(targetDoc.get('id'));
this.get('refresh')();
},
let refresh = this.get('refresh');
refresh();
// Load up documents for selected space and select the first one.
onSelectSpace(space) {
this.set('targetSpace', space);
this.get('documentService').getAllBySpace(space.get('id')).then((docs) => {
this.set('targetDocs', docs);
if (space.get('id') === this.get('folder.id')) {
this.set('targetDoc', this.get('document'));
} else {
if (docs.length > 0) {
this.set('targetDoc', docs[0]);
}
}
});
},
onSelectDoc(doc) {
this.set('targetDoc', doc);
},
// Page up -- above pages shunt down
@ -277,6 +297,15 @@ export default Component.extend(ModalMixin, {
let cb = this.get('onPageLevelChange');
cb(state.pageId, pendingChanges);
}
},
onExpand() {
this.set('expanded', !this.get('expanded'));
this.get('onExpand')(this.get('page.id'), this.get('expanded'));
},
onCopyLink() {
this.set('currentPageId', this.get('page.id'));
}
}
});

View file

@ -167,9 +167,9 @@ export default Component.extend(Notifier, {
if (tag.length> 0) {
if (!_.includes(tagzToSave, tag) && !_.startsWith(tag, '-')) {
tagzToSave.push(tag);
this.$('#add-tag-field-' + t.number).removeClass('is-invalid');
$('#add-tag-field-' + t.number).removeClass('is-invalid');
} else {
this.$('#add-tag-field-' + t.number).addClass('is-invalid');
$('#add-tag-field-' + t.number).addClass('is-invalid');
}
}
});

View file

@ -168,9 +168,9 @@ export default Component.extend(Notifier, {
if (tag.length> 0) {
if (!_.includes(tagzToSave, tag) && !_.startsWith(tag, '-')) {
tagzToSave.push(tag);
this.$('#add-tag-field-' + t.number).removeClass('is-invalid');
$('#add-tag-field-' + t.number).removeClass('is-invalid');
} else {
this.$('#add-tag-field-' + t.number).addClass('is-invalid');
$('#add-tag-field-' + t.number).addClass('is-invalid');
}
}
});

View file

@ -17,7 +17,7 @@ import Notifier from '../../mixins/notifier';
import Component from '@ember/component';
export default Component.extend(Modals, Notifier, {
classNames: ["section"],
classNames: ["document-meta", ' non-printable'],
documentService: service('document'),
browserSvc: service('browser'),
appMeta: service(),
@ -37,6 +37,15 @@ export default Component.extend(Modals, Notifier, {
didInsertElement() {
this._super(...arguments);
// For authenticated users we send server auth token.
let qry = '';
if (this.get('session.hasSecureToken')) {
qry = '?secure=' + this.get('session.secureToken');
} else if (this.get('session.authenticated')) {
qry = '?token=' + this.get('session.authToken');
}
this.set('downloadQuery', qry);
if (!this.get('permissions.documentEdit') || this.get('document.protection') === this.get('constants').ProtectionType.Lock) {
return;
}
@ -47,7 +56,7 @@ export default Component.extend(Modals, Notifier, {
let uploadUrl = `${url}/documents/${documentId}/attachments`;
// Handle upload clicks on button and anything inside that button.
let sel = ['#upload-document-files ', '#upload-document-files > div'];
let sel = ['#upload-document-files ', '#upload-document-files > span'];
for (var i=0; i < 2; i++) {
let dzone = new Dropzone(sel[i], {
headers: {
@ -86,15 +95,6 @@ export default Component.extend(Modals, Notifier, {
dzone.removeFile(file);
});
}
// For authenticated users we send server auth token.
let qry = '';
if (this.get('session.hasSecureToken')) {
qry = '?secure=' + this.get('session.secureToken');
} else if (this.get('session.authenticated')) {
qry = '?token=' + this.get('session.authToken');
}
this.set('downloadQuery', qry);
},
getAttachments() {
@ -109,15 +109,6 @@ export default Component.extend(Modals, Notifier, {
this.notifySuccess('File deleted');
this.getAttachments();
});
},
onExport() {
this.get('documentSvc').export({}).then((htmlExport) => {
this.get('browserSvc').downloadFile(htmlExport, this.get('space.slug') + '.html');
this.notifySuccess('Exported');
});
this.modalClose("#space-export-modal");
}
}
});

View file

@ -1,41 +0,0 @@
// 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 { computed } from '@ember/object';
import { notEmpty } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import Modals from '../../mixins/modal';
import Component from '@ember/component';
export default Component.extend(Modals, {
appMeta: service(),
documentService: service('document'),
sessionService: service('session'),
router: service(),
userChanges: notEmpty('contributorMsg'),
unassigned: computed('selectedCategories', 'tagz', function() {
return this.get('selectedCategories').length === 0 && this.get('tagz').length === 0;
}),
actions: {
onEditStatus() {
if (!this.get('permissions.documentEdit')) return;
this.get('router').transitionTo('document.settings', {queryParams: {tab: 'general'}});
},
onSelectVersion(version) {
let space = this.get('space');
this.get('router').transitionTo('document', space.get('id'), space.get('slug'), version.documentId, this.get('document.slug'));
}
}
});

View file

@ -38,6 +38,7 @@ export default Component.extend(Notifier, {
didReceiveAttrs() {
this._super(...arguments);
// Show/allow liking if space allows it and document is published.
this.set('showLikes', this.get('folder.allowLikes') && this.get('document.isLive'));
},

View file

@ -9,6 +9,7 @@
//
// https://documize.com
import $ from 'jquery';
import { inject as service } from '@ember/service';
import { A } from '@ember/array';
import { debounce } from '@ember/runloop';
@ -152,9 +153,9 @@ export default Component.extend(Notifier, Modals, {
this.set('showSpacePermExplain', !this.get('showSpacePermExplain'));
if (this.showSpacePermExplain) {
this.$(".space-perms").show();
$(".space-perms").show();
} else {
this.$(".space-perms").hide();
$(".space-perms").hide();
}
},
@ -162,9 +163,9 @@ export default Component.extend(Notifier, Modals, {
this.set('showDocumentPermExplain', !this.get('showDocumentPermExplain'));
if (this.showDocumentPermExplain) {
this.$(".document-perms").show();
$(".document-perms").show();
} else {
this.$(".document-perms").hide();
$(".document-perms").hide();
}
},
@ -257,7 +258,7 @@ export default Component.extend(Notifier, Modals, {
}
if (email.length === 0) {
this.$('#space-invite-email').addClass('is-invalid').focus();
$('#space-invite-email').addClass('is-invalid').focus();
return;
}
@ -283,7 +284,7 @@ export default Component.extend(Notifier, Modals, {
this.get('spaceSvc').share(this.get('folder.id'), result).then(() => {
this.notifySuccess('Invites sent');
this.$('#space-invite-email').removeClass('is-invalid');
$('#space-invite-email').removeClass('is-invalid');
this.modalClose("#space-invite-user-modal");
this.load();
});

View file

@ -17,7 +17,9 @@ import AuthMixin from '../../mixins/auth';
import Component from '@ember/component';
export default Component.extend(AuthMixin, {
classNames: ["section"],
tagName: 'div',
classNames: ['master-sidebar'],
router: service(),
documentService: service('document'),
folderService: service('folder'),

View file

@ -19,7 +19,6 @@ import Notifier from '../../mixins/notifier';
import Component from '@ember/component';
export default Component.extend(ModalMixin, AuthMixin, Notifier, {
classNames: ["display-inline-block"],
spaceService: service('folder'),
localStorage: service(),
templateService: service('template'),

View file

@ -0,0 +1,17 @@
// 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 Component from '@ember/component';
export default Component.extend({
tagName: 'div',
classNames: ['master-grid-container'],
});

View file

@ -0,0 +1,17 @@
// 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 Component from '@ember/component';
export default Component.extend({
tagName: 'div',
classNames: ['master-content'],
});

View file

@ -0,0 +1,17 @@
// 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 Component from '@ember/component';
export default Component.extend({
tagName: 'div',
classNames: ['custom-action'],
});

View file

@ -0,0 +1,23 @@
// 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 Component from '@ember/component';
export default Component.extend({
tagName: 'div',
classNames: ['goto-top'],
actions: {
onClick() {
this.get('browser').scrollTo('html');
}
}
});

View file

@ -0,0 +1,17 @@
// 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 Component from '@ember/component';
export default Component.extend({
tagName: 'div',
classNames: ['master-sidebar', 'non-printable'],
});

View file

@ -17,7 +17,7 @@ import Component from '@ember/component';
export default Component.extend(Modals, {
tagName: 'div',
classNames: ['master-sidebar-container', 'non-printable'],
classNames: ['master-navigation', 'non-printable'],
selectedItem: '',
folderService: service('folder'),
appMeta: service(),

View file

@ -0,0 +1,18 @@
// 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 Modals from '../../mixins/modal';
import Component from '@ember/component';
export default Component.extend(Modals, {
tagName: 'div',
classNames: ['master-navigation', 'non-printable'],
});

View file

@ -19,7 +19,9 @@ export default Component.extend({
size: 500,
calcClass: computed(function() {
switch(this.size) {
let size = parseInt(this.size, 10);
switch(size) {
case 100:
return 'spacer-100';

View file

@ -0,0 +1,84 @@
// 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 { computed } from '@ember/object';
import Component from '@ember/component';
export default Component.extend({
tagName: 'button',
classNames: [],
classNameBindings: ['calcClass'],
attributeBindings: ['calcAttrs:data-dismiss', 'submitAttrs:type'],
label: '',
icon: '',
color: '',
light: false,
themed: false,
dismiss: false,
truncate: false,
stretch: false,
uppercase: true,
iconClass: '',
hasIcon: computed('iconClass', function() {
return this.iconClass.trim() != '';
}),
calcClass: computed(function() {
// Prepare icon class name
this.iconClass = this.icon;
// Prepare button class name
let bc = 'button';
if (this.themed) {
bc += '-theme';
} else {
bc += '-' + this.color;
}
if (this.light) {
bc += '-light';
}
if (!this.uppercase) {
bc += ' text-case-normal';
}
if (this.truncate) {
bc += ' text-truncate';
}
if (this.stretch) {
bc += ' max-width-100 text-left';
}
return bc;
}),
calcAttrs: computed(function() {
if (this.dismiss) {
return 'modal';
}
return null;
}),
submitAttrs: computed(function() {
return this.submit ? "submit": null;
}),
click(e) {
if (!_.isUndefined(this.onClick)) {
e.preventDefault();
this.onClick(e);
}
}
});

View file

@ -0,0 +1,17 @@
// 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 Component from '@ember/component';
export default Component.extend({
tagName: 'div',
classNames: ['divider'],
});

View file

@ -0,0 +1,55 @@
// 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 { computed } from '@ember/object';
import Component from '@ember/component';
export default Component.extend({
classNames: [],
classNameBindings: ['calcClass'],
label: '',
color: '',
arrow: true,
iconClass: '',
calcClass: computed(function() {
// Prepare icon class name
this.iconClass = this.get('constants').Icon.ArrowSmallDown;
// Prepare button class name
let bc = 'dropdown';
if (!this.themed) {
bc += ' dropdown-' + this.color;
}
return bc;
}),
calcAttrs: computed(function() {
if (this.dismiss) {
return 'modal';
}
return null;
}),
submitAttrs: computed(function() {
return this.submit ? "submit": null;
}),
click(e) {
if (!_.isUndefined(this.onClick)) {
e.preventDefault();
this.onClick(e);
}
}
});

View file

@ -12,15 +12,13 @@
import Component from '@ember/component';
export default Component.extend({
classNames: ['dmz-toolbar', 'non-printable'],
classNames: ['dmz-toolbar'],
classNameBindings:
['raised:dmz-toolbar-raised',
'large:dmz-toolbar-large',
'bordered:dmz-toolbar-bordered',
'light:dmz-toolbar-light',
'dark:dmz-toolbar-dark'],
raised: false,
large: false,
bordered: false,
dark: false,
light: false,

View file

@ -228,16 +228,19 @@ let constants = EmberObject.extend({
Delete: 'dicon-bin',
Edit: 'dicon-pen-2',
Email: 'dicon-email',
Expand: 'dicon-enlarge',
Export: 'dicon-data-upload',
Export2: 'dicon-upload',
Filter: 'dicon-sort-tool',
Grid: 'dicon-grid-interface',
GoTop: 'dicon-move-layer-up',
Handshake: 'dicon-handshake',
Index: 'dicon-menu-8',
Integrations: 'dicon-geometry',
Link: 'dicon-link',
ListBullet: 'dicon-list-bullet-2',
Locked: 'dicon-lock',
MoreHorizontal: 'dicon-menu-5',
NotAllowed: 'dicon-ban',
PDF: 'dicon-pdf',
Print: 'dicon-print',
@ -252,6 +255,7 @@ let constants = EmberObject.extend({
Send: 'dicon-send',
Settings: 'dicon-settings-gear',
Share: 'dicon-network-connection',
Sort: 'dicon-alpha-order',
Split: 'dicon-split-37',
Tag: 'dicon-delete-key',
Tick: 'dicon-check',
@ -333,6 +337,7 @@ let constants = EmberObject.extend({
Close: 'Close',
Copy: 'Copy',
Delete: 'Delete',
Duplicate: 'Duplicate',
Edit: 'Edit',
Export: 'Export',
File: 'File',
@ -341,13 +346,16 @@ let constants = EmberObject.extend({
Invite: 'Invite',
Join: 'Join',
Leave: 'Leave',
Login: 'Login',
Move: 'Move',
Next: 'Next',
OK: 'OK',
Preview: 'Preview',
Print: 'Print',
Publish: 'Publish',
Reject: 'Reject',
Remove: 'Remove',
Reply: 'Reply',
Reset: 'Reset',
Restore: 'Restore',
Request: 'Request',
@ -357,6 +365,8 @@ let constants = EmberObject.extend({
Share: 'Share',
SignIn: 'Sign In',
Sort: 'Sort',
Space: 'Space',
Spaces: 'Spaces',
Unassigned: 'Unassigned',
Update: 'Update',
Upload: 'Upload',

View file

@ -1,20 +1,25 @@
{{#layout/master-sidebar hideNavigation=true}}
{{ui/ui-spacer size=300}}
<div class="section">
<div class="title">welcome to documize</div>
<p>Let's set up your account and you started</p>
</div>
{{/layout/master-sidebar}}
<Layout::MasterNavigation @hideNavigation={{true}} />
<Layout::MasterToolbar />
{{#layout/master-content}}
{{layout/logo-heading
title=appMeta.title
desc=appMeta.message
logo=true}}
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">welcome to documize</div>
<p>Let's set up your account and get you started</p>
</div>
</div>
</Layout::Grid::Sidebar>
{{onboard/share-folder
serial=serial
folderId=folderId
slug=slug}}
{{/layout/master-content}}
<Layout::Grid::Content>
{{layout/logo-heading
title=appMeta.title
desc=appMeta.message
logo=true}}
{{onboard/share-folder
serial=serial
folderId=folderId
slug=slug}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -1,71 +1,83 @@
{{#layout/master-sidebar selectedItem="settings"}}
{{ui/ui-spacer size=300}}
<div class="section">
<div class="title">administration</div>
<div class="list">
{{#link-to "customize.general" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Settings}} />
<div class="name">General</div>
{{/link-to}}
{{#link-to "customize.labels" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Checkbox}} />
<div class="name">Labels</div>
{{/link-to}}
{{#link-to "customize.folders" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Grid}} />
<div class="name">Spaces</div>
{{/link-to}}
{{#link-to "customize.users" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Person}} />
<div class="name">User Management</div>
{{/link-to}}
{{#link-to "customize.groups" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.People}} />
<div class="name">User Groups</div>
{{/link-to}}
{{#link-to "customize.integrations" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Integrations}} />
<div class="name">Integrations</div>
{{/link-to}}
{{#if session.isGlobalAdmin}}
{{#link-to "customize.smtp" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Send}} />
<div class="name">Mail Server</div>
{{/link-to}}
{{#link-to "customize.auth" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Locked}} />
<div class="name">Authentication</div>
{{/link-to}}
{{#link-to "customize.search" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Search}} />
<div class="name">Search</div>
{{/link-to}}
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{#link-to "customize.audit" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.ButtonAction}} />
<div class="name">Audit Log</div>
{{/link-to}}
{{/if}}
{{/if}}
{{#link-to "customize.backup" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Database}} />
<div class="name">Backup & Restore</div>
{{/link-to}}
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{#link-to "customize.billing" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Handshake}} />
<div class="name">Billing</div>
{{/link-to}}
{{/if}}
{{#link-to "customize.product" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Announce}} />
<div class="name">Changelog</div>
{{/link-to}}
<Layout::MasterNavigation @selectedItem="settings" />
<Layout::MasterToolbar>
<div class="zone-1" />
<div class="zone-2">
<div class="label color-gray-700">
Documize {{appMeta.edition}} Edition {{appMeta.version}} (build {{appMeta.revision}})
</div>
</div>
{{/layout/master-sidebar}}
<div class="zone-3" />
</Layout::MasterToolbar>
{{#layout/master-content}}
{{outlet}}
{{/layout/master-content}}
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">administration</div>
<div class="list">
{{#link-to "customize.general" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Settings}} />
<div class="name">General</div>
{{/link-to}}
{{#link-to "customize.labels" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Checkbox}} />
<div class="name">Labels</div>
{{/link-to}}
{{#link-to "customize.folders" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Grid}} />
<div class="name">Spaces</div>
{{/link-to}}
{{#link-to "customize.users" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Person}} />
<div class="name">User Management</div>
{{/link-to}}
{{#link-to "customize.groups" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.People}} />
<div class="name">User Groups</div>
{{/link-to}}
{{#link-to "customize.integrations" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Integrations}} />
<div class="name">Integrations</div>
{{/link-to}}
{{#if session.isGlobalAdmin}}
{{#link-to "customize.smtp" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Send}} />
<div class="name">Mail Server</div>
{{/link-to}}
{{#link-to "customize.auth" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Locked}} />
<div class="name">Authentication</div>
{{/link-to}}
{{#link-to "customize.search" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Search}} />
<div class="name">Search</div>
{{/link-to}}
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{#link-to "customize.audit" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.ButtonAction}} />
<div class="name">Audit Log</div>
{{/link-to}}
{{/if}}
{{/if}}
{{#link-to "customize.backup" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Database}} />
<div class="name">Backup & Restore</div>
{{/link-to}}
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{#link-to "customize.billing" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Handshake}} />
<div class="name">Billing</div>
{{/link-to}}
{{/if}}
{{#link-to "customize.product" activeClass="selected" class="item" tagName="div"}}
<i class={{concat "dicon " constants.Icon.Announce}} />
<div class="name">Changelog</div>
{{/link-to}}
</div>
</div>
</div>
</Layout::Grid::Sidebar>
<Layout::Grid::Content>
{{outlet}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -9,7 +9,7 @@
//
// https://documize.com
import { Promise as EmberPromise } from 'rsvp';
import { Promise as EmberPromise, all } from 'rsvp';
import { inject as service } from '@ember/service';
import Notifier from '../../../mixins/notifier';
import Controller from '@ember/controller';
@ -19,6 +19,7 @@ export default Controller.extend(Notifier, {
templateService: service('template'),
sectionService: service('section'),
linkService: service('link'),
localStore: service('local-storage'),
appMeta: service(),
router: service(),
sidebarTab: 'toc',
@ -45,8 +46,19 @@ export default Controller.extend(Notifier, {
onCopyPage(pageId, targetDocumentId) {
let documentId = this.get('document.id');
this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => {
let pages = this.get('pages');
// Make list of page ID values including all child pages.
let pagesToProcess = [{ pageId: pageId }].concat(this.get('documentService').getChildren(pages, pageId));
// Copy each page.
let promises = [];
pagesToProcess.forEach((page, index) => {
promises[index] = this.get('documentService').copyPage(documentId, page.pageId, targetDocumentId);
});
// Do post-processing after all copying has completed.
all(promises).then(() => {
// refresh data if copied to same document
if (documentId === targetDocumentId) {
this.set('pageId', '');
@ -61,9 +73,21 @@ export default Controller.extend(Notifier, {
onMovePage(pageId, targetDocumentId) {
let documentId = this.get('document.id');
let pages = this.get('pages');
this.get('documentService').copyPage(documentId, pageId, targetDocumentId).then(() => {
this.send('onPageDeleted', { id: pageId, children: false });
// Make list of page ID values including all child pages.
let pagesToProcess = [{ pageId: pageId }].concat(this.get('documentService').getChildren(pages, pageId));
// Copy each page.
let promises = [];
pagesToProcess.forEach((page, index) => {
promises[index] = this.get('documentService').copyPage(documentId, page.pageId, targetDocumentId);
});
// Do post-processing after all copying has completed.
all(promises).then(() => {
// For move operation we delete all copied pages.
this.send('onPageDeleted', { id: pageId, children: true });
});
},
@ -108,19 +132,9 @@ export default Controller.extend(Notifier, {
let documentId = this.get('document.id');
let deleteId = deletePage.id;
let deleteChildren = deletePage.children;
let pendingChanges = [];
let pages = this.get('pages');
let pageIndex = _.findIndex(pages, function(i) { return i.get('page.id') === deleteId; });
let item = pages[pageIndex];
// select affected pages
for (var i = pageIndex + 1; i < pages.get('length'); i++) {
if (i === pageIndex + 1 && pages[i].get('page.level') === item.get('page.level')) break;
if (pages[i].get('page.level') <= item.get('page.level')) break;
pendingChanges.push({ pageId: pages[i].get('page.id'), level: pages[i].get('page.level') - 1 });
}
let pendingChanges = this.get('documentService').getChildren(pages, deleteId);
this.set('currentPageId', null);
@ -188,6 +202,12 @@ export default Controller.extend(Notifier, {
});
},
onDuplicate(name) {
this.get('documentService').duplicate(this.get('folder.id'), this.get('document.id'), name).then(() => {
this.notifySuccess('Duplicated');
});
},
onPageSequenceChange(currentPageId, changes) {
this.set('currentPageId', currentPageId);
@ -263,6 +283,36 @@ export default Controller.extend(Notifier, {
});
});
});
},
// Expand all if nothing is expanded at the moment.
// Collapse all if something is expanded at the moment.
onExpandAll() {
let expandState = this.get('localStore').getDocSectionHide(this.get('document.id'));
if (expandState.length === 0) {
let pages = this.get('pages');
pages.forEach((item) => {
expandState.push(item.get('page.id'));
})
} else {
expandState = [];
}
this.get('localStore').setDocSectionHide(this.get('document.id'), expandState);
this.set('expandState', expandState);
},
onExpand(pageId, show) {
let expandState = this.get('localStore').getDocSectionHide(this.get('document.id'));
if (show) {
expandState = _.without(expandState, pageId)
} else {
expandState.push(pageId);
}
this.get('localStore').setDocSectionHide(this.get('document.id'), expandState);
}
}
});

View file

@ -19,6 +19,7 @@ export default Route.extend(AuthenticatedRouteMixin, {
linkService: service('link'),
folderService: service('folder'),
userService: service('user'),
localStore: service('local-storage'),
contributionStatus: '',
approvalStatus: '',
@ -69,6 +70,9 @@ export default Route.extend(AuthenticatedRouteMixin, {
controller.set('blocks', model.blocks);
controller.set('versions', model.versions);
controller.set('attachments', model.attachments);
// For persistence of section expand/collapse state.
controller.set('expandState', this.get('localStore').getDocSectionHide(model.document.id));
},
activate: function () {

View file

@ -1,8 +1,12 @@
{{#layout/master-sidebar}}
{{ui/ui-spacer size=100}}
<div class="section">
{{document/sidebar-meta
<Layout::MasterNavigation />
<Layout::MasterToolbar>
<div class="zone-1">
<Document::DocumentsList @space={{folder}} @docId={{document.id}} />
</div>
<div class="zone-2" />
<div class="zone-3">
{{document/document-toolbar
tab=tab
roles=roles
pages=pages
space=folder
@ -10,128 +14,93 @@
document=document
versions=versions
permissions=permissions
refresh=(action "refresh")
onSaveTemplate=(action "onSaveTemplate")
onSaveDocument=(action "onSaveDocument")
onDuplicate=(action "onDuplicate")
onDocumentDelete=(action "onDocumentDelete")}}
</div>
</Layout::MasterToolbar>
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<Layout::Grid::SidebarGoTop />
<Layout::Grid::SidebarCustomAction>
<i class="dicon {{constants.Icon.Expand}} {{if (gt expandState.length 0) "color-green-500"}}" {{action "onExpandAll"}}>
{{#attach-tooltip showDelay=750}}Expand/collapse{{/attach-tooltip}}
</i>
</Layout::Grid::SidebarCustomAction>
<Ui::UiSpacer @size="200" />
{{document/sidebar-toc
page=page
roles=roles
pages=pages
folder=folder
document=document
permissions=permissions
currentPageId=currentPageId
onShowPage=(action "onShowPage")
onPageLevelChange=(action "onPageLevelChange")
onPageSequenceChange=(action "onPageSequenceChange")}}
</div>
</Layout::Grid::Sidebar>
<Layout::Grid::Content>
<div class="document-meta">
<div class="document-heading">
<h1 class="name">{{document.name}}</h1>
<h2 class="desc">{{document.excerpt}}</h2>
<div class="dates">
{{formatted-date document.created}}
{{#if (not-eq document.created document.revised)}}
&mdash; revised {{formatted-date document.revised}}
{{/if}}
</div>
</div>
</div>
{{document/document-meta
tab=tab
roles=roles
pages=pages
space=folder
spaces=folders
document=document
versions=versions
attachments=attachments
permissions=permissions
contributionStatus=contributionStatus
approvalStatus=approvalStatus}}
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
<div class="text-center">
{{#ui/ui-toolbar dark=false light=true raised=true large=false bordered=true}}
{{ui/ui-toolbar-icon icon=constants.Icon.Index color=constants.Color.Gray tooltip="Table of contents"
selected=(eq sidebarTab "toc") onClick=(action "onSidebarChange" "toc")}}
{{ui/ui-toolbar-icon icon=constants.Icon.Attachment color=constants.Color.Gray tooltip="Attachments"
selected=(eq sidebarTab "files") onClick=(action "onSidebarChange" "files")}}
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{ui/ui-toolbar-icon icon=constants.Icon.Chat color=constants.Color.Gray tooltip="Comments & Feedback"
selected=(eq sidebarTab "feedback") onClick=(action "onSidebarChange" "feedback")}}
{{/if}}
{{/ui/ui-toolbar}}
</div>
</div>
{{ui/ui-spacer size=200}}
{{#if (eq sidebarTab "toc")}}
{{document/sidebar-toc
page=page
{{document/view-content
expandState=expandState
roles=roles
links=links
pages=pages
blocks=blocks
folder=folder
folders=folders
sections=sections
document=document
permissions=permissions
attachments=attachments
currentPageId=currentPageId
onShowPage=(action "onShowPage")
refresh=(action "refresh")
onExpand=(action "onExpand")
onSavePage=(action "onSavePage")
onCopyPage=(action "onCopyPage")
onMovePage=(action "onMovePage")
onDeletePage=(action "onPageDeleted")
onInsertSection=(action "onInsertSection")
onSavePageAsBlock=(action "onSavePageAsBlock")
onPageLevelChange=(action "onPageLevelChange")
onPageSequenceChange=(action "onPageSequenceChange")}}
{{/if}}
{{#if (eq sidebarTab "files")}}
{{document/sidebar-attachment
document=document
permissions=permissions}}
{{/if}}
{{#if (eq sidebarTab "feedback")}}
{{enterprise/sidebar-feedback
document=document
permissions=permissions}}
{{/if}}
{{/layout/master-sidebar}}
{{#layout/master-content}}
{{document/document-toolbar
tab=tab
roles=roles
space=folder
spaces=folders
document=document
versions=versions
permissions=permissions
refresh=(action "refresh")
onSaveTemplate=(action "onSaveTemplate")
onSaveDocument=(action "onSaveDocument")
onDocumentDelete=(action "onDocumentDelete")}}
{{document/document-meta
tab=tab
roles=roles
pages=pages
space=folder
spaces=folders
document=document
versions=versions
permissions=permissions
contributionStatus=contributionStatus
approvalStatus=approvalStatus}}
{{#if contributionStatus}}
{{ui/ui-spacer size=200}}
<div class="document-meta">
<div class="label-workflow-status">
{{contributionStatus}}
</div>
</div>
{{else}}
{{#if approvalStatus}}
{{ui/ui-spacer size=200}}
<div class="document-meta">
<div class="label-workflow-status">
{{approvalStatus}}
</div>
</div>
{{/if}}
{{/if}}
{{ui/ui-spacer size=300}}
<div class="document-meta {{if permissions.documentEdit "cursor-pointer"}}" {{action "onEditMeta"}}>
<div class="document-heading">
<h1 class="name">{{document.name}}</h1>
<h2 class="desc">{{document.excerpt}}</h2>
</div>
</div>
{{document/view-content
roles=roles
links=links
pages=pages
blocks=blocks
folder=folder
folders=folders
sections=sections
document=document
permissions=permissions
attachments=attachments
currentPageId=currentPageId
refresh=(action "refresh")
onSavePage=(action "onSavePage")
onCopyPage=(action "onCopyPage")
onMovePage=(action "onMovePage")
onDeletePage=(action "onPageDeleted")
onInsertSection=(action "onInsertSection")
onSavePageAsBlock=(action "onSavePageAsBlock")
onPageLevelChange=(action "onPageLevelChange")
onPageSequenceChange=(action "onPageSequenceChange")
onAttachmentUpload=(action "onAttachmentUpload")
onAttachmentDelete=(action "onAttachmentDelete")}}
{{/layout/master-content}}
onPageSequenceChange=(action "onPageSequenceChange")
onAttachmentUpload=(action "onAttachmentUpload")
onAttachmentDelete=(action "onAttachmentDelete")}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -19,6 +19,10 @@ export default Controller.extend(Notifier, {
selectedRevision: null,
actions: {
onBack() {
this.get('router').transitionTo('document.index');
},
onRevision(revision) {
this.set('selectedRevision', revision);
},

View file

@ -1,38 +1,47 @@
{{#layout/master-sidebar}}
{{ui/ui-spacer size=300}}
<div class="section">
{{#link-to "document.index"}}
{{ui/ui-button color=constants.Color.Yellow light=true icon=constants.Icon.ArrowLeft label="Document"}}
{{/link-to}}
{{ui/ui-spacer size=400}}
<div class="title">REVISIONS</div>
<div class="list">
{{#each revisions as |revision|}}
<div class="item {{if (eq selectedRevision revision) "selected"}}" {{action "onRevision" revision}}>
<i class={{concat "dicon " constants.Icon.TriangleSmallRight}} />
<div class="name">{{formatted-date revision.created}}</div>
</div>
{{/each}}
</div>
<Layout::MasterNavigation />
<Layout::MasterToolbar>
<div class="zone-1">
{{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}}
{{ui/ui-toolbar-button themed=true uppercase=false
icon=constants.Icon.ArrowLeft label=document.name onClick=(action "onBack")}}
{{/ui/ui-toolbar}}
</div>
{{/layout/master-sidebar}}
<div class="zone-2" />
<div class="zone-3" />
</Layout::MasterToolbar>
{{#layout/master-content}}
{{layout/logo-heading
title="Content Revisions"
desc="Review previous content changes and roll back edits"
icon=constants.Icon.TimeBack}}
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">REVISIONS</div>
<div class="list">
{{#each revisions as |revision|}}
<div class="item {{if (eq selectedRevision revision) "selected"}}" {{action "onRevision" revision}}>
<i class={{concat "dicon " constants.Icon.TriangleSmallRight}} />
<div class="name">{{formatted-date revision.created}}</div>
</div>
{{/each}}
</div>
</div>
</div>
</Layout::Grid::Sidebar>
<Layout::Grid::Content>
{{layout/logo-heading
title="Content Revisions"
desc="Review previous content changes and roll back edits"
icon=constants.Icon.TimeBack}}
{{document/view-revision
pages=pages
folder=folder
document=document
permissions=permissions
revisions=revisions
revision=selectedRevision
onRollback=(action "onRollback")}}
</Layout::Grid::Content>
</Layout::Grid::Container>
{{document/view-revision
pages=pages
folder=folder
document=document
permissions=permissions
revisions=revisions
revision=selectedRevision
onRollback=(action "onRollback")}}
{{/layout/master-content}}

View file

@ -13,6 +13,7 @@ import { inject as service } from '@ember/service';
import Controller from '@ember/controller';
export default Controller.extend({
router: service(),
documentService: service('document'),
actions: {
@ -56,6 +57,6 @@ export default Controller.extend({
this.set('attachments', files);
});
});
},
},
}
});

View file

@ -1,25 +1,27 @@
{{#layout/master-sidebar}}
{{ui/ui-spacer size=300}}
<div class="section">
{{#link-to "document.index" model.folder.id model.folder.slug model.document.id model.document.slug}}
{{ui/ui-button color=constants.Color.Yellow light=true icon=constants.Icon.ArrowLeft label="Document"}}
{{/link-to}}
<Layout::MasterNavigation />
<Layout::MasterToolbar>
<div class="zone-1">
{{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}}
{{ui/ui-toolbar-button themed=true uppercase=false
icon=constants.Icon.ArrowLeft label=model.document.name onClick=(action "onCancel")}}
{{/ui/ui-toolbar}}
</div>
{{/layout/master-sidebar}}
<div class="zone-2" />
<div class="zone-3" />
</Layout::MasterToolbar>
{{#layout/master-content}}
{{document/document-editor
document=model.document
folder=model.folder
page=model.page
<Layout::Container>
{{document/document-editor
document=model.document
folder=model.folder
page=model.page
meta=model.meta
attachments=model.attachments
onCancel=(action "onCancel") onAction=(action "onAction")}}
{{document/section-attachment uploadLabel="Upload Attachments"
editMode=true page=model.page document=model.document
{{document/section-attachment uploadLabel="Upload Attachments"
editMode=true page=model.page document=model.document
files=model.attachments
onAttachmentUpload=(action "onAttachmentUpload")
onAttachmentDelete=(action "onAttachmentDelete")}}
{{/layout/master-content}}
</Layout::Container>

View file

@ -23,6 +23,10 @@ export default Controller.extend(Notifier, {
tab: 'general',
actions: {
onBack() {
this.get('router').transitionTo('document.index');
},
onTab(view) {
this.set('tab', view);
},

View file

@ -1,87 +1,96 @@
{{#layout/master-sidebar}}
{{ui/ui-spacer size=300}}
<div class="section">
{{#link-to "document.index"}}
{{ui/ui-button color=constants.Color.Yellow light=true icon=constants.Icon.ArrowLeft label="Document"}}
{{/link-to}}
{{ui/ui-spacer size=400}}
<div class="title">Document Options</div>
<div class="list">
<div class="item {{if (eq tab "general") "selected"}}" {{action "onTab" "general"}}>
<i class={{concat "dicon " constants.Icon.Settings}} />
<div class="name">Content Settings</div>
</div>
<div class="item {{if (eq tab "category") "selected"}}" {{action "onTab" "category"}}>
<i class={{concat "dicon " constants.Icon.Category}} />
<div class="name">Categories</div>
</div>
<div class="item {{if (eq tab "tag") "selected"}}" {{action "onTab" "tag"}}>
<i class={{concat "dicon " constants.Icon.Tag}} />
<div class="name">Tags</div>
</div>
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{#if model.permissions.documentApprove}}
<div class="item {{if (eq tab "protection") "selected"}}" {{action "onTab" "protection"}}>
<i class={{concat "dicon " constants.Icon.Locked}} />
<div class="name">Change Control</div>
</div>
{{/if}}
{{#if model.permissions.documentVersion}}
<div class="item {{if (eq tab "versions") "selected"}}" {{action "onTab" "versions"}}>
<i class={{concat "dicon " constants.Icon.Copy}} />
<div class="name">Versions</div>
</div>
{{/if}}
{{/if}}
</div>
<Layout::MasterNavigation />
<Layout::MasterToolbar>
<div class="zone-1">
{{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}}
{{ui/ui-toolbar-button themed=true uppercase=false
icon=constants.Icon.ArrowLeft label=model.document.name onClick=(action "onBack")}}
{{/ui/ui-toolbar}}
</div>
{{/layout/master-sidebar}}
<div class="zone-2" />
<div class="zone-3" />
</Layout::MasterToolbar>
{{#layout/master-content}}
{{#if (eq tab "general")}}
{{document/settings-general
space=model.folder
document=model.document
permissions=model.permissions
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">Options</div>
<div class="list">
<div class="item {{if (eq tab "general") "selected"}}" {{action "onTab" "general"}}>
<i class={{concat "dicon " constants.Icon.Settings}} />
<div class="name">Content Settings</div>
</div>
<div class="item {{if (eq tab "category") "selected"}}" {{action "onTab" "category"}}>
<i class={{concat "dicon " constants.Icon.Category}} />
<div class="name">Categories</div>
</div>
<div class="item {{if (eq tab "tag") "selected"}}" {{action "onTab" "tag"}}>
<i class={{concat "dicon " constants.Icon.Tag}} />
<div class="name">Tags</div>
</div>
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{#if model.permissions.documentApprove}}
<div class="item {{if (eq tab "protection") "selected"}}" {{action "onTab" "protection"}}>
<i class={{concat "dicon " constants.Icon.Locked}} />
<div class="name">Change Control</div>
</div>
{{/if}}
{{#if model.permissions.documentVersion}}
<div class="item {{if (eq tab "versions") "selected"}}" {{action "onTab" "versions"}}>
<i class={{concat "dicon " constants.Icon.Copy}} />
<div class="name">Versions</div>
</div>
{{/if}}
{{/if}}
</div>
</div>
</div>
</Layout::Grid::Sidebar>
{{#if (eq tab "category")}}
{{document/settings-category
space=model.folder
document=model.document
permissions=model.permissions
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
<Layout::Grid::Content>
{{#if (eq tab "general")}}
{{document/settings-general
space=model.folder
document=model.document
permissions=model.permissions
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
{{#if (eq tab "tag")}}
{{document/settings-tag
space=model.folder
document=model.document
permissions=model.permissions
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
{{#if (eq tab "category")}}
{{document/settings-category
space=model.folder
document=model.document
permissions=model.permissions
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
{{#if (eq tab "protection")}}
{{document/settings-protection
space=model.folder
spaces=model.folders
document=model.document
permissions=model.permissions
onRefresh=(action "onRefresh")
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
{{#if (eq tab "tag")}}
{{document/settings-tag
space=model.folder
document=model.document
permissions=model.permissions
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
{{#if (eq tab "versions")}}
{{enterprise/settings-version
space=model.folder
spaces=model.folders
document=model.document
permissions=model.permissions
versions=model.versions
onRefresh=(action "onRefresh")
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
{{/layout/master-content}}
{{#if (eq tab "protection")}}
{{document/settings-protection
space=model.folder
spaces=model.folders
document=model.document
permissions=model.permissions
onRefresh=(action "onRefresh")
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
{{#if (eq tab "versions")}}
{{enterprise/settings-version
space=model.folder
spaces=model.folders
document=model.document
permissions=model.permissions
versions=model.versions
onRefresh=(action "onRefresh")
onSaveDocument=(action "onSaveDocument")}}
{{/if}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -18,6 +18,10 @@ export default Controller.extend(Notifier, {
sectionSvc: service('section'),
actions: {
onBack() {
this.get('router').transitionTo('folder.settings');
},
onCancel( /*page*/ ) {
this.get('router').transitionTo('folder.settings', {queryParams: {tab: 'blocks'}});
},

View file

@ -1,18 +1,30 @@
{{#layout/master-sidebar}}
{{ui/ui-spacer size=300}}
<div class="section">
{{#link-to "folder.settings"}}
{{ui/ui-button color=constants.Color.Yellow light=true icon=constants.Icon.ArrowLeft label="Space Settings"}}
{{/link-to}}
<Layout::MasterNavigation />
<Layout::MasterToolbar>
<div class="zone-1">
{{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}}
{{ui/ui-toolbar-button themed=true uppercase=false
icon=constants.Icon.ArrowLeft label=model.space.name onClick=(action "onBack")}}
{{/ui/ui-toolbar}}
</div>
{{/layout/master-sidebar}}
</Layout::MasterToolbar>
{{#layout/master-content}}
{{layout/logo-heading
title="Content Blocks"
desc="Content blocks provide re-usable content that can be inserted into any document"
icon=constants.Icon.Integrations}}
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">about</div>
<div class="text">Manage reusable snippets of content for this space</div>
</div>
</div>
</Layout::Grid::Sidebar>
{{document/block-editor document=model.document folder=model.folder block=model.block
onCancel=(action "onCancel") onAction=(action "onAction")}}
{{/layout/master-content}}
<Layout::Grid::Content>
{{layout/logo-heading
title="Content Blocks"
desc="Content blocks provide re-usable content that can be inserted into any document"
icon=constants.Icon.Integrations}}
{{document/block-editor document=model.document folder=model.space block=model.block
onCancel=(action "onCancel") onAction=(action "onAction")}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -15,6 +15,7 @@ import NotifierMixin from '../../../mixins/notifier';
import Controller from '@ember/controller';
export default Controller.extend(NotifierMixin, {
router: service(),
documentService: service('document'),
folderService: service('folder'),
localStorage: service('localStorage'),
@ -25,7 +26,7 @@ export default Controller.extend(NotifierMixin, {
filteredDocs: null,
// eslint-disable-next-line ember/avoid-leaking-state-in-ember-objects
sortBy: {
name: true,
name: true,
created: false,
updated: false,
asc: true,
@ -33,6 +34,10 @@ export default Controller.extend(NotifierMixin, {
},
actions: {
onBack() {
this.get('router').transitionTo('folders');
},
onRefresh() {
this.get('target._routerMicrolib').refresh();
},
@ -93,25 +98,25 @@ export default Controller.extend(NotifierMixin, {
if (_.isNull(docs)) return;
if (sortBy.name) {
if (sortBy.name) {
docs = docs.sortBy('name');
ls.storeSessionItem('space.sortBy', 'name');
}
if (sortBy.created) {
if (sortBy.created) {
docs = docs.sortBy('created');
ls.storeSessionItem('space.sortBy', 'created');
}
if (sortBy.updated) {
if (sortBy.updated) {
docs = docs.sortBy('revised');
ls.storeSessionItem('space.sortBy', 'updated');
}
if (sortBy.desc) {
if (sortBy.desc) {
docs = docs.reverseObjects();
ls.storeSessionItem('space.sortOrder', 'desc');
} else {
ls.storeSessionItem('space.sortOrder', 'asc');
}
this.set('filteredDocs', docs);
}
}

View file

@ -44,11 +44,14 @@ export default Route.extend(AuthenticatedRouteMixin, {
d.set('selected', false);
});
let labelId = this.modelFor('folder').folder.get('labelId');
return hash({
folder: this.modelFor('folder').folder,
permissions: this.modelFor('folder').permissions,
label: _.find(this.modelFor('folder').labels, {id: this.modelFor('folder').folder.get('labelId')}),
label: _.find(this.modelFor('folder').labels, {id: labelId}),
labels: this.modelFor('folder').labels,
labelSpaces: _.filter(folders, function(s) { return s.get('labelId') === labelId; }),
folders: folders,
documents: documents,
documentsDraft: _.filter(documents, function(d) { return d.get('lifecycle') === constants.Lifecycle.Draft; }),

View file

@ -1,4 +1,26 @@
{{#layout/master-sidebar}}
<Layout::MasterNavigation />
<Layout::MasterToolbar>
<div class="zone-1">
{{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}}
{{ui/ui-toolbar-button themed=true uppercase=true
icon=constants.Icon.ArrowLeft label=constants.Label.Spaces onClick=(action "onBack")}}
{{/ui/ui-toolbar}}
</div>
<div class="zone-2" />
<div class="zone-3">
{{folder/space-toolbar
spaces=model.folders
space=model.folder
permissions=model.permissions
templates=model.templates
category=category
categories=model.categories
documents=filteredDocs
onRefresh=(action "onRefresh")}}
</div>
</Layout::MasterToolbar>
<Layout::Grid::Container>
{{folder/space-sidebar
spaces=model.folders
space=model.folder
@ -17,43 +39,42 @@
categoryFilter=category
onFiltered=(action "onFiltered")
onRefresh=(action "onRefresh")}}
{{/layout/master-sidebar}}
{{#layout/master-content}}
<div class="grid-container-6-4">
<div class="grid-cell-1">
{{#if (eq model.folder.labelId "")}}
<div class="space-label">Unclassified</div>
{{else}}
<div class="space-label" style={{{model.label.bgColor}}}>{{model.label.name}}</div>
<Layout::Grid::Content>
{{#if (eq model.folder.labelId "")}}
<div class="space-label">Unclassified</div>
{{else}}
<div class="space-label" style={{{model.label.bgColor}}}>{{model.label.name}}</div>
{{#if (gt model.labelSpaces.length 1)}}
<i class="space-label-dropdown dicon {{constants.Icon.ArrowSmallDown}}">
{{#attach-popover class="ember-attacher-popper" hideOn="click clickout" showOn="click" isShown=false placement="bottom-middle"}}
<ul class="menu">
{{#each model.labelSpaces as |space|}}
{{#if (not-eq space.id model.folder.id)}}
{{#link-to "folder.index" space.id space.slug class="item"}}{{space.name}}{{/link-to}}
{{/if}}
{{/each}}
</ul>
{{/attach-popover}}
</i>
{{/if}}
{{layout/logo-heading
title=model.folder.name
desc=model.folder.desc
meta=model.folder.icon}}
</div>
<div class="grid-cell-2 grid-cell-right">
{{folder/space-toolbar
spaces=model.folders
space=model.folder
permissions=model.permissions
templates=model.templates
category=category
categories=model.categories
documents=filteredDocs
onRefresh=(action "onRefresh")}}
</div>
</div>
{{folder/documents-list
documents=filteredDocs
spaces=model.folders
space=model.folder
templates=model.templates
permissions=model.permissions
sortBy=sortBy
onFiltered=(action "onFiltered")
onExportDocument=(action "onExportDocument")
onDeleteDocument=(action "onDeleteDocument")
onMoveDocument=(action "onMoveDocument")}}
{{/layout/master-content}}
{{/if}}
{{layout/logo-heading
title=model.folder.name
desc=model.folder.desc
meta=model.folder.icon}}
{{folder/documents-list
documents=filteredDocs
spaces=model.folders
space=model.folder
templates=model.templates
permissions=model.permissions
sortBy=sortBy
onFiltered=(action "onFiltered")
onExportDocument=(action "onExportDocument")
onDeleteDocument=(action "onDeleteDocument")
onMoveDocument=(action "onMoveDocument")}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -22,6 +22,10 @@ export default Controller.extend(NotifierMixin, {
tab: 'general',
actions: {
onBack() {
this.get('router').transitionTo('folder.index');
},
onTab(view) {
this.set('tab', view);
},

View file

@ -1,75 +1,81 @@
{{#layout/master-sidebar}}
{{ui/ui-spacer size=300}}
<div class="section">
{{#link-to "folder.index"}}
{{ui/ui-button color=constants.Color.Yellow light=true icon=constants.Icon.ArrowLeft label="Space"}}
{{/link-to}}
{{ui/ui-spacer size=400}}
<div class="title">space management</div>
<div class="list">
<div class="item {{if (eq tab "general") "selected"}}" {{action "onTab" "general"}}>
<i class={{concat "dicon " constants.Icon.Settings}} />
<div class="name">Meta</div>
</div>
<div class="item {{if (eq tab "categories") "selected"}}" {{action "onTab" "categories"}}>
<i class={{concat "dicon " constants.Icon.Category}} />
<div class="name">Categories</div>
</div>
<div class="item {{if (eq tab "permissions") "selected"}}" {{action "onTab" "permissions"}}>
<i class={{concat "dicon " constants.Icon.Locked}} />
<div class="name">Permissions</div>
</div>
<div class="item {{if (eq tab "blocks") "selected"}}" {{action "onTab" "blocks"}}>
<i class={{concat "dicon " constants.Icon.Blocks}} />
<div class="name">Content Blocks</div>
</div>
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
<div class="item {{if (eq tab "archived") "selected"}}" {{action "onTab" "archived"}}>
<i class={{concat "dicon " constants.Icon.Archive}} />
<div class="name">Archived Content</div>
</div>
{{/if}}
{{#if model.permissions.spaceOwner}}
<div class="item {{if (eq tab "deletion") "selected"}}" {{action "onTab" "deletion"}}>
<i class={{concat "dicon " constants.Icon.Delete}} />
<div class="name">Deletion</div>
</div>
{{/if}}
</div>
<Layout::MasterNavigation />
<Layout::MasterToolbar>
<div class="zone-1">
{{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}}
{{ui/ui-toolbar-button themed=true uppercase=false
icon=constants.Icon.ArrowLeft label=model.folder.name onClick=(action "onBack")}}
{{/ui/ui-toolbar}}
</div>
{{/layout/master-sidebar}}
</Layout::MasterToolbar>
{{#layout/master-content}}
{{#if (eq tab "general")}}
{{folder/settings-general permissions=model.permissions space=model.folder labels=model.labels}}
{{/if}}
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">space management</div>
<div class="list">
<div class="item {{if (eq tab "general") "selected"}}" {{action "onTab" "general"}}>
<i class={{concat "dicon " constants.Icon.Settings}} />
<div class="name">Meta</div>
</div>
<div class="item {{if (eq tab "categories") "selected"}}" {{action "onTab" "categories"}}>
<i class={{concat "dicon " constants.Icon.Category}} />
<div class="name">Categories</div>
</div>
<div class="item {{if (eq tab "permissions") "selected"}}" {{action "onTab" "permissions"}}>
<i class={{concat "dicon " constants.Icon.Locked}} />
<div class="name">Permissions</div>
</div>
<div class="item {{if (eq tab "blocks") "selected"}}" {{action "onTab" "blocks"}}>
<i class={{concat "dicon " constants.Icon.Blocks}} />
<div class="name">Content Blocks</div>
</div>
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
<div class="item {{if (eq tab "archived") "selected"}}" {{action "onTab" "archived"}}>
<i class={{concat "dicon " constants.Icon.Archive}} />
<div class="name">Archived Content</div>
</div>
{{/if}}
{{#if model.permissions.spaceOwner}}
<div class="item {{if (eq tab "deletion") "selected"}}" {{action "onTab" "deletion"}}>
<i class={{concat "dicon " constants.Icon.Delete}} />
<div class="name">Deletion</div>
</div>
{{/if}}
</div>
</div>
</div>
</Layout::Grid::Sidebar>
{{#if (eq tab "permissions")}}
{{folder/settings-permissions permissions=model.permissions folders=model.folders folder=model.folder onRefresh=(action "onRefresh")}}
{{/if}}
{{#if (eq tab "templates")}}
{{folder/settings-templates permissions=model.permissions space=model.folder templates=model.templates}}
{{/if}}
{{#if (eq tab "blocks")}}
{{folder/settings-blocks permissions=model.permissions space=model.folder}}
{{/if}}
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{#if (eq tab "archived")}}
{{enterprise/space-archived permissions=model.permissions spaces=model.folder space=model.folder}}
<Layout::Grid::Content>
{{#if (eq tab "general")}}
{{folder/settings-general permissions=model.permissions space=model.folder labels=model.labels}}
{{/if}}
{{/if}}
{{#if (eq tab "categories")}}
{{folder/settings-category permissions=model.permissions spaces=model.folder space=model.folder}}
{{/if}}
{{#if (eq tab "permissions")}}
{{folder/settings-permissions permissions=model.permissions folders=model.folders folder=model.folder onRefresh=(action "onRefresh")}}
{{/if}}
{{#if (eq tab "deletion")}}
{{folder/settings-delete permissions=model.permissions spaces=model.folder space=model.folder}}
{{/if}}
{{/layout/master-content}}
{{#if (eq tab "templates")}}
{{folder/settings-templates permissions=model.permissions space=model.folder templates=model.templates}}
{{/if}}
{{#if (eq tab "blocks")}}
{{folder/settings-blocks permissions=model.permissions space=model.folder}}
{{/if}}
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{#if (eq tab "archived")}}
{{enterprise/space-archived permissions=model.permissions spaces=model.folder space=model.folder}}
{{/if}}
{{/if}}
{{#if (eq tab "categories")}}
{{folder/settings-category permissions=model.permissions spaces=model.folder space=model.folder}}
{{/if}}
{{#if (eq tab "deletion")}}
{{folder/settings-delete permissions=model.permissions spaces=model.folder space=model.folder}}
{{/if}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -1,138 +1,142 @@
{{#layout/master-sidebar selectedItem="spaces"}}
{{ui/ui-spacer size=300}}
<div class="section">
<div class="title">filter</div>
<div class="list">
<div class="item {{if (eq selectedView "all") "selected"}}" {{action "onSelect" "all"}}>
<i class={{concat "dicon " constants.Icon.All}} />
<div class="name">All ({{model.spaces.length}})</div>
</div>
<div class="item {{if (eq selectedView "public") "selected"}}" {{action "onSelect" "public"}}>
<i class={{concat "dicon " constants.Icon.World}} />
<div class="name">Public ({{publicSpaces.length}})</div>
</div>
{{#if session.authenticated}}
<div class="item {{if (eq selectedView "protected") "selected"}}" {{action "onSelect" "protected"}}>
<i class={{concat "dicon " constants.Icon.People}} />
<div class="name">Protected ({{protectedSpaces.length}})</div>
</div>
<div class="item {{if (eq selectedView "personal") "selected"}}" {{action "onSelect" "personal"}}>
<i class={{concat "dicon " constants.Icon.Person}} />
<div class="name">Personal ({{personalSpaces.length}})</div>
</div>
{{/if}}
</div>
</div>
{{ui/ui-spacer size=300}}
<div class="section">
<div class="title">label</div>
{{#if labels}}
<div class="list">
{{#each labels as |label|}}
{{#if (gt label.count 0)}}
<div class="item {{if (eq selectedView label.id) "selected"}}" {{action "onSelect" label.id}}>
<i class={{concat "dicon label-color " constants.Icon.Checkbox}} style={{label.bgfgColor}}/>
<div class="name">{{label.name}} ({{label.count}})</div>
</div>
{{/if}}
{{/each}}
</div>
{{else}}
<div class="empty">No labels</div>
<Layout::MasterNavigation @selectedItem="spaces" />
<Layout::MasterToolbar>
<div class="zone-1" />
<div class="zone-2" />
<div class="zone-3">
{{#if (or session.isEditor session.isAdmin)}}
{{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}}
{{#if session.isEditor}}
{{ui/ui-toolbar-button icon=constants.Icon.Plus color=constants.Color.Green
label=constants.Label.Space onClick=(action "onShowModal")}}
{{ui/ui-toolbar-divider}}
{{/if}}
{{#if session.isAdmin}}
{{ui/ui-toolbar-icon icon=constants.Icon.Settings color=constants.Color.Green
tooltip="Space settings" linkTo="customize"}}
{{/if}}
{{/ui/ui-toolbar}}
{{/if}}
</div>
{{/layout/master-sidebar}}
</Layout::MasterToolbar>
{{#layout/master-content}}
<div class="grid-container-8-2">
<div class="grid-cell-1">
{{layout/logo-heading
title=appMeta.title
desc=appMeta.message
logo=true}}
</div>
<div class="grid-cell-2 grid-cell-right">
{{#if (or session.isEditor session.isAdmin)}}
{{#ui/ui-toolbar dark=false light=true raised=true large=true bordered=true tooltip="New space"}}
{{#if session.isEditor}}
{{ui/ui-toolbar-icon icon=constants.Icon.Plus color=constants.Color.Green onClick=(action "onShowModal")}}
{{ui/ui-toolbar-label label="SPACE" color=constants.Color.Green onClick=(action "onShowModal")}}
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">filter</div>
<div class="list">
<div class="item {{if (eq selectedView "all") "selected"}}" {{action "onSelect" "all"}}>
<i class={{concat "dicon " constants.Icon.All}} />
<div class="name">All ({{model.spaces.length}})</div>
</div>
<div class="item {{if (eq selectedView "public") "selected"}}" {{action "onSelect" "public"}}>
<i class={{concat "dicon " constants.Icon.World}} />
<div class="name">Public ({{publicSpaces.length}})</div>
</div>
{{#if session.authenticated}}
<div class="item {{if (eq selectedView "protected") "selected"}}" {{action "onSelect" "protected"}}>
<i class={{concat "dicon " constants.Icon.People}} />
<div class="name">Protected ({{protectedSpaces.length}})</div>
</div>
<div class="item {{if (eq selectedView "personal") "selected"}}" {{action "onSelect" "personal"}}>
<i class={{concat "dicon " constants.Icon.Person}} />
<div class="name">Personal ({{personalSpaces.length}})</div>
</div>
{{/if}}
{{/ui/ui-toolbar}}
{{/if}}
</div>
</div>
<Ui::UiSpacer @size="300" />
<div class="section">
<div class="title">label</div>
{{#if labels}}
<div class="list">
{{#each labels as |label|}}
{{#if (gt label.count 0)}}
<div class="item {{if (eq selectedView label.id) "selected"}}" {{action "onSelect" label.id}}>
<i class={{concat "dicon label-color " constants.Icon.Checkbox}} style={{label.bgfgColor}}/>
<div class="name">{{label.name}} ({{label.count}})</div>
</div>
{{/if}}
{{/each}}
</div>
{{else}}
<div class="empty">No labels</div>
{{/if}}
</div>
</div>
</div>
</Layout::Grid::Sidebar>
{{ui/ui-spacer size=400}}
<Layout::Grid::Content>
{{layout/logo-heading title=appMeta.title desc=appMeta.message logo=true}}
{{spaces/space-list spaces=selectedSpaces labels=labels}}
{{spaces/space-list spaces=selectedSpaces labels=labels}}
<div class="modal" tabindex="-1" role="dialog" id="add-space-modal">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">New Space</div>
<div class="modal-body">
<form onsubmit={{action "onAddSpace"}}>
<div class="form-group">
<label for="new-space-name">Name</label>
{{input type="text" id="new-space-name" class="form-control mousetrap" placeholder="Space name" value=spaceName}}
<small class="form-text text-muted">Characters and numbers only</small>
</div>
<div class="modal" tabindex="-1" role="dialog" id="add-space-modal">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">New Space</div>
<div class="modal-body">
<form onsubmit={{action "onAddSpace"}}>
<div class="form-group">
<label for="new-space-name">Name</label>
{{input type="text" id="new-space-name" class="form-control mousetrap" placeholder="Space name" value=spaceName}}
<small class="form-text text-muted">Characters and numbers only</small>
</div>
<div class="form-group">
<label>Description</label>
{{focus-input id="space-desc" type="text" value=spaceDesc class="form-control" placeholder="Space description" autocomplete="off"}}
</div>
<div class="form-group">
<label>Description</label>
{{focus-input id="space-desc" type="text" value=spaceDesc class="form-control" placeholder="Space description" autocomplete="off"}}
</div>
<div class="form-group">
<label>Icon</label>
<div class="ui-icon-picker">
<ul class="list">
{{#each iconList as |icon|}}
<li class="item {{if (eq spaceIcon icon) "selected"}}" {{action "onSetIcon" icon}}>
{{ui/ui-icon-meta icon=icon}}
<div class="form-group">
<label>Icon</label>
<div class="ui-icon-picker">
<ul class="list">
{{#each iconList as |icon|}}
<li class="item {{if (eq spaceIcon icon) "selected"}}" {{action "onSetIcon" icon}}>
{{ui/ui-icon-meta icon=icon}}
</li>
{{/each}}
</ul>
</div>
</div>
<div class="form-group">
<label>Label</label>
<ul class="space-label-picker">
<li class="label none {{if (eq spaceLabel "") "selected"}}" {{action "onSetLabel" ""}}>None</li>
{{#each labels as |label|}}
<li class="label {{if (eq spaceLabel label.id) "selected"}}"
style={{label.bgColor}}
{{action "onSetLabel" label.id}} title={{label.name}}>
{{label.name}}
</li>
{{/each}}
</ul>
</div>
</div>
<div class="form-group">
<label>Label</label>
<ul class="space-label-picker">
<li class="label none {{if (eq spaceLabel "") "selected"}}" {{action "onSetLabel" ""}}>None</li>
{{#each labels as |label|}}
<li class="label {{if (eq spaceLabel label.id) "selected"}}"
style={{label.bgColor}}
{{action "onSetLabel" label.id}} title={{label.name}}>
{{label.name}}
</li>
{{/each}}
</ul>
</div>
<div class="form-group">
<label for="clone-space-dropdown">Clone Space</label>
{{ui/ui-select id="clone-space-dropdown" content=spaces prompt="select space" action=(action "onCloneSpaceSelect") optionValuePath="id" optionLabelPath="name" selection=clonedSpace}}
<small id="emailHelp" class="form-text text-muted">Copy templates, permissions, documents from existing space</small>
<div class="margin-top-10" />
{{#if hasClone}}
{{#ui/ui-checkbox selected=copyTemplate}}Copy templates{{/ui/ui-checkbox}}
{{#ui/ui-checkbox selected=copyPermission}}Copy permissions{{/ui/ui-checkbox}}
{{#ui/ui-checkbox selected=copyDocument}}Copy documents{{/ui/ui-checkbox}}
{{/if}}
</div>
</form>
</div>
<div class="modal-footer">
{{ui/ui-button color=constants.Color.Gray light=true label=constants.Label.Cancel dismiss=true}}
{{ui/ui-button-gap}}
{{ui/ui-button color=constants.Color.Green light=true label=constants.Label.Add onClick=(action "onAddSpace")}}
<div class="form-group">
<label for="clone-space-dropdown">Clone Space</label>
{{ui/ui-select id="clone-space-dropdown" content=spaces prompt="select space" action=(action "onCloneSpaceSelect") optionValuePath="id" optionLabelPath="name" selection=clonedSpace}}
<small id="emailHelp" class="form-text text-muted">Copy templates, permissions, documents from existing space</small>
<div class="margin-top-10" />
{{#if hasClone}}
{{#ui/ui-checkbox selected=copyTemplate}}Copy templates{{/ui/ui-checkbox}}
{{#ui/ui-checkbox selected=copyPermission}}Copy permissions{{/ui/ui-checkbox}}
{{#ui/ui-checkbox selected=copyDocument}}Copy documents{{/ui/ui-checkbox}}
{{/if}}
</div>
</form>
</div>
<div class="modal-footer">
{{ui/ui-button color=constants.Color.Gray light=true label=constants.Label.Cancel dismiss=true}}
{{ui/ui-button-gap}}
{{ui/ui-button color=constants.Color.Green light=true label=constants.Label.Add onClick=(action "onAddSpace")}}
</div>
</div>
</div>
</div>
</div>
{{/layout/master-content}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -1,11 +1,26 @@
{{#layout/master-sidebar}}
{{/layout/master-sidebar}}
<Layout::MasterNavigation />
<Layout::MasterToolbar />
{{#layout/master-content}}
{{layout/logo-heading
title=session.user.fullname
desc="Manage you profile and password"
icon=constants.Icon.Person}}
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">PROFILE</div>
<div class="text">
Set your personal information or reset your password.
</div>
<div class="text">
Have a product idea, suggestion or some feedback? <a href="mailto:support@documize.com">Get in touch.</a>
</div>
</div>
</div>
</Layout::Grid::Sidebar>
<Layout::Grid::Content>
{{layout/logo-heading
title=session.user.fullname
desc="Manage your profile and password"
icon=constants.Icon.Person}}
{{user/user-profile model=model save=(action "save")}}
{{/layout/master-content}}
{{user/user-profile model=model save=(action "save")}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -1,75 +1,79 @@
{{#layout/master-sidebar selectedItem="search"}}
{{ui/ui-spacer size=300}}
<Layout::MasterNavigation @selectedItem="search" />
<Layout::MasterToolbar />
<div class="section">
<div class="title">Match Filter</div>
<div class="list">
<div class="item">
{{input id="search-1" type="checkbox" checked=matchFilter.matchDoc}}
<label for="search-1" class="name">Document name</label>
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">Match Filter</div>
<div class="list">
<div class="item">
{{input id="search-1" type="checkbox" checked=matchFilter.matchDoc}}
<label for="search-1" class="name">Document name</label>
</div>
<div class="item">
{{input id="search-2" type="checkbox" checked=matchFilter.matchContent}}
<label for="search-2" class="name">Document content</label>
</div>
<div class="item">
{{input id="search-3" type="checkbox" checked=matchFilter.matchTag}}
<label for="search-3" class="name">Tag name</label>
</div>
<div class="item">
{{input id="search-4" type="checkbox" checked=matchFilter.matchFile}}
<label for="search-4" class="name">Attachment name</label>
</div>
</div>
</div>
<div class="item">
{{input id="search-2" type="checkbox" checked=matchFilter.matchContent}}
<label for="search-2" class="name">Document content</label>
</div>
<div class="item">
{{input id="search-3" type="checkbox" checked=matchFilter.matchTag}}
<label for="search-3" class="name">Tag name</label>
</div>
<div class="item">
{{input id="search-4" type="checkbox" checked=matchFilter.matchFile}}
<label for="search-4" class="name">Attachment name</label>
<Ui::UiSpacer @size="200" />
<div class="section">
<div class="title">query examples</div>
<div class="view-search">
{{#if (eq appMeta.storageProvider constants.StoreProvider.MySQL)}}
<div class="syntax">
<div class="example">apple banana</div>
<div class="explain">Show results that contain at least one of the two words</div>
<div class="example">+apple +banana</div>
<div class="explain">Show results that contain both words</div>
<div class="example">+apple macintosh</div>
<div class="explain">Show results that contain the word "apple", but rank rows higher if they also contain "macintosh"</div>
<div class="example">+apple -macintosh</div>
<div class="explain">Show results that contain the word "apple" but not "macintosh"</div>
<div class="example">+apple +(&gt;turnover &lt;strudel)</div>
<div class="explain">Show results that contain the words "apple" and "turnover", or "apple" and "strudel" (in any order), but rank "apple turnover" higher than "apple strudel"</div>
<div class="example">apple*</div>
<div class="explain">Show results that contain words such as "apple", "apples", "applesauce", or "applet"</div>
<div class="example">"some words"</div>
<div class="explain">Show results that contain the exact phrase "some words" (for example, rows that contain "some words of wisdom" but not "some noise words")</div>
</div>
{{/if}}
{{#if (eq appMeta.storageProvider constants.StoreProvider.PostgreSQL)}}
<div class="syntax">
<div class="example">apple | banana</div>
<div class="explain">Show results that contain at either word</div>
<div class="example">apple & banana</div>
<div class="explain">Show results that contain both words</div>
<div class="example">apple !macintosh</div>
<div class="explain">Show results that contain the word "apple" but not "macintosh"</div>
<div class="example">google & (apple | microsoft) & !ibm</div>
<div class="explain">Show results that have "google", either "apple" or "microsoft" but not "ibm"</div>
</div>
{{/if}}
{{#if (eq appMeta.storageProvider constants.StoreProvider.SQLServer)}}
{{/if}}
</div>
</div>
</div>
</div>
{{ui/ui-spacer size=200}}
</Layout::Grid::Sidebar>
<div class="section">
<div class="title">query examples</div>
<div class="view-search">
{{#if (eq appMeta.storageProvider constants.StoreProvider.MySQL)}}
<div class="syntax">
<div class="example">apple banana</div>
<div class="explain">Show results that contain at least one of the two words</div>
<div class="example">+apple +banana</div>
<div class="explain">Show results that contain both words</div>
<div class="example">+apple macintosh</div>
<div class="explain">Show results that contain the word "apple", but rank rows higher if they also contain "macintosh"</div>
<div class="example">+apple -macintosh</div>
<div class="explain">Show results that contain the word "apple" but not "macintosh"</div>
<div class="example">+apple +(&gt;turnover &lt;strudel)</div>
<div class="explain">Show results that contain the words "apple" and "turnover", or "apple" and "strudel" (in any order), but rank "apple turnover" higher than "apple strudel"</div>
<div class="example">apple*</div>
<div class="explain">Show results that contain words such as "apple", "apples", "applesauce", or "applet"</div>
<div class="example">"some words"</div>
<div class="explain">Show results that contain the exact phrase "some words" (for example, rows that contain "some words of wisdom" but not "some noise words")</div>
</div>
{{/if}}
{{#if (eq appMeta.storageProvider constants.StoreProvider.PostgreSQL)}}
<div class="syntax">
<div class="example">apple | banana</div>
<div class="explain">Show results that contain at either word</div>
<div class="example">apple & banana</div>
<div class="explain">Show results that contain both words</div>
<div class="example">apple !macintosh</div>
<div class="explain">Show results that contain the word "apple" but not "macintosh"</div>
<div class="example">google & (apple | microsoft) & !ibm</div>
<div class="explain">Show results that have "google", either "apple" or "microsoft" but not "ibm"</div>
</div>
{{/if}}
{{#if (eq appMeta.storageProvider constants.StoreProvider.SQLServer)}}
{{/if}}
</div>
</div>
{{/layout/master-sidebar}}
<Layout::Grid::Content>
{{layout/logo-heading
title="Search"
desc="Find content"
icon=constants.Icon.Search}}
{{#layout/master-content}}
{{layout/logo-heading
title="Search"
desc="Find content"
icon=constants.Icon.Search}}
{{search/search-view
filter=filter
matchFilter=matchFilter}}
{{/layout/master-content}}
{{search/search-view
filter=filter
matchFilter=matchFilter}}
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -12,4 +12,7 @@
import Route from '@ember/routing/route';
export default Route.extend({
activate() {
this.get('browser').setTitle('Product News');
}
});

View file

@ -1,26 +1,40 @@
{{#layout/master-sidebar}}
{{ui/ui-spacer size=300}}
<div class="section">
<div class="title">SUMMARY</div>
{{ui/ui-spacer size=100}}
<p>Documize {{appMeta.edition}} Edition</p>
<p>Version {{appMeta.version}}</p>
<p>Build {{appMeta.revision}}</p>
</div>
{{/layout/master-sidebar}}
{{#layout/master-content}}
{{layout/logo-heading
title="Product News"
desc="Latest product news and updates from Documize Inc."
icon=constants.Icon.Announce}}
<div class="product-news">
{{{newsContent}}}
<div class="action">
Have an idea? Suggestion or feedback? <a href="mailto:support@documize.com">Get in touch!</a>
<Layout::MasterNavigation />
<Layout::MasterToolbar>
<div class="zone-1" />
<div class="zone-2">
<div class="label color-gray-700">
Documize {{appMeta.edition}} Edition {{appMeta.version}} (build {{appMeta.revision}})
</div>
</div>
{{/layout/master-content}}
<div class="zone-3" />
</Layout::MasterToolbar>
<Layout::Grid::Container>
<Layout::Grid::Sidebar>
<div class="sidebar-content">
<div class="section">
<div class="title">ABOUT</div>
<div class="text">
Documize product updates are released frequently for both
cloud and self-hosted customers.
</div>
<div class="text">
Have an idea, suggestion or some feedback? <a href="mailto:support@documize.com">Get in touch.</a>
</div>
</div>
</div>
</Layout::Grid::Sidebar>
<Layout::Grid::Content>
{{layout/logo-heading
title="Product News"
desc="Latest product news and updates"
icon=constants.Icon.Announce}}
<div class="product-news">
{{{newsContent}}}
<div class="action">
Have an idea? Suggestion or feedback? <a href="mailto:support@documize.com">Get in touch!</a>
</div>
</div>
</Layout::Grid::Content>
</Layout::Grid::Container>

View file

@ -78,6 +78,21 @@ export default Service.extend({
});
},
// Duplicate creates a copy.
duplicate(spaceId, docId, docName) {
let data = {
spaceId: spaceId,
documentId: docId,
documentName: docName
};
return this.get('ajax').request(`document/duplicate`, {
method: 'POST',
data: JSON.stringify(data)
});
},
//**************************************************
// Page
//**************************************************
@ -168,6 +183,22 @@ export default Service.extend({
});
},
// Given a page ID, return all children of the starting page.
getChildren(pages, pageId) {
let children = [];
let pageIndex = _.findIndex(pages, function(i) { return i.get('page.id') === pageId; });
let item = pages[pageIndex];
for (var i = pageIndex + 1; i < pages.get('length'); i++) {
if (i === pageIndex + 1 && pages[i].get('page.level') === item.get('page.level')) break;
if (pages[i].get('page.level') <= item.get('page.level')) break;
children.push({ pageId: pages[i].get('page.id'), level: pages[i].get('page.level') - 1 });
}
return children;
},
//**************************************************
// Page Revisions
//**************************************************

View file

@ -26,5 +26,24 @@ export default Service.extend({
clearAll() {
localStorage.clear();
}
},
getDocSectionHide(docId) {
let state = localStorage[`doc-hide-${docId}`];
if (_.isUndefined(state) || _.isEmpty(state)) {
return [];
}
return _.split(state, '|');
},
setDocSectionHide(docId, state) {
let key = `doc-hide-${docId}`;
if (state.length === 0) {
delete localStorage[key];
} else {
localStorage[key] = _.join(state, '|');
}
},
});

View file

@ -17,7 +17,7 @@
**************************************************************/
/**************************************************************
* Gray, Grey shades
* Gray shades
**************************************************************/
$gray-shades: (
900: #1F2833,
@ -153,9 +153,11 @@ $color-white-dark-1: #f5f5f5;
* Specialty colors
**************************************************************/
// Documents, spaces card background color
// Documents and spaces card background color
$color-card: #F6F4EE;
$color-sidebar: #f2f8fd;
$color-sidebar: #F6F4EE;
// $color-card: #F6F4EE;
// $color-sidebar: #f2f8fd;
/**************************************************************
* Theme colors.

View file

@ -160,269 +160,289 @@ icons
-------------------------*/
.dicon-delete-key::before {
content: "\ea02";
}
content: "\ea02";
}
.dicon-i-remove::before {
content: "\ea03";
}
.dicon-i-remove::before {
content: "\ea03";
}
.dicon-bin::before {
content: "\ea04";
}
.dicon-bin::before {
content: "\ea04";
}
.dicon-attachment::before {
content: "\ea06";
}
.dicon-attachment::before {
content: "\ea06";
}
.dicon-pen-2::before {
content: "\ea08";
}
.dicon-pen-2::before {
content: "\ea08";
}
.dicon-settings-gear::before {
content: "\ea0c";
}
.dicon-settings-gear::before {
content: "\ea0c";
}
.dicon-small-down::before {
content: "\ea11";
}
.dicon-small-down::before {
content: "\ea11";
}
.dicon-small-left::before {
content: "\ea12";
}
.dicon-small-left::before {
content: "\ea12";
}
.dicon-small-right::before {
content: "\ea13";
}
.dicon-small-right::before {
content: "\ea13";
}
.dicon-small-up::before {
content: "\ea14";
}
.dicon-small-up::before {
content: "\ea14";
}
.dicon-small-triangle-down::before {
content: "\ea15";
}
.dicon-small-triangle-down::before {
content: "\ea15";
}
.dicon-small-triangle-left::before {
content: "\ea16";
}
.dicon-small-triangle-left::before {
content: "\ea16";
}
.dicon-small-triangle-right::before {
content: "\ea17";
}
.dicon-small-triangle-right::before {
content: "\ea17";
}
.dicon-small-triangle-up::before {
content: "\ea18";
}
.dicon-small-triangle-up::before {
content: "\ea18";
}
.dicon-arrow-down-2::before {
content: "\ea19";
}
.dicon-arrow-down-2::before {
content: "\ea19";
}
.dicon-arrow-left-2::before {
content: "\ea1a";
}
.dicon-arrow-left-2::before {
content: "\ea1a";
}
.dicon-arrow-right-2::before {
content: "\ea1b";
}
.dicon-arrow-right-2::before {
content: "\ea1b";
}
.dicon-arrow-up-2::before {
content: "\ea1c";
}
.dicon-arrow-up-2::before {
content: "\ea1c";
}
.dicon-chart-bar-33::before {
content: "\ea1d";
}
.dicon-chart-bar-33::before {
content: "\ea1d";
}
.dicon-geometry::before {
content: "\ea1e";
}
.dicon-geometry::before {
content: "\ea1e";
}
.dicon-bookmark::before {
content: "\ea1f";
}
.dicon-bookmark::before {
content: "\ea1f";
}
.dicon-bookmark-delete::before {
content: "\ea20";
}
.dicon-bookmark-delete::before {
content: "\ea20";
}
.dicon-bookmark-add::before {
content: "\ea22";
}
.dicon-bookmark-add::before {
content: "\ea22";
}
.dicon-pdf::before {
content: "\ea23";
}
.dicon-pdf::before {
content: "\ea23";
}
.dicon-print::before {
content: "\ea24";
}
.dicon-print::before {
content: "\ea24";
}
.dicon-list-bullet-2::before {
content: "\ea25";
}
.dicon-list-bullet-2::before {
content: "\ea25";
}
.dicon-magnifier::before {
content: "\ea26";
}
.dicon-magnifier::before {
content: "\ea26";
}
.dicon-b-chat::before {
content: "\ea27";
}
.dicon-b-chat::before {
content: "\ea27";
}
.dicon-filter-tool::before {
content: "\ea28";
}
.dicon-filter-tool::before {
content: "\ea28";
}
.dicon-grid-interface::before {
content: "\ea29";
}
.dicon-grid-interface::before {
content: "\ea29";
}
.dicon-lock::before {
content: "\ea2a";
}
.dicon-lock::before {
content: "\ea2a";
}
.dicon-unlocked::before {
content: "\ea2b";
}
.dicon-unlocked::before {
content: "\ea2b";
}
.dicon-menu-7::before {
content: "\ea2c";
}
.dicon-menu-7::before {
content: "\ea2c";
}
.dicon-network-connection::before {
content: "\ea2d";
}
.dicon-network-connection::before {
content: "\ea2d";
}
.dicon-e-add::before {
content: "\ea2e";
}
.dicon-e-add::before {
content: "\ea2e";
}
.dicon-data-upload::before {
content: "\ea2f";
}
.dicon-data-upload::before {
content: "\ea2f";
}
.dicon-upload::before {
content: "\ea30";
}
.dicon-upload::before {
content: "\ea30";
}
.dicon-flag::before {
content: "\ea31";
}
.dicon-flag::before {
content: "\ea31";
}
.dicon-globe::before {
content: "\ea32";
}
.dicon-globe::before {
content: "\ea32";
}
.dicon-single-01::before {
content: "\ea33";
}
.dicon-single-01::before {
content: "\ea33";
}
.dicon-multiple-19::before {
content: "\ea34";
}
.dicon-multiple-19::before {
content: "\ea34";
}
.dicon-box::before {
content: "\ea35";
}
.dicon-box::before {
content: "\ea35";
}
.dicon-time::before {
content: "\ea37";
}
.dicon-time::before {
content: "\ea37";
}
.dicon-split-37::before {
content: "\ea38";
}
.dicon-split-37::before {
content: "\ea38";
}
.dicon-sort-tool::before {
content: "\ea39";
}
.dicon-sort-tool::before {
content: "\ea39";
}
.dicon-button-2::before {
content: "\ea3a";
}
.dicon-button-2::before {
content: "\ea3a";
}
.dicon-menu-6::before {
content: "\ea40";
}
.dicon-menu-6::before {
content: "\ea40";
}
.dicon-pulse::before {
content: "\ea41";
}
.dicon-pulse::before {
content: "\ea41";
}
.dicon-copy::before {
content: "\ea43";
}
.dicon-copy::before {
content: "\ea43";
}
.dicon-menu-8::before {
content: "\ea48";
}
.dicon-menu-8::before {
content: "\ea48";
}
.dicon-send::before {
content: "\ea49";
}
.dicon-send::before {
content: "\ea49";
}
.dicon-email::before {
content: "\ea4a";
}
.dicon-email::before {
content: "\ea4a";
}
.dicon-download::before {
content: "\ea4b";
}
.dicon-download::before {
content: "\ea4b";
}
.dicon-database::before {
content: "\ea4c";
}
.dicon-database::before {
content: "\ea4c";
}
.dicon-notification::before {
content: "\ea4d";
}
.dicon-notification::before {
content: "\ea4d";
}
.dicon-handshake::before {
content: "\ea4e";
}
.dicon-handshake::before {
content: "\ea4e";
}
.dicon-add-27::before {
content: "\ea4f";
}
.dicon-add-27::before {
content: "\ea4f";
}
.dicon-delete-28::before {
content: "\ea50";
}
.dicon-delete-28::before {
content: "\ea50";
}
.dicon-i-check::before {
content: "\ea51";
}
.dicon-i-check::before {
content: "\ea51";
}
.dicon-shape-rectangle::before {
content: "\ea52";
}
.dicon-shape-rectangle::before {
content: "\ea52";
}
.dicon-ban::before {
content: "\ea53";
}
.dicon-ban::before {
content: "\ea53";
}
.dicon-check-single::before {
content: "\ea54";
}
.dicon-check-single::before {
content: "\ea54";
}
.dicon-check-double::before {
content: "\ea55";
}
.dicon-check-double::before {
content: "\ea55";
}
.dicon-check::before {
content: "\ea56";
}
.dicon-check::before {
content: "\ea56";
}
.dicon-preview::before {
content: "\ea58";
}
.dicon-preview::before {
content: "\ea58";
}
.dicon-link::before {
content: "\ea59";
}
.dicon-link::before {
content: "\ea59";
}
.dicon-b-check::before {
content: "\ea5a";
}
.dicon-b-check::before {
content: "\ea5a";
}
.dicon-e-delete::before {
content: "\ea5b";
}
.dicon-menu-5::before {
content: "\ea5c";
}
.dicon-move-layer-up::before {
content: "\ea5d";
}
.dicon-alpha-order::before {
content: "\ea5e";
}
.dicon-enlarge::before {
content: "\ea5f";
}

View file

@ -1,5 +1,6 @@
@import "grid.scss";
@import "spacing.scss";
@import "headings.scss";
@import "master-internal.scss";
@import "layout.scss";
@import "toolbar.scss";
@import "sidebar.scss";

View file

@ -0,0 +1,140 @@
// *****************************************************************
// Define mobile-first layout for main content zone with a sidebar.
// *****************************************************************
.master-grid-container {
display: block;
height: auto;
width: 100%;
.master-sidebar {
display: block;
height: auto;
margin: 10px;
}
.master-content {
display: block;
height: auto;
padding: 10px;
}
}
// Tablet starts around 700px
@media (min-width: $display-break-1) {
.master-grid-container {
display: grid;
grid-template-columns: 200px auto;
.master-sidebar {
width: 200px;
margin: 20px 10px 20px 20px;
height: calc(100vh - 90px - 40px);
@include sticky();
top: 0px;
overflow-x: hidden;
overflow-y: auto;
}
.master-content {
grid-column-start: 2;
padding: 20px;
max-width: calc(100vw - 210px);
}
}
}
// Small screen starts around 900px
@media (min-width: $display-break-2) and (min-height: 650px) {
.master-grid-container {
display: grid;
grid-template-columns: 240px auto;
.master-sidebar {
width: 220px;
}
.master-content {
grid-column-start: 2;
padding: 20px;
max-width: calc(100vw - 250px);
}
}
}
// Medium screen starts around 1200px
@media (min-width: $display-break-3) and (min-height: 650px) {
.master-grid-container {
display: grid;
grid-template-columns: 300px auto;
.master-sidebar {
width: 280px;
margin: 40px 10px 40px 20px;
height: calc(100vh - 90px - 80px);
}
.master-content {
grid-column-start: 2;
padding: 40px 30px;
max-width: calc(100vw - 310px);
}
}
}
// Large screen starts around 1600px
@media (min-width: $display-break-4) and (min-height: 650px) {
.master-grid-container {
display: grid;
grid-template-columns: 400px minmax(auto, 1200px);
.master-sidebar {
width: 400px;
margin: 40px 10px 40px 20px;
}
.master-content {
grid-column-start: 2;
padding: 40px 40px;
max-width: 1200px;
}
}
}
// *****************************************************************
// Define mobile-first layout for content without a sidebar.
// *****************************************************************
.master-container {
display: block;
height: auto;
width: 100%;
padding: 20px;
}
// Tablet starts around 700px
@media (min-width: $display-break-1) {
.master-container {
padding: 20px;
}
}
// Small screen starts around 900px
@media (min-width: $display-break-2) and (min-height: 650px) {
.master-container {
padding: 20px;
}
}
// Medium screen starts around 1200px
@media (min-width: $display-break-3) and (min-height: 650px) {
.master-container {
padding: 30px;
}
}
// Large screen starts around 1600px
@media (min-width: $display-break-4) and (min-height: 650px) {
.master-container {
padding: 40px;
// max-width: 1200px;
}
}

View file

@ -1,389 +0,0 @@
// CSS GRID LAYOUT
// Mobile-first layout
.master-container {
display: block;
height: auto;
width: 100%;
.master-content {
display: block;
height: auto;
width: 100%;
padding: 10px;
}
}
.master-sidebar-container {
display: block;
height: auto;
width: 100%;
z-index: 1041; // required if we want to show modals from inside sidebar
.master-navbar {
display: block;
height: auto;
width: 100%;
background-color: $theme-500;
text-align: center;
padding: 0;
z-index: 999;
> .nav-content {
display: flex;
flex-grow: 1;
flex-direction: row;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
width: 100%;
> .nav-options {
> .selected {
> .dicon, > .name {
color: $color-white !important;
}
}
> .option {
cursor: pointer;
display: inline-block;
> .dicon {
display: inline-block;
color: $theme-300;
font-size: 20px;
padding: 10px;
}
> .name {
display: none;
color: $theme-300;
}
&:hover {
> .dicon, > .name {
color: $theme-400 !important;
}
}
}
}
> .meta {
> .logo {
display: none;
cursor: pointer;
}
> .bookmarks, > .login, > .invalid-plan {
display: inline-block;
>.dicon {
cursor: pointer;
color: $color-white;
font-size: 20px;
padding: 10px;
}
}
> .invalid-plan {
>.dicon {
color: map-get($yellow-shades, 600) !important;
}
}
> .user-gravatar-container {
display: inline-block;
margin: 0 10px 0 0;
padding: 0;
vertical-align: text-bottom;
> .user-gravatar {
cursor: pointer;
position: relative;
width: 25px;
height: 25px;
line-height: 24px;
padding: 0;
border-radius: 50%;
font-size: 0.75rem;
text-align: center;
color: $theme-500;
font-weight: bold;
background-color: $color-white;
@extend .no-select;
}
}
}
}
}
.master-sidebar {
display: block;
height: auto;
width: 100%;
padding: 5px 10px;
z-index: 888;
// background-color: map-get($gray-shades, 100);
background-color: $color-sidebar;
}
}
// Tablet starts around 700px
@media (min-width: $display-break-1) {
.master-container {
display: grid;
grid-template-columns: 240px auto;
.master-content {
grid-column-start: 2;
padding: 20px;
max-width: calc(100vw - 250px);
}
}
.master-sidebar-container {
position: fixed;
width: 240px;
height: 100vh;
.master-navbar {
position: fixed;
top: 0;
left: 0;
width: 40px;
height: 100vh;
text-align: center;
padding: 10px 0;
> .nav-content {
display: flex;
flex-grow: 1;
flex-direction: column;
align-items: center;
justify-content: space-between;
flex-wrap: nowrap;
height: 100vh;
> .nav-options {
> .option {
display: block;
>.dicon {
display: block;
font-size: 20px;
padding: 20px 0;
}
}
}
> .meta {
padding-bottom: 35px;
> .logo {
display: block;
> img {
width: 32px;
height: 32px;
}
> .documize {
display: none;
}
}
> .bookmarks, > .login, > .invalid-plan {
display: block;
>.dicon {
color: $color-white;
font-size: 20px;
padding: 10px 0;
}
}
> .user-gravatar-container {
display: block;
text-align: center;
margin: 10px 0 15px 4px;
padding: 0;
> .user-gravatar {
display: block;
}
}
}
}
}
.master-sidebar {
position: fixed;
top: 0;
left: 40px;
width: 200px;
height: 100vh;
overflow-x: hidden;
overflow-y: auto;
}
}
}
// Small screen starts around 900px
@media (min-width: $display-break-2) and (min-height: 650px) {
.master-container {
display: grid;
grid-template-columns: 290px auto;
.master-content {
grid-column-start: 2;
padding: 20px;
max-width: calc(100vw - 300px);
}
}
.master-sidebar-container {
position: fixed;
width: 290px;
height: 100vh;
.master-navbar {
position: fixed;
top: 0;
left: 0;
width: 70px;
height: 100vh;
text-align: center;
> .nav-content {
> .nav-options {
> .option {
> .dicon {
display: block;
font-size: 24px;
padding: 15px 0 10px 0;
}
> .name {
display: block;
padding: 0 0 15px 0;
font-size: 0.8rem;
font-weight: 700;
text-transform: uppercase;
}
}
}
> .meta {
> .logo {
> img {
width: 32px;
height: 32px;
}
> .documize {
display: block;
font-size: 0.7rem;
color: white;
text-decoration: none;
}
}
> .user-gravatar-container {
margin: 10px 0 15px 8px;
padding: 0;
> .user-gravatar {
width: 30px;
height: 30px;
line-height: 30px;
font-size: 0.9rem;
}
}
}
}
}
.master-sidebar {
position: fixed;
top: 0;
left: 70px;
width: 220px;
height: 100vh;
}
}
}
// Medium screen starts around 1200px
@media (min-width: $display-break-3) and (min-height: 650px) {
.master-container {
display: grid;
grid-template-columns: 320px auto;
.master-content {
grid-column-start: 2;
padding: 40px 30px;
max-width: calc(100vw - 330px);
}
}
.master-sidebar-container {
position: fixed;
width: 320px;
height: 100vh;
.master-navbar {
position: fixed;
top: 0;
left: 0;
width: 70px;
height: 100vh;
}
.master-sidebar {
position: fixed;
top: 0;
left: 70px;
width: 250px;
height: 100vh;
padding: 20px 10px;
}
}
}
// Large screen starts around 1600px
@media (min-width: $display-break-4) and (min-height: 650px) {
.master-container {
display: grid;
grid-template-columns: 370px minmax(auto, 1200px);
.master-content {
grid-column-start: 2;
padding: 40px 40px;
max-width: 1200px;
}
}
.master-sidebar-container {
position: fixed;
width: 370px;
height: 100vh;
.master-navbar {
position: fixed;
top: 0;
left: 0;
width: 70px;
height: 100vh;
}
.master-sidebar {
position: fixed;
top: 0;
left: 70px;
width: 300px;
height: 100vh;
padding: 20px 15px;
}
}
}

View file

@ -1,7 +1,39 @@
.sidebar-content {
display: block;
position: relative;
// @extend .text-truncate;
padding: 20px 5px 20px 10px;
// background-color: $theme-100;
background-color: $color-sidebar;
// background-color: map-get($gray-shades, 100);
@include border-radius(6px);
> .goto-top {
position: absolute;
top: 10px;
left: 10px;
cursor: pointer;
color: map-get($gray-shades, 500);
font-size: 1rem;
&:hover {
color: map-get($gray-shades, 800);
}
}
// Allows for icon to be placed top right corner of sidebar zone.
// Expects icon to be placed in the zone.
> .custom-action {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
color: map-get($gray-shades, 500);
font-size: 1rem;
&:hover {
color: map-get($gray-shades, 800);
}
}
> .section {
margin: 0;

View file

@ -0,0 +1,129 @@
// *****************************************************************
// Define mobile-first layout for top navigation bar and toolbar.
// *****************************************************************
.master-navigation {
display: block;
height: auto;
width: 100%;
> .navbar {
display: block;
height: 40px;
width: 100%;
background-color: $theme-500;
text-align: center;
padding: 0;
z-index: 999;
> .container {
display: flex;
flex-grow: 1;
flex-direction: row;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
width: 100%;
padding: 0 20px;
> .options {
> .selected {
> .dicon {
color: $color-white !important;
}
}
> .option {
cursor: pointer;
display: inline-block;
> .dicon {
display: inline-block;
color: $theme-300;
font-size: 20px;
padding: 10px 10px;
}
&:hover {
> .dicon {
color: $color-white !important;
}
}
}
> a.option {
color: $theme-300;
&:hover {
color: $color-white;
}
}
> .invalid-plan {
> .dicon {
color: map-get($yellow-shades, 600) !important;
}
}
> .user-gravatar-container {
display: inline-block;
margin: 0;
padding: 7px 10px;
vertical-align: top;
> .user-gravatar {
display: inline-block;
cursor: pointer;
position: relative;
width: 26px;
height: 26px;
line-height: 26px;
padding: 0;
border-radius: 50%;
font-size: 0.85rem;
text-align: center;
color: $theme-500;
font-weight: bold;
background-color: $color-white;
@extend .no-select;
&:hover {
background-color: $theme-100;
}
}
}
}
}
}
> .toolbar {
display: block;
width: 100%;
background-color: $color-sidebar;
background-color: $theme-100;
padding: 0;
// z-index: 999;
> .container {
height: 50px;
width: 100%;
display: flex;
flex-grow: 1;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: 0 15px 0 20px;
> div[class^="zone-"], > div[class*=" zone-"] {
margin: 0;
padding: 0;
align-items: center;
align-self: center;
> .label {
font-size: 1rem;
}
}
}
}
}

View file

@ -179,12 +179,12 @@
.dmz-button-theme {
@extend %dmz-button;
background-color: $theme-800;
background-color: $theme-500;
color: $color-white;
@include button-shadow();
&:hover {
background-color: $theme-600;
background-color: $theme-700;
}
}
.dmz-button-theme-light {

View file

@ -8,7 +8,7 @@
// -webkit-box-shadow: 0 20px 66px 0 rgba(34,48,73,0.2);
// box-shadow: 0 20px 66px 0 rgba(34,48,73,0.2);
@include border-radius(5px);
@include border-radius(3px);
> p {
margin: 4px;
@ -19,6 +19,9 @@
margin: 0;
padding: 0;
min-width: 140px;
max-height: calc(100vh - 200px);
overflow: hidden;
overflow-y: auto;
> .item {
color: map-get($gray-shades, 800);
@ -36,20 +39,21 @@
&:hover {
color: $color-black;
background-color: map-get($yellow-shades, 100);
@include border-radius(3px);
}
}
> .header {
color: map-get($gray-shades, 800);
background-color: map-get($gray-shades, 300);
color: $color-white;
background-color: $theme-500;
font-size: 1rem;
font-weight: 600;
cursor: auto;
&:hover {
color: map-get($gray-shades, 800);
background-color: map-get($gray-shades, 300);
}
color: $color-white;
background-color: $theme-500;
}
}
> .divider {

View file

@ -1,40 +1,44 @@
%toolbar-shadow {
box-shadow: 1px 1px 3px 0px map-get($gray-shades, 200);
box-shadow: none;
}
.dmz-toolbar {
display: inline-flex;
flex-basis: auto;
align-items: center;
text-align: center;
white-space: nowrap;
vertical-align: middle;
border: 1px solid transparent;
height: 30px;
width: auto;
padding: 6px 10px;
line-height: 24px;
@extend .no-select;
@include border-radius(6px);
@include border-radius(4px);
> .dicon {
font-size: 16px;
font-weight: 500;
color: map-get($gray-shades, 600);
font-size: 20px;
color: $theme-500;
padding: 0 0.5rem;
cursor: pointer;
&:hover {
color: map-get($gray-shades, 700);
color: $theme-400;
}
}
> .divider {
margin: 0 6px;
width: 1px;
background-color: $theme-200;
}
> .icon-selected {
color: map-get($yellow-shades, 600);
}
> .label {
font-size: 14px;
font-weight: 500;
font-weight: 400;
color: map-get($gray-shades, 600);
padding: 0 0.5rem;
align-self: center;
@ -68,17 +72,154 @@
color: map-get($green-shades, 600);
}
}
}
.dmz-toolbar-large {
height: 40px;
padding: 9px 10px;
line-height: 33px;
> .dropdown {
display: inline-block;
cursor: pointer;
> .dicon {
font-size: 20px;
&:hover {
> .label, > .dicon {
color: $theme-400;
}
}
> .label {
display: inline-block;
font-size: 1rem;
font-weight: 400;
color: $theme-500;
padding: 0 0 0 0.5rem;
vertical-align: text-bottom;
}
> .dicon {
font-size: 20px;
color: $theme-500;
padding: 0 0.3rem 0 0;
vertical-align: bottom;
}
}
> .dropdown-green {
> .label, > .dicon {
color: map-get($green-shades, 500);
&:hover {
color: map-get($green-shades, 600);
}
}
}
> %button {
display: inline-block;
white-space: nowrap;
text-align: center;
padding: 0.375rem 0.75rem;
// margin: 0 0.5rem;
font-weight: 500;
padding: 0 0.5rem;
font-size: 1rem;
border: 1px solid transparent;
text-transform: uppercase;
cursor: pointer;
@extend .no-select;
@include border-radius(2px);
outline: none;
background-color: map-get($gray-shades, 600);
color: $color-white;
// @include button-shadow();
> .dicon {
font-size: 1rem;
padding: 0.2rem 0.4rem 0 0;
font-weight: 500;
}
> .label {
display: inline-block;
font-size: 1rem;
margin: 0;
padding: 0;
}
&:hover {
color: map-get($gray-shades, 800);
border-color: map-get($gray-shades, 500);
}
}
.button-theme {
@extend %button;
background-color: $theme-500;
color: $color-white;
&:hover {
color: $color-white;
border-color: $theme-600;
background-color: $theme-600;
}
}
.button-green {
@extend %button;
background-color: map-get($green-shades, 600);
color: $color-white;
&:hover {
color: $color-white;
border-color: map-get($green-shades, 500);
background-color: map-get($green-shades, 500);
}
}
.button-green-light {
@extend %button;
background-color: map-get($green-shades, 200);
color: map-get($green-shades, 700);
border: 1px solid map-get($green-shades, 300);
&:hover {
background-color: map-get($green-shades, 300);
}
}
.button-yellow {
@extend %button;
background-color: map-get($yellow-shades, 600);
color: $color-white;
&:hover {
background-color: map-get($yellow-shades, 700);
}
}
.button-yellow-light {
@extend %button;
background-color: map-get($yellow-shades, 200);
color: map-get($yellow-shades, 700);
border: 1px solid map-get($yellow-shades, 300);
&:hover {
background-color: map-get($yellow-shades, 300);
}
}
.button-red {
@extend %button;
background-color: map-get($red-shades, 600);
color: $color-white;
&:hover {
background-color: map-get($red-shades, 700);
}
}
.button-red-light {
@extend %button;
background-color: map-get($red-shades, 100);
color: map-get($red-shades, 700);
border: 1px solid map-get($red-shades, 200);
&:hover {
background-color: map-get($red-shades, 200);
}
}
}
@ -88,6 +229,7 @@
.dmz-toolbar-light {
background-color: map-get($gray-shades, 100);
background-color: $color-white;
}
.dmz-toolbar-raised {

View file

@ -15,8 +15,10 @@ a {
text-decoration: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
outline: none;
a:focus, a:hover {
outline: none;
text-decoration: underline;
}
}

View file

@ -1,10 +1,16 @@
.document-meta-wrapper {
padding: 20px 20px 0 20px;
@include border-radius(7px);
background-color: map-get($gray-shades, 100);
}
.document-meta {
margin: 0;
padding: 0;
> .title {
text-transform: uppercase;
font-size: 1rem;
font-size: 0.8rem;
font-weight: 600;
color: map-get($gray-shades, 700);
margin-bottom: 5px;
@ -138,13 +144,33 @@
@extend .no-select;
display: block;
margin: 0;
font-size: 1.1rem;
font-size: 0.9rem;
font-weight: 400;
color: map-get($yellow-shades, 700);
color: map-get($green-shades, 700);
}
> .label-version {
@include border-radius(3px);
@extend .no-select;
display: inline-block;
margin: 5px 0 5px 0;
padding: 0.3rem 0.7rem;
font-size: 1.1rem;
font-weight: 500;
background-color: map-get($gray-shades, 800);
color: map-get($gray-shades, 100);
}
> .version-dropdown {
color: map-get($gray-shades, 500);
font-size: 25px;
vertical-align: middle;
cursor: pointer;
}
> .document-heading {
.name {
margin: 0;
color: map-get($gray-shades, 900);
font-size: 2.2rem;
font-weight: 700;
@ -155,5 +181,12 @@
font-size: 1.2rem;
font-weight: 500;
}
> .dates {
margin-bottom: 2rem;
font-size: 0.9rem;
font-weight: 300;
color: map-get($gray-shades, 700);
}
}
}

View file

@ -2,7 +2,7 @@
margin: 0 0 0 0;
> .page-header {
margin: 2rem 0 2rem 0;
margin: 0 0 2rem 0;
> .page-number {
color: $theme-500;
@ -55,6 +55,14 @@
color: map-get($yellow-shades, 700);
}
}
> i.expand {
color: map-get($green-shades, 500);
&:hover {
color: map-get($green-shades, 700);
}
}
}
}

View file

@ -1,51 +1,67 @@
#upload-document-files {
> .dz-preview, .dz-processing {
display: none !important;
}
}
.document-sidebar-attachment {
> .files {
margin: 0;
padding: 0;
> .file {
@include card();
list-style-type: none;
margin: 10px 0 0 0;
padding: 5px;
width: 100%;
margin: 0;
padding: 0 10px 0 0;
font-size: 0.9rem;
position: relative;
display: inline-block;
> a {
display: inline-block;
font-size: 0.9rem;
vertical-align: text-top;
margin-right: 10px;
width: 90%;
font-size: 1rem;
@extend .text-truncate;
color: map-get($gray-shades, 800);
&:hover {
color: map-get($gray-shades, 900);
}
}
> .menu {
position: absolute;
right: -10px;
top: 0;
display: inline-block;
color: map-get($gray-shades, 300);
font-size: 1.2rem;
&:hover {
color: map-get($gray-shades, 600);
}
}
}
}
}
#upload-document-files {
list-style-type: none;
margin: 0;
padding: 0;
font-size: 0.9rem;
position: relative;
display: inline-block;
text-transform: uppercase;
vertical-align: super;
> span {
display: inline-block;
color: map-get($gray-shades, 600);
font-size: 1rem;
cursor: pointer;
&:hover {
color: map-get($gray-shades, 800);
}
}
> .dz-preview, .dz-processing {
display: none !important;
}
}
.dz-preview, .dz-processing {
display: none !important;
}
.section-attachments {
margin: 1.5rem 0 0 0;
margin: 1.5rem 0 1.5rem 0;
padding: 0;
> .file {

View file

@ -26,21 +26,24 @@
padding: 0;
list-style: none;
font-size: 1rem;
overflow-x: hidden;
list-style-type: none;
margin: 0 0 0 0;
.item {
@extend .no-select;
padding: 5px 0;
text-overflow: ellipsis;
word-wrap: break-word;
white-space: nowrap;
overflow: hidden;
// text-overflow: ellipsis;
// word-wrap: break-word;
// white-space: nowrap;
// overflow: hidden;
> .link {
color: map-get($gray-shades, 800);
font-weight: 500;
// font-weight: 300;
// text-overflow: ellipsis;
// word-wrap: break-word;
// white-space: nowrap;
overflow: hidden;
&:hover {
color: map-get($yellow-shades, 600);
@ -48,7 +51,7 @@
> .numbering {
color: map-get($gray-shades, 600);
font-weight: 500;
font-weight: 300;
display: inline-block;
margin-right: 10px;
font-size: 0.9rem;

View file

@ -10,6 +10,12 @@
color: map-get($gray-shades, 100);
}
.space-label-dropdown {
font-size: 25px;
vertical-align: middle;
cursor: pointer;
}
.view-space {
> .documents {
margin: 0;
@ -17,7 +23,6 @@
> .document {
@include card();
box-shadow: none;
list-style-type: none;
margin: 0 0 2rem 0;
padding: 15px 20px;
@ -70,84 +75,84 @@
margin-top: 0.4rem;
color: $color-black-light-3;
}
}
> .meta {
padding: 25px 0 0 0;
> .meta {
padding: 25px 0 0 0;
> .lifecycle {
display: inline-block;
text-transform: uppercase;
font-size: 0.9rem;
font-weight: 500;
text-align: center;
@include border-radius(5px);
background-color: map-get($gray-shades, 300);
padding: 0.25rem 1rem;
margin-right: 20px;
> .draft {
color: map-get($yellow-shades, 600);
}
> .live {
color: map-get($green-shades, 600);
}
> .archived {
color: map-get($red-shades, 600);
}
}
> .dicon {
color: map-get($gray-shades, 600);
font-size: 20px;
}
.categories {
display: inline-block;
padding: 0;
> .category {
padding: 0 15px 0 0;
> .lifecycle {
display: inline-block;
text-transform: uppercase;
font-size: 0.9rem;
font-weight: 500;
text-align: center;
@include border-radius(5px);
background-color: map-get($gray-shades, 300);
padding: 0.25rem 1rem;
margin-right: 20px;
> .dicon {
color: map-get($gray-shades, 500);
font-size: 20px;
vertical-align: bottom;
> .draft {
color: map-get($yellow-shades, 600);
}
> .name {
display: inline-block;
color: map-get($gray-shades, 800);
font-size: 1rem;
> .live {
color: map-get($green-shades, 600);
}
> .archived {
color: map-get($red-shades, 600);
}
}
}
.hashtags {
display: inline-block;
padding: 0;
> .dicon {
color: map-get($gray-shades, 600);
font-size: 20px;
}
> .hashtag {
padding: 0 15px 0 0;
.categories {
display: inline-block;
padding: 0;
> .dicon {
color: map-get($gray-shades, 500);
font-size: 20px;
vertical-align: bottom;
}
> .name {
> .category {
padding: 0 15px 0 0;
display: inline-block;
color: map-get($gray-shades, 800);
font-size: 1rem;
}
&:hover {
> .dicon, > .name {
color: map-get($gray-shades, 600);
> .dicon {
color: map-get($gray-shades, 500);
font-size: 20px;
vertical-align: bottom;
}
> .name {
display: inline-block;
color: map-get($gray-shades, 800);
font-size: 1rem;
}
}
}
.hashtags {
display: inline-block;
padding: 0;
> .hashtag {
padding: 0 15px 0 0;
> .dicon {
color: map-get($gray-shades, 500);
font-size: 20px;
vertical-align: bottom;
}
> .name {
display: inline-block;
color: map-get($gray-shades, 800);
font-size: 1rem;
}
&:hover {
> .dicon, > .name {
color: map-get($gray-shades, 600);
}
}
}
}

View file

@ -26,7 +26,7 @@
</ul>
</div>
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
{{#if isKeycloakProvider}}
<div class="form-group">

View file

@ -26,7 +26,7 @@
</small>
</div>
</div>
{{ui/ui-spacer size=400}}
<Ui::UiSpacer @size="400" />
<div class="change-log">
{{{changelog}}}
</div>

View file

@ -29,7 +29,7 @@
{{ui/ui-button color=constants.Color.Yellow light=true label="Upgrade"}}
</a>
{{/if}}
{{ui/ui-spacer size=400}}
<Ui::UiSpacer @size="400" />
<form>
<div class="form-group">
@ -101,7 +101,7 @@
{{#if (eq appMeta.edition constants.Product.EnterpriseEdition)}}
{{#if (eq appMeta.location "cloud")}}
{{ui/ui-spacer size=400}}
<Ui::UiSpacer @size="400" />
<div class="view-customize">
<div class="deactivation-zone">
<p>Let us know if you would like to close your account or cancel your subscription.</p>

View file

@ -1,6 +1,6 @@
{{#if spaces}}
{{ui/ui-button color=constants.Color.Yellow light=true icon=constants.Icon.Export label="Export All Content" onClick=(action "onExport")}}
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
<div class="view-customize">
<ul class="space-list">
@ -28,7 +28,7 @@
</div>
<div class="desc">Some description that is to be wired up to the backend</div>
{{/link-to}}
{{ui/ui-spacer size=200}}
<Ui::UiSpacer @size="200" />
{{#ui/ui-toolbar dark=false light=true raised=true large=false bordered=true}}
{{ui/ui-toolbar-icon icon=constants.Icon.AddUser color=constants.Color.Green tooltip="Add myself as owner" onClick=(action "onOwner" space.id)}}
{{ui/ui-toolbar-icon icon=constants.Icon.Delete color=constants.Color.Red tooltip="Delete space" onClick=(action "onShow" space.id)}}

View file

@ -6,7 +6,7 @@
label=constants.Label.Add
onClick=(action "onShowAddModal")}}
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
<ul class="space-labels">
{{#each labels as |label|}}
@ -75,4 +75,4 @@
{{#ui/ui-dialog title="Delete Label" confirmCaption="Delete" buttonColor=constants.Color.Red show=showDeleteDialog onAction=(action "onDelete")}}
<p>Are you sure you want to delete the label <b>{{deleteLabel.name}}?</b></p>
{{/ui/ui-dialog}}
{{/ui/ui-dialog}}

View file

@ -21,9 +21,9 @@
{{input id="newUserEmail" type="email" class="form-control" placeholder="Email" value=newUser.email}}
</div>
</div>
{{ui/ui-spacer size=200}}
<Ui::UiSpacer @size="200" />
{{ui/ui-button color=constants.Color.Green icon=constants.Icon.Person light=true label=constants.Label.Add onClick=(action "onAddUser")}}
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
</form>
<form onsubmit={{action "onAddUser"}}>
<div class="form-group">

View file

@ -26,7 +26,7 @@
</div>
</div>
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
<div class="groups-list">
{{#each groups as |group|}}
@ -35,7 +35,7 @@
{{group.name}} ({{group.members}})
</div>
<div class="desc">{{group.purpose}}</div>
{{ui/ui-spacer size=200}}
<Ui::UiSpacer @size="200" />
{{#ui/ui-toolbar dark=false light=true raised=true large=false bordered=true}}
{{ui/ui-toolbar-icon icon=constants.Icon.AddUser color=constants.Color.Gray tooltip="Add members" onClick=(action "onShowAddMemberModal" group.id)}}
{{#if (gt group.members 0)}}
@ -146,7 +146,7 @@
{{ui/ui-toolbar-label color=constants.Color.Gray label="ALL" selected=(eq userLimit 99999) onClick=(action "onLimit" 99999)}}
{{/ui/ui-toolbar}}
</div>
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
<div class="group-users-members">
{{#each users as |user|}}
<div class="item">
@ -169,4 +169,4 @@
</div>
</div>
</div>
</div>
</div>

View file

@ -1,6 +1,6 @@
<div class="view-customize">
{{#if isAuthProviderKeycloak}}
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
{{#if syncInProgress}}
{{ui/ui-button color=constants.Color.Gray light=true icon=constants.Icon.Locked label="Keycloak user sync running..."}}
{{else}}
@ -9,7 +9,7 @@
{{/if}}
{{#if (or isAuthProviderLDAP c)}}
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
{{#if syncInProgress}}
{{ui/ui-button color=constants.Color.Gray light=true icon=constants.Icon.Locked label="LDAP user sync running..."}}
{{else}}
@ -17,7 +17,7 @@
{{/if}}
{{/if}}
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
<div class="explain-user-perms">
<div class="title" {{action "togglePerms"}}>
Permissions Explained
@ -40,7 +40,7 @@
<div class="perm-desc">Can login and use Documize</div>
</div>
</div>
{{ui/ui-spacer size=300}}
<Ui::UiSpacer @size="300" />
<div class="form-group">
{{focus-input type="text" class="form-control" placeholder="filter users" value=filter key-up=(action "onFilterChange")}}

View file

@ -1,7 +1,53 @@
{{ui/ui-spacer size=300}}
<div class="document-meta non-printable">
<div class="title">STATUS</div>
<div class="{{if (eq document.lifecycle constants.Lifecycle.Draft) "label-draft"}}
{{if (eq document.lifecycle constants.Lifecycle.Live) "label-live"}}
{{if (eq document.lifecycle constants.Lifecycle.Archived) "label-archived"}}">
{{document.lifecycleLabel}}
{{#attach-tooltip showDelay=1000}}Lifecycle: Draft &middot; Live &middot; Archived{{/attach-tooltip}}
</div>
<div class="document-meta">
<div class="title {{if permissions.documentEdit "cursor-pointer"}}" {{action "onEditCategory"}}>CATEGORY / TAG</div>
{{#if (eq document.protection constants.ProtectionType.None)}}
<div class="label-open">
OPEN
{{#attach-tooltip showDelay=1000}}Change Control: Open &middot; Protected &middot; Locked{{/attach-tooltip}}
</div>
{{/if}}
{{#if (eq document.protection constants.ProtectionType.Review)}}
<div class="label-protected">
PROTECTED
{{#attach-tooltip showDelay=1000}}Change Control: Open &middot; Protected &middot; Locked{{/attach-tooltip}}
</div>
{{/if}}
{{#if (eq document.protection constants.ProtectionType.Lock)}}
<div class="label-locked">
LOCKED
{{#attach-tooltip showDelay=1000}}Change Control: Open &middot; Protected &middot; Locked{{/attach-tooltip}}
</div>
{{/if}}
{{#if contributionStatus}}
<div class="label-workflow-status">
{{contributionStatus}}
</div>
{{else}}
{{#if approvalStatus}}
<div class="label-workflow-status">
{{approvalStatus}}
</div>
{{/if}}
{{/if}}
{{#if document.template}}
<div class="label-template non-printable">
Template
{{#attach-tooltip showDelay=1000}}This is a template{{/attach-tooltip}}
</div>
{{/if}}
<Ui::UiSpacer @size="200" />
<div class="title">CATEGORY / TAG</div>
{{#each selectedCategories as |cat|}}
<div class="meta-label">
<i class="dicon {{constants.Icon.Category}}"/>
@ -16,14 +62,15 @@
{{#attach-tooltip showDelay=1000}}Tag{{/attach-tooltip}}
</div>
{{/each}}
{{#if unassigned}}
{{#if permissions.spaceManage}}
{{#ui/ui-toolbar dark=false light=true raised=true large=false bordered=true}}
{{ui/ui-toolbar-icon icon=constants.Icon.Plus color=constants.Color.Gray linkTo="document.settings"}}
{{/ui/ui-toolbar}}
<div class="empty cursor-pointer" {{action "onEditCategory"}}>Unassigned</div>
{{else}}
<div class="empty">Unassigned</div>
{{/if}}
{{/if}}
</div>
{{document/sidebar-attachment document=document permissions=permissions}}
<Ui::UiSpacer @size="200" />

View file

@ -11,33 +11,41 @@
onAction=(action "onSavePage")}}
</div>
{{else}}
{{document/page-heading
page=page
meta=meta
pages=pages
roles=roles
folder=folder
blocks=blocks
tabMode=tabMode
pending=pending
document=document
permissions=permissions
onEdit=(action "onEdit")
refresh=(action refresh)
onCopyPage=(action "onCopyPage")
onMovePage=(action "onMovePage")
onDeletePage=(action "onDeletePage")
onSavePageAsBlock=(action "onSavePageAsBlock")
onPageLevelChange=(action onPageLevelChange)
onPageSequenceChange=(action onPageSequenceChange)
onShowSectionWizard=(action onShowSectionWizard)}}
<div class={{page.tocIndentCss}}>
{{document/page-heading
expanded=expanded
page=page
meta=meta
pages=pages
roles=roles
folder=folder
folders=folders
blocks=blocks
tabMode=tabMode
pending=pending
document=document
permissions=permissions
currentPageId=currentPageId
onEdit=(action "onEdit")
refresh=(action refresh)
onExpand=(action onExpand)
onCopyPage=(action "onCopyPage")
onMovePage=(action "onMovePage")
onDeletePage=(action "onDeletePage")
onSavePageAsBlock=(action "onSavePageAsBlock")
onPageLevelChange=(action onPageLevelChange)
onPageSequenceChange=(action onPageSequenceChange)
onShowSectionWizard=(action onShowSectionWizard)}}
<div class="wysiwyg">
{{section/base-renderer page=page}}
{{#if expanded}}
<div class="wysiwyg">
{{section/base-renderer page=page}}
</div>
{{/if}}
</div>
{{/if}}
{{document/section-attachment uploadLabel="Upload Attachments"
{{document/section-attachment uploadLabel="Upload Attachments"
editMode=editMode page=page document=document files=attachments
onAttachmentUpload=(action onAttachmentUpload)
onAttachmentDelete=(action onAttachmentDelete)}}

Some files were not shown because too many files have changed in this diff Show more