Merge pull request #1042 from taigaio/enhancement/list-all-wiki-pages

Enhancement #4340: Add list all wiki pages
stable
David Barragán Merino 2016-06-16 15:48:40 +02:00 committed by GitHub
commit e8e8cbcc87
17 changed files with 373 additions and 55 deletions

View File

@ -4,17 +4,20 @@
## 2.2.0 ???? (Unreleased)
### Features
- Show a confirmation notice when you exit edit mode by pressing ESC in the markdown inputs.
- Add the tribe button to link stories from tree.taiga.io with gigs in tribe.taiga.io.
- Show a confirmation notice when you exit edit mode by pressing ESC in the markdown inputs.
- Errors (not found, server error, permissions and blocked project) don't change the current url.
- Neew Attachments image slider in preview mode.
- New admin area to edit the tag colors used in your project.
- Display the current user (me) at first in assignment lightbox (thanks to [@mikaoelitiana](https://github.com/mikaoelitiana))
- Add a new permissions to allow add comments instead of use the existent modify permission for this purpose.
- Ability to edit comments, view edition history and redesign comments module UI.
- Divide the user dashboard in two columns in large screens,
- Upvote and downvote issues from the issues list.
- Divide dashboard in two columns in large screens,
- Drag & Drop ordering for wiki links.
- Comments:
- Add a new permissions to allow add comments instead of use the existent modify permission for this purpose.
- Ability to edit comments, view edition history and redesign comments module UI.
- Wiki:
- Drag & Drop ordering for wiki links.
- Add a list of all wiki pages
### Misc
- Lots of small and not so small bugfixes.

View File

@ -188,6 +188,13 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven
# Wiki
$routeProvider.when("/project/:pslug/wiki",
{redirectTo: (params) -> "/project/#{params.pslug}/wiki/home"}, )
$routeProvider.when("/project/:pslug/wiki-list",
{
templateUrl: "wiki/wiki-list.html",
loader: true,
section: "wiki"
}
)
$routeProvider.when("/project/:pslug/wiki/:slug",
{
templateUrl: "wiki/wiki.html",

View File

@ -80,6 +80,7 @@ urls = {
"project-issues-detail": "/project/:project/issue/:ref"
"project-wiki": "/project/:project/wiki"
"project-wiki-list": "/project/:project/wiki-list"
"project-wiki-page": "/project/:project/wiki/:slug"
# Team

View File

@ -165,6 +165,39 @@ CreatedByDisplayDirective = ($template, $compile, $translate, $navUrls)->
module.directive("tgCreatedByDisplay", ["$tgTemplate", "$compile", "$translate", "$tgNavUrls",
CreatedByDisplayDirective])
UserDisplayDirective = ($template, $compile, $translate, $navUrls)->
# Display the user information (full name and photo).
#
# Example:
# div.creator(tg-user-display, tg-user-id="{{ user.id }}")
#
# Requirements:
# - scope.usersById object is required.
link = ($scope, $el, $attrs) ->
id = $attrs.tgUserId
console.log($scope.usersById[id])
$scope.user = $scope.usersById[id] or {
full_name_display: $translate.instant("COMMON.EXTERNAL_USER")
photo: "/" + window._version + "/images/user-noimage.png"
}
$scope.url = if $scope.user.is_active then $navUrls.resolve("user-profile", {username: $scope.user.username}) else ""
$scope.$on "$destroy", ->
$el.off()
return {
link: link
restrict: "EA"
scope: true,
templateUrl: "common/components/user-display.html"
}
module.directive("tgUserDisplay", ["$tgTemplate", "$compile", "$translate", "$tgNavUrls",
UserDisplayDirective])
#############################################################################
## Watchers directive
#############################################################################

View File

@ -34,6 +34,9 @@ resourceProvider = ($repo, $http, $urls) ->
service.getBySlug = (projectId, slug) ->
return $repo.queryOne("wiki", "by_slug?project=#{projectId}&slug=#{slug}")
service.list = (projectId) ->
return $repo.queryMany("wiki", {project: projectId})
service.listLinks = (projectId) ->
return $repo.queryMany("wiki-links", {project: projectId})

View File

@ -0,0 +1,100 @@
###
# Copyright (C) 2014-2016 Andrey Antukh <niwi@niwi.nz>
# Copyright (C) 2014-2016 Jesús Espino Garcia <jespinog@gmail.com>
# Copyright (C) 2014-2016 David Barragán Merino <bameda@dbarragan.com>
# Copyright (C) 2014-2016 Alejandro Alonso <alejandro.alonso@kaleidos.net>
# Copyright (C) 2014-2016 Juan Francisco Alcántara <juanfran.alcantara@kaleidos.net>
# Copyright (C) 2014-2016 Xavi Julian <xavier.julian@kaleidos.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# File: modules/wiki/pages-list.coffee
###
taiga = @.taiga
mixOf = @.taiga.mixOf
module = angular.module("taigaWiki")
#############################################################################
## Wiki Pages List Controller
#############################################################################
class WikiPagesListController extends mixOf(taiga.Controller, taiga.PageMixin)
@.$inject = [
"$scope",
"$rootScope",
"$tgRepo",
"$tgModel",
"$tgConfirm",
"$tgResources",
"$routeParams",
"$q",
"$tgNavUrls",
"tgErrorHandlingService"
]
constructor: (@scope, @rootscope, @repo, @model, @confirm, @rs, @params, @q,
@navUrls, @errorHandlingService) ->
@scope.projectSlug = @params.pslug
@scope.wikiSlug = @params.slug
@scope.wikiTitle = @scope.wikiSlug
@scope.sectionName = "Wiki"
@scope.linksVisible = false
promise = @.loadInitialData()
# On Error
promise.then null, @.onInitialDataError.bind(@)
loadProject: ->
return @rs.projects.getBySlug(@params.pslug).then (project) =>
if not project.is_wiki_activated
@errorHandlingService.permissionDenied()
@scope.projectId = project.id
@scope.project = project
@scope.$emit('project:loaded', project)
return project
loadWikiPages: ->
promise = @rs.wiki.list(@scope.projectId).then (wikipages) =>
@scope.wikipages = wikipages
loadWikiLinks: ->
return @rs.wiki.listLinks(@scope.projectId).then (wikiLinks) =>
@scope.wikiLinks = wikiLinks
for link in @scope.wikiLinks
link.url = @navUrls.resolve("project-wiki-page", {
project: @scope.projectSlug
slug: link.href
})
selectedWikiLink = _.find(wikiLinks, {href: @scope.wikiSlug})
@scope.wikiTitle = selectedWikiLink.title if selectedWikiLink?
loadInitialData: ->
promise = @.loadProject()
return promise.then (project) =>
@.fillUsersAndRoles(project.members, project.roles)
@q.all([@.loadWikiLinks(), @.loadWikiPages()]).then @.checkLinksPerms.bind(this)
checkLinksPerms: ->
if @scope.project.my_permissions.indexOf("add_wiki_link") != -1 ||
(@scope.project.my_permissions.indexOf("view_wiki_links") != -1 && @scope.wikiLinks.length)
@scope.linksVisible = true
module.controller("WikiPagesListController", WikiPagesListController)

View File

@ -1459,13 +1459,24 @@
"DELETE_LIGHTBOX_TITLE": "Delete Wiki Page",
"DELETE_LINK_TITLE": "Delete Wiki link",
"NAVIGATION": {
"HOME": "Main Page",
"SECTION_NAME": "Links",
"ACTION_ADD_LINK": "Add link"
"ACTION_ADD_LINK": "Add link",
"ALL_PAGES": "All pages"
},
"SUMMARY": {
"TIMES_EDITED": "times <br />edited",
"LAST_EDIT": "last <br />edit",
"LAST_MODIFICATION": "last modification"
},
"SECTION_PAGES_LIST": "All pages",
"PAGES_LIST_COLUMNS": {
"TITLE": "Title",
"EDITIONS": "Editions",
"CREATED": "Created",
"MODIFIED": "Modified",
"CREATOR": "Creator",
"LAST_MODIFIER": "Last modifier"
}
},
"HINTS": {

View File

@ -0,0 +1,21 @@
.user-avatar(ng-if="url")
a(
href="{{url}}"
title="{{user.full_name_display}}"
)
img(
src="{{user.photo}}"
alt="{{user.full_name_display}}"
)
a.user-full-name(
ng-if="url"
href="{{url}}"
title="{{user.full_name_display}}"
) {{user.full_name_display}}
.user-avatar(ng-if="!url")
img(
src="{{user.photo}}"
alt="{{user.full_name_display}}"
)
span.user-full-name(ng-if="!url") {{user.full_name_display}}

View File

@ -0,0 +1,57 @@
doctype html
div.wrapper(
ng-controller="WikiPagesListController as ctrl"
ng-init="section='wiki'"
)
tg-project-menu
sidebar.menu-secondary.extrabar(ng-if="linksVisible")
section.wiki-nav(
tg-wiki-nav
ng-model="wikiLinks"
)
section.main.wiki
header
h1
span(tg-bo-bind="project.name")
span.green(translate="PROJECT.SECTION.WIKI")
span.date(translate="WIKI.SECTION_PAGES_LIST")
section.wiki-pages-table.basic-table
.row.title
.title-field(
translate="WIKI.PAGES_LIST_COLUMNS.TITLE"
)
.editions-field(
translate="WIKI.PAGES_LIST_COLUMNS.EDITIONS"
)
.creator-field(
translate="WIKI.PAGES_LIST_COLUMNS.CREATOR"
)
.created-field(
translate="WIKI.PAGES_LIST_COLUMNS.CREATED"
)
.last-modifier-field(
translate="WIKI.PAGES_LIST_COLUMNS.LAST_MODIFIER"
)
.modified-field(
translate="WIKI.PAGES_LIST_COLUMNS.MODIFIED"
)
.row.table-main(ng-repeat="wikipage in wikipages track by wikipage.slug")
.title-field
a(
href=""
tg-nav="project-wiki-page:project=project.slug,slug=wikipage.slug"
) {{wikipage.slug}}
.editions-field {{wikipage.editions}}
.creator-field(
tg-user-display
tg-user-id="{{wikipage.owner}}"
)
.created-field(tg-bo-bind="wikipage.created_date|momentFormat:'DD MMM YYYY HH:mm'")
.last-modifier-field(
tg-user-display
tg-user-id="{{wikipage.last_modifier}}"
)
.modified-field(tg-bo-bind="wikipage.modified_date|momentFormat:'DD MMM YYYY HH:mm'")

View File

@ -1,28 +1,45 @@
header
h1(translate="WIKI.NAVIGATION.SECTION_NAME")
h1(translate="WIKI.NAVIGATION.SECTION_NAME")
nav
ul.sortable
li.wiki-link(ng-repeat="link in wikiLinks", data-id!="{{ $index }}", tg-bind-scope)
tg-svg.dragger(svg-icon="icon-drag")
a.link-title(title!="{{ link.title }}", href!="{{ link.url }}") {{ link.title }}
ul
li.wiki-link
a.link-title(
href=""
tg-nav="project-wiki-list:project=project.slug"
translate="WIKI.NAVIGATION.ALL_PAGES"
)
<% if (deleteWikiLinkPermission) { %>
a.js-delete-link.remove-wiki-page(title!="{{'WIKI.DELETE_LINK_TITLE' | translate}}")
tg-svg(svg-icon="icon-trash")
<% } %>
li.wiki-link
a.link-title(
href=""
tg-nav="project-wiki:project=project.slug"
translate="WIKI.NAVIGATION.HOME"
)
input.hidden(
type="text"
placeholder="{{'COMMON.FIELDS.NAME' | translate}}"
value!="{{ link.title }}"
)
ul.sortable
li.wiki-link(ng-repeat="link in wikiLinks", data-id!="{{ $index }}", tg-bind-scope)
<% if (addWikiLinkPermission) { %>
tg-svg.dragger(svg-icon="icon-drag")
<% } %>
a.link-title(title!="{{ link.title }}", href!="{{ link.url }}") {{ link.title }}
li.new.hidden
input(
type="text"
placeholder="{{'COMMON.FIELDS.NAME' | translate}}"
)
<% if (deleteWikiLinkPermission) { %>
a.js-delete-link.remove-wiki-page(title!="{{'WIKI.DELETE_LINK_TITLE' | translate}}")
tg-svg(svg-icon="icon-trash")
<% } %>
input.hidden(
type="text"
placeholder="{{'COMMON.FIELDS.NAME' | translate}}"
value!="{{ link.title }}"
)
li.new.hidden
input(
type="text"
placeholder="{{'COMMON.FIELDS.NAME' | translate}}"
)
<% if (addWikiLinkPermission) { %>
a(

View File

@ -1,14 +1,14 @@
div.wiki-times-edited
span.number <%- totalEditions %>
span.description(translate="WIKI.SUMMARY.TIMES_EDITED")
div.wiki-last-modified
span.number <%- lastModifiedDate %>
span.description(translate="WIKI.SUMMARY.LAST_EDIT")
div.wiki-username-edition
figure.avatar
.wiki-username-edition
.avatar
img(src!="<%- user.imgUrl %>" alt!="<%- user.name %>")
div.wiki-user-modification
.wiki-user-modification
span.description(translate="WIKI.SUMMARY.LAST_MODIFICATION")
span.username <%- user.name %>
.wiki-last-modified
span.number <%- lastModifiedDate %>
span.description(translate="WIKI.SUMMARY.LAST_EDIT")
.wiki-times-edited
span.number <%- totalEditions %>
span.description(translate="WIKI.SUMMARY.TIMES_EDITED")

View File

@ -4,7 +4,10 @@ div.wrapper(ng-controller="WikiDetailController as ctrl",
ng-init="section='wiki'")
tg-project-menu
sidebar.menu-secondary.extrabar(ng-if="linksVisible")
section.wiki-nav(tg-wiki-nav, ng-model="wikiLinks")
section.wiki-nav(
tg-wiki-nav
ng-model="wikiLinks"
)
section.main.wiki
header
h1
@ -12,13 +15,18 @@ div.wrapper(ng-controller="WikiDetailController as ctrl",
span.green(translate="PROJECT.SECTION.WIKI")
div.summary.wiki-summary(tg-wiki-summary, ng-model="wiki", ng-if="wiki.id")
h2.wiki-title(ng-bind='wikiTitle')
section.wiki-content(
tg-editable-wysiwyg,
tg-editable-wiki-content,
ng-model="wiki"
)
div.summary.wiki-summary(
tg-wiki-summary
ng-model="wiki"
ng-if="wiki.id"
)
tg-attachments-full(
ng-if="wiki.id"

View File

@ -11,6 +11,9 @@
padding: .3rem 0;
text-align: left;
width: 100%;
@include breakpoint(tablet) {
flex-direction: column;
}
@for $i from 1 through 8 {
.width-#{$i} {
flex-basis: 50px;

View File

@ -1,11 +1,17 @@
.wiki {
.wysiwyg {
margin-bottom: 0;
}
.wiki-title {
@include font-type(light);
@include font-size(larger);
@include font-size(xxlarge);
margin-bottom: 0;
padding: 1rem;
}
.remove {
@include font-size(small);
color: $gray-light;
cursor: pointer;
&:hover {
color: $red-light;
transition: color .1s linear;
@ -22,8 +28,8 @@
}
.wiki-content {
@include cursor-progress;
margin-bottom: 2rem;
@include font-size(large);
max-width: 1024px;
position: relative;
&.editable {
&:hover {

View File

@ -47,9 +47,6 @@
}
.wiki-nav {
ul {
border-top: 1px solid $gray-light;
}
.add-button {
color: $white;
display: block;

View File

@ -0,0 +1,49 @@
.wiki-pages-table {
display: flex;
.row {
padding: .5rem;
}
.title {
@include font-size(medium);
@include font-type(bold);
}
.table-main {
@include font-size(small);
}
.title-field {
flex-basis: 180px;
flex-grow: 1;
flex-shrink: 0;
}
.created-field,
.created-field,
.modified-field {
flex-basis: 10vw;
flex-grow: 0;
flex-shrink: 0;
margin-right: .5rem;
}
.editions-field {
flex-basis: 80px;
flex-grow: 0;
flex-shrink: 0;
margin-right: .5rem;
text-align: center;
}
.creator-field,
.last-modifier-field {
align-items: center;
display: flex;
flex-basis: 200px;
.user-avatar {
flex-grow: 0;
img {
height: 2rem;
}
}
.user-full-name {
flex-grow: 1;
padding: .5rem;
}
}
}

View File

@ -1,28 +1,30 @@
.wiki-summary {
align-items: center;
flex-wrap: wrap;
justify-content: flex-start;
margin-top: 1rem;
&.summary {
background: $mass-white;
color: $gray;
}
div {
display: flex;
justify-content: space-between;
margin-right: 1rem;
}
.number {
line-height: 2rem;
top: 0;
margin-right: 1.25rem;
}
.wiki-user-modification {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
figure {
margin-right: .3rem;
width: 32px;
.avatar {
margin-right: .5rem;
width: 2.25rem;
}
img {
height: 100%;
width: 100%;
}
.username {
@include font-size(large);
color: $primary-light;
white-space: nowrap;
}
}