Преглед изворни кода

Merge branch 'support/apply-bootstrap4' into support/create-apiV3-for-update-bokkmark-status

itizawa пре 6 година
родитељ
комит
ef8f37b88e

+ 2 - 2
resource/locales/ja/translation.json

@@ -257,9 +257,9 @@
       "Redirect": "リダイレクトする"
     },
     "help": {
-      "redirect": "<code>%s</code> にアクセスされた際に自動的に新しいページにジャンプします",
+      "redirect": "<code class='text-break'>%s</code> にアクセスされた際に自動的に新しいページにジャンプします",
       "metadata": "最終更新ユーザー、最終更新日を更新せず維持します",
-      "recursive": "<code>%s</code> 配下のページも移動/名前変更します"
+      "recursive": "<code class='text-break'>%s</code> 配下のページも移動/名前変更します"
     }
   },
   "Put Back": "元に戻す",

+ 2 - 0
src/client/js/app.jsx

@@ -35,6 +35,7 @@ import CommentContainer from './services/CommentContainer';
 import EditorContainer from './services/EditorContainer';
 import TagContainer from './services/TagContainer';
 import GrowiSubNavigation from './components/Navbar/GrowiSubNavigation';
+import GrowiSubNavigationForUserPage from './components/Navbar/GrowiSubNavigationForUserPage';
 import PersonalContainer from './services/PersonalContainer';
 
 import { appContainer, componentMappings } from './bootstrap';
@@ -101,6 +102,7 @@ if (pageContainer.state.path != null) {
     'revision-path': <RevisionPath behaviorType={appContainer.config.behaviorType} pageId={pageContainer.state.pageId} pagePath={pageContainer.state.path} />,
     'tag-label': <TagLabels />,
     'grw-subnav': <GrowiSubNavigation />,
+    'grw-subnav-for-user-page': <GrowiSubNavigationForUserPage />,
   });
 }
 

+ 83 - 0
src/client/js/components/Navbar/GrowiSubNavigationForUserPage.jsx

@@ -0,0 +1,83 @@
+import React, { useState, useEffect } from 'react';
+import PropTypes from 'prop-types';
+
+import { withTranslation } from 'react-i18next';
+import { throttle } from 'throttle-debounce';
+
+import { createSubscribedElement } from '../UnstatedUtils';
+import AppContainer from '../../services/AppContainer';
+import RevisionPath from '../Page/RevisionPath';
+import PageContainer from '../../services/PageContainer';
+import BookmarkButton from '../BookmarkButton';
+import UserPicture from '../User/UserPicture';
+
+const GrowiSubNavigationForUserPage = (props) => {
+  const pageUser = JSON.parse(document.querySelector('#grw-subnav-for-user-page').getAttribute('data-page-user'));
+  const { appContainer, pageContainer } = props;
+  const { pageId } = pageContainer.state;
+  const [isCompactMode, setIsCompactMode] = useState(false);
+  const scrollAmountForFixed = 175;
+  const layoutType = appContainer.getConfig().layoutType;
+
+  useEffect(() => {
+    window.addEventListener('scroll', throttle(300, () => {
+      setIsCompactMode(window.pageYOffset > scrollAmountForFixed);
+    }));
+  }, []);
+
+  return (
+    <div className={(isCompactMode && layoutType === 'growi') && 'fixed-top grw-compact-subnavbar px-3'}>
+
+      {/* Page Path */}
+      <h4>
+        <RevisionPath behaviorType={appContainer.config.behaviorType} pageId={pageId} pagePath={pageContainer.state.path} />
+      </h4>
+
+      <div className="d-flex">
+        <div className="users-info d-flex align-items-center mr-auto">
+          <UserPicture user={pageUser} />
+
+          <div className="users-meta">
+            <div className="d-flex align-items-center">
+              <h1>
+                {pageUser.name}
+              </h1>
+            </div>
+            <div className="user-page-meta">
+              <ul>
+                <li className="user-page-username"><i className="icon-user mr-1"></i>{pageUser.username}</li>
+                <li className="user-page-email">
+                  <i className="icon-envelope mr-1"></i>
+                  {pageUser.isEmailPublished ? pageUser.email : '*****'}
+                </li>
+                {pageUser.introduction && <li className="user-page-introduction"><p>{pageUser.introduction}</p></li>}
+              </ul>
+            </div>
+          </div>
+        </div>
+
+        {/* Header Button */}
+        <BookmarkButton pageId={pageId} crowi={appContainer} />
+      </div>
+
+
+    </div>
+  );
+
+};
+
+/**
+ * Wrapper component for using unstated
+ */
+const GrowiSubNavigationForUserPageWrapper = (props) => {
+  return createSubscribedElement(GrowiSubNavigationForUserPage, props, [AppContainer, PageContainer]);
+};
+
+
+GrowiSubNavigationForUserPage.propTypes = {
+  t: PropTypes.func.isRequired, //  i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
+};
+
+export default withTranslation()(GrowiSubNavigationForUserPageWrapper);

+ 1 - 1
src/client/js/components/PageComment/Comment.jsx

@@ -206,7 +206,7 @@ class Comment extends React.PureComponent {
               </div>
               <div className="page-comment-body">{commentBody}</div>
               <div className="page-comment-meta">
-                {commentedDate}
+                <span><a href={`#${commentId}`}>{commentedDate}</a></span>
                 <UncontrolledTooltip placement="bottom" fade={false} target={commentedDateId}>{commentedDateFormatted}</UncontrolledTooltip>
                 { isEdited && (
                   <>

+ 1 - 1
src/client/js/components/SearchPage/SearchResultList.jsx

@@ -21,7 +21,7 @@ class SearchResultList extends React.Component {
         // Add prefix 'id_' in id attr, because scrollspy of bootstrap doesn't work when the first letter of id of target component is numeral.
         <div id={`id_${page._id}`} key={page._id} className="search-result-page mb-5">
           <h2>
-            <a href={page.path}>{page.path}</a>
+            <a href={page.path} className="text-break">{page.path}</a>
             { showTags && (
               <div className="mt-1 small"><i className="tag-icon icon-tag"></i> {page.tags.join(', ')}</div>
             )}

+ 1 - 1
src/client/styles/scss/_login.scss

@@ -122,7 +122,7 @@
   .collapse-external-auth {
     overflow: hidden;
 
-    &:not(.in) {
+    &:not(.show) {
       height: 0;
       padding: 0 !important;
     }

+ 0 - 218
src/server/routes/bookmark.js

@@ -1,218 +0,0 @@
-/**
- * @swagger
- *  tags:
- *    name: Bookmarks
- */
-
-/**
- * @swagger
- *
- *  components:
- *    schemas:
- *      Bookmark:
- *        description: Bookmark
- *        type: object
- *        properties:
- *          _id:
- *            type: string
- *            description: page ID
- *            example: 5e07345972560e001761fa63
- *          __v:
- *            type: number
- *            description: DB record version
- *            example: 0
- *          createdAt:
- *            type: string
- *            description: date created at
- *            example: 2010-01-01T00:00:00.000Z
- *          page:
- *            $ref: '#/components/schemas/Page/properties/_id'
- *          user:
- *            $ref: '#/components/schemas/User/properties/_id'
- */
-
-module.exports = function(crowi, app) {
-  const debug = require('debug')('growi:routes:bookmark');
-  const Bookmark = crowi.model('Bookmark');
-  const Page = crowi.model('Page');
-  const ApiResponse = require('../util/apiResponse');
-  const ApiPaginate = require('../util/apiPaginate');
-  const actions = {};
-  actions.api = {};
-
-  /**
-   * @swagger
-   *
-   *    /bookmarks.get:
-   *      get:
-   *        tags: [Bookmarks, CrowiCompatibles]
-   *        operationId: getBookmark
-   *        summary: /bookmarks.get
-   *        description: Get bookmark of the page with the user
-   *        parameters:
-   *          - in: query
-   *            name: page_id
-   *            required: true
-   *            schema:
-   *              $ref: '#/components/schemas/Page/properties/_id'
-   *        responses:
-   *          200:
-   *            description: Succeeded to get bookmark of the page with the user.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    bookmark:
-   *                      $ref: '#/components/schemas/Bookmark'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {get} /bookmarks.get Get bookmark of the page with the user
-   * @apiName GetBookmarks
-   * @apiGroup Bookmark
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  actions.api.get = function(req, res) {
-    const pageId = req.query.page_id;
-
-    Bookmark.findByPageIdAndUserId(pageId, req.user)
-      .then((data) => {
-        debug('bookmark found', pageId, data);
-        const result = {};
-
-        result.bookmark = data;
-        return res.json(ApiResponse.success(result));
-      })
-      .catch((err) => {
-        return res.json(ApiResponse.error(err));
-      });
-  };
-
-  actions.api.list = function(req, res) {
-    const paginateOptions = ApiPaginate.parseOptions(req.query);
-
-    const options = Object.assign(paginateOptions, { populatePage: true });
-    Bookmark.findByUserId(req.user._id, options)
-      .then((result) => {
-        return res.json(ApiResponse.success(result));
-      })
-      .catch((err) => {
-        return res.json(ApiResponse.error(err));
-      });
-  };
-
-  /**
-   * @swagger
-   *
-   *    /bookmarks.add:
-   *      post:
-   *        tags: [Bookmarks, CrowiCompatibles]
-   *        operationId: addBookmark
-   *        summary: /bookmarks.add
-   *        description: Add bookmark of the page
-   *        parameters:
-   *          - in: query
-   *            name: page_id
-   *            schema:
-   *              $ref: '#/components/schemas/Page/properties/_id'
-   *            required: true
-   *        responses:
-   *          200:
-   *            description: Succeeded to add bookmark of the page.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    bookmark:
-   *                      $ref: '#/components/schemas/Bookmark'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {post} /bookmarks.add Add bookmark of the page
-   * @apiName AddBookmark
-   * @apiGroup Bookmark
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  actions.api.add = async function(req, res) {
-    const pageId = req.body.page_id;
-
-    const page = await Page.findByIdAndViewer(pageId, req.user);
-    if (page == null) {
-      return res.json(ApiResponse.success({ bookmark: null }));
-    }
-
-    const bookmark = await Bookmark.add(page, req.user);
-
-    bookmark.depopulate('page');
-    bookmark.depopulate('user');
-    const result = { bookmark };
-
-    return res.json(ApiResponse.success(result));
-  };
-
-  /**
-   * @swagger
-   *
-   *    /bookmarks.remove:
-   *      post:
-   *        tags: [Bookmarks, CrowiCompatibles]
-   *        operationId: removeBookmark
-   *        summary: /bookmarks.remove
-   *        description: Remove bookmark of the page
-   *        requestBody:
-   *          content:
-   *            application/json:
-   *              schema:
-   *                properties:
-   *                  page_id:
-   *                    $ref: '#/components/schemas/Page/properties/_id'
-   *                required:
-   *                  - page_id
-   *        responses:
-   *          200:
-   *            description: Succeeded to remove bookmark of the page.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {post} /bookmarks.remove Remove bookmark of the page
-   * @apiName RemoveBookmark
-   * @apiGroup Bookmark
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  actions.api.remove = function(req, res) {
-    const pageId = req.body.page_id;
-
-    Bookmark.removeBookmark(pageId, req.user)
-      .then((data) => {
-        debug('Bookmark removed.', data); // if the bookmark is not exists, this 'data' is null
-        return res.json(ApiResponse.success());
-      })
-      .catch((err) => {
-        return res.json(ApiResponse.error(err));
-      });
-  };
-
-  return actions;
-};

+ 0 - 6
src/server/routes/index.js

@@ -23,7 +23,6 @@ module.exports = function(crowi, app) {
   const user = require('./user')(crowi, app);
   const attachment = require('./attachment')(crowi, app);
   const comment = require('./comment')(crowi, app);
-  const bookmark = require('./bookmark')(crowi, app);
   const tag = require('./tag')(crowi, app);
   const revision = require('./revision')(crowi, app);
   const search = require('./search')(crowi, app);
@@ -160,11 +159,6 @@ module.exports = function(crowi, app) {
   app.post('/_api/comments.add'       , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , csrf, comment.api.add);
   app.post('/_api/comments.update'    , comment.api.validators.add(), accessTokenParser , loginRequiredStrictly , csrf, comment.api.update);
   app.post('/_api/comments.remove'    , accessTokenParser , loginRequiredStrictly , csrf, comment.api.remove);
-  app.get('/_api/bookmarks.get'       , accessTokenParser , loginRequired , bookmark.api.get);
-  app.post('/_api/bookmarks.add'      , accessTokenParser , loginRequiredStrictly , csrf, bookmark.api.add);
-  app.post('/_api/bookmarks.remove'   , accessTokenParser , loginRequiredStrictly , csrf, bookmark.api.remove);
-  app.post('/_api/likes.add'          , accessTokenParser , loginRequiredStrictly , csrf, page.api.like);
-  app.post('/_api/likes.remove'       , accessTokenParser , loginRequiredStrictly , csrf, page.api.unlike);
   app.get('/_api/attachments.list'    , accessTokenParser , loginRequired , attachment.api.list);
   app.post('/_api/attachments.add'                  , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly ,csrf, attachment.api.add);
   app.post('/_api/attachments.uploadProfileImage'   , uploads.single('file'), autoReap, accessTokenParser, loginRequiredStrictly ,csrf, attachment.api.uploadProfileImage);

+ 0 - 144
src/server/routes/page.js

@@ -1230,150 +1230,6 @@ module.exports = function(crowi, app) {
     return res.json(ApiResponse.success(result));
   };
 
-  /**
-   * @swagger
-   *
-   *    /likes.add:
-   *      post:
-   *        tags: [Likes, CrowiCompatibles]
-   *        operationId: addLike
-   *        summary: /likes.add
-   *        description: Like page
-   *        requestBody:
-   *          content:
-   *            application/json:
-   *              schema:
-   *                properties:
-   *                  page_id:
-   *                    $ref: '#/components/schemas/Page/properties/_id'
-   *                required:
-   *                  - page_id
-   *        responses:
-   *          200:
-   *            description: Succeeded to be page liked.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    page:
-   *                      $ref: '#/components/schemas/Page'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {post} /likes.add Like page
-   * @apiName LikePage
-   * @apiGroup Page
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  api.like = async function(req, res) {
-    const pageId = req.body.page_id;
-    if (!pageId) {
-      return res.json(ApiResponse.error('page_id required'));
-    }
-    if (!req.user) {
-      return res.json(ApiResponse.error('user required'));
-    }
-
-    let page;
-    try {
-      page = await Page.findByIdAndViewer(pageId, req.user);
-      if (page == null) {
-        throw new Error(`Page '${pageId}' is not found or forbidden`);
-      }
-      page = await page.like(req.user);
-    }
-    catch (err) {
-      debug('Seen user update error', err);
-      return res.json(ApiResponse.error(err));
-    }
-
-    const result = { page };
-    result.seenUser = page.seenUsers;
-    res.json(ApiResponse.success(result));
-
-    try {
-      // global notification
-      await globalNotificationService.fire(GlobalNotificationSetting.EVENT.PAGE_LIKE, page, req.user);
-    }
-    catch (err) {
-      logger.error('Like notification failed', err);
-    }
-  };
-
-  /**
-   * @swagger
-   *
-   *    /likes.remove:
-   *      post:
-   *        tags: [Likes, CrowiCompatibles]
-   *        operationId: removeLike
-   *        summary: /likes.remove
-   *        description: Unlike page
-   *        requestBody:
-   *          content:
-   *            application/json:
-   *              schema:
-   *                properties:
-   *                  page_id:
-   *                    $ref: '#/components/schemas/Page/properties/_id'
-   *                required:
-   *                  - page_id
-   *        responses:
-   *          200:
-   *            description: Succeeded to not be page liked.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    page:
-   *                      $ref: '#/components/schemas/Page'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {post} /likes.remove Unlike page
-   * @apiName UnlikePage
-   * @apiGroup Page
-   *
-   * @apiParam {String} page_id Page Id.
-   */
-  api.unlike = async function(req, res) {
-    const pageId = req.body.page_id;
-    if (!pageId) {
-      return res.json(ApiResponse.error('page_id required'));
-    }
-    if (req.user == null) {
-      return res.json(ApiResponse.error('user required'));
-    }
-
-    let page;
-    try {
-      page = await Page.findByIdAndViewer(pageId, req.user);
-      if (page == null) {
-        throw new Error(`Page '${pageId}' is not found or forbidden`);
-      }
-      page = await page.unlike(req.user);
-    }
-    catch (err) {
-      debug('Seen user update error', err);
-      return res.json(ApiResponse.error(err));
-    }
-
-    const result = { page };
-    result.seenUser = page.seenUsers;
-    return res.json(ApiResponse.success(result));
-  };
-
   /**
    * @swagger
    *

+ 1 - 1
src/server/views/layout-crowi/page_list.html

@@ -46,7 +46,7 @@
     {% include '../widget/page_content.html' %}
   </div>
 
-  <div class="row page-list hidden-print {% if page.isPortal() %}mt-5{% endif %}">
+  <div class="row page-list d-print-none {% if page.isPortal() %}mt-5{% endif %}">
     <div class="col-md-12">
       {% include '../widget/page_list_and_timeline.html' %}
     </div>

+ 1 - 1
src/server/views/layout-growi/page.html

@@ -35,7 +35,7 @@
   </div>
 
   {% if 'growi' === getConfig('crowi', 'customize:behavior') || 'crowi-plus' === getConfig('crowi', 'customize:behavior') %}
-  <div class="row page-list hidden-print mt-5">
+  <div class="row page-list d-print-none mt-5">
     <div class="col-md-10">
       {% include '../widget/page_list_and_timeline.html' %}
     </div>

+ 1 - 1
src/server/views/layout-growi/page_list.html

@@ -34,7 +34,7 @@
 
   </div>
 
-  <div class="row page-list hidden-print {% if page.isPortal() %}mt-5{% endif %}">
+  <div class="row page-list d-print-none {% if page.isPortal() %}mt-5{% endif %}">
     <div class="col-md-10">
       {% include '../widget/page_list_and_timeline.html' %}
     </div>

+ 2 - 2
src/server/views/layout-growi/user_page.html

@@ -7,7 +7,7 @@
 
 {% block content_header %}
   {% if pageUser %}
-    {% include '../widget/user_page_header.html' %}
+    <header id="grw-subnav-for-user-page" class="user-page-header" data-page-user="{{ pageUser|json }}"></header>
   {% else %}
     {% parent %}
   {% endif %}
@@ -59,7 +59,7 @@
   </div>
 
   {% if 'growi' === getConfig('crowi', 'customize:behavior') || 'crowi-plus' === getConfig('crowi', 'customize:behavior') %}
-  <div class="row page-list hidden-print mt-5">
+  <div class="row page-list d-print-none mt-5">
     <div class="col-md-10">
       {% include '../widget/page_list_and_timeline.html' %}
     </div>

+ 1 - 1
src/server/views/layout-kibela/user_page.html

@@ -7,7 +7,7 @@
 
 {% block content_header %}
   {% if pageUser %}
-    {% include '../widget/user_page_header.html' %}
+    <header id="grw-subnav-for-user-page" class="user-page-header" data-page-user="{{ pageUser|json }}"></header>
   {% else %}
     {% parent %}
   {% endif %}

+ 69 - 67
src/server/views/login.html

@@ -30,74 +30,76 @@
         <div class="logo mb-3">{% include 'widget/logo.html' %}</div>
         <h1>{{ appService.getAppTitle() }}</h1>
 
-        <div class="login-form-errors">
-          {% if isLdapSetupFailed() %}
-          <div class="alert alert-warning small">
-            <strong><i class="icon-fw icon-info"></i>LDAP is enabled but the configuration has something wrong.</strong>
-            <br>
-            (Please set the environment variables <code>DEBUG=crowi:service:PassportService</code> to get the logs)
-          </div>
-          {% endif %}
-
-          {#
-          # The case that there already exists a user whose username matches ID of the newly created LDAP user
-          # https://github.com/weseek/growi/issues/193
-          #}
-          {% set failedProviderForDuplicatedUsernameException = req.flash('provider-DuplicatedUsernameException') %}
-          {% if failedProviderForDuplicatedUsernameException != null %}
-          <div class="alert alert-warning small">
-            <p><strong><i class="icon-fw icon-ban"></i>DuplicatedUsernameException occured</strong></p>
-            <p>
-              Your {{ failedProviderForDuplicatedUsernameException }} authentication was succeess, but a new user could not be created.
-              See the issue <a href="https://github.com/weseek/growi/issues/193">#193</a>.
-            </p>
-          </div>
-          {% endif %}
+        <div class="row">
+          <div class="login-form-errors col-12">
+            {% if isLdapSetupFailed() %}
+            <div class="alert alert-warning small">
+              <strong><i class="icon-fw icon-info"></i>LDAP is enabled but the configuration has something wrong.</strong>
+              <br>
+              (Please set the environment variables <code>DEBUG=crowi:service:PassportService</code> to get the logs)
+            </div>
+            {% endif %}
 
-          {% set success = req.flash('successMessage') %}
-          {% if success.length %}
-          <div class="alert alert-success">
-            {{ success }}
-          </div>
-          {% endif %}
+            {#
+            # The case that there already exists a user whose username matches ID of the newly created LDAP user
+            # https://github.com/weseek/growi/issues/193
+            #}
+            {% set failedProviderForDuplicatedUsernameException = req.flash('provider-DuplicatedUsernameException') %}
+            {% if failedProviderForDuplicatedUsernameException != null %}
+            <div class="alert alert-warning small">
+              <p><strong><i class="icon-fw icon-ban"></i>DuplicatedUsernameException occured</strong></p>
+              <p>
+                Your {{ failedProviderForDuplicatedUsernameException }} authentication was succeess, but a new user could not be created.
+                See the issue <a href="https://github.com/weseek/growi/issues/193">#193</a>.
+              </p>
+            </div>
+            {% endif %}
 
-          {% set warn = req.flash('warningMessage') %}
-          {% if warn.length %}
-          {% for w in warn %}
-          <div class="alert alert-warning">
-            {{ w }}
-          </div>
-          {% endfor %}
-          {% endif %}
-
-          {% set error = req.flash('errorMessage') %}
-          {% if error.length %}
-          {% for e in error %}
-          <div class="alert alert-danger">
-            {{ e }}
-          </div>
-          {% endfor %}
-          {% endif %}
-
-          {% if req.form.errors.length > 0 %}
-          <div class="alert alert-danger">
-            <ul>
-            {% for error in req.form.errors %}
-              <li>{{ error }}</li>
+            {% set success = req.flash('successMessage') %}
+            {% if success.length %}
+            <div class="alert alert-success">
+              {{ success }}
+            </div>
+            {% endif %}
+
+            {% set warn = req.flash('warningMessage') %}
+            {% if warn.length %}
+            {% for w in warn %}
+            <div class="alert alert-warning">
+              {{ w }}
+            </div>
             {% endfor %}
-            </ul>
+            {% endif %}
+
+            {% set error = req.flash('errorMessage') %}
+            {% if error.length %}
+            {% for e in error %}
+            <div class="alert alert-danger">
+              {{ e }}
+            </div>
+            {% endfor %}
+            {% endif %}
+
+            {% if req.form.errors.length > 0 %}
+            <div class="alert alert-danger">
+              <ul>
+              {% for error in req.form.errors %}
+                <li>{{ error }}</li>
+              {% endfor %}
+              </ul>
+            </div>
+            {% endif %}
           </div>
-          {% endif %}
-        </div>
-        <div id="register-form-errors">
-          {% set message = req.flash('registerWarningMessage') %}
-          {% if message.length %}
-          <div class="alert alert-danger">
-            {% for msg in message %}
-            {{ msg }}<br>
-            {% endfor  %}
+          <div id="register-form-errors">
+            {% set message = req.flash('registerWarningMessage') %}
+            {% if message.length %}
+            <div class="alert alert-danger">
+              {% for msg in message %}
+              {{ msg }}<br>
+              {% endfor  %}
+            </div>
+            {% endif %}
           </div>
-          {% endif %}
         </div>
       </div>
     </div>
@@ -118,17 +120,17 @@
             {% if isLocalOrLdapStrategiesEnabled %}
             <form role="form" action="/login" method="post">
 
-              <div class="input-group">
+              <div class="input-group mb-3">
                 <div class="input-group-prepend">
                   <span class="input-group-text"><i class="icon-user"></i></span>
                 </div>
                 <input type="text" class="form-control" placeholder="Username or E-mail" name="loginForm[username]">
                 {% if passportService.isLdapStrategySetup %}
-                <span class="input-group-append">
-                  <small class="text-success">
+                <div class="input-group-append">
+                  <small class="input-group-text text-success">
                     <i class="icon-fw icon-check"></i> LDAP
                   </small>
-                </span>
+                </div>
                 {% endif %}
               </div>
 

+ 1 - 1
src/server/views/widget/page_list.html

@@ -10,7 +10,7 @@
 <li>
   <img src="{{ page.lastUpdateUser|picture }}" class="picture rounded-circle">
   <a href="{{ page.path }}"
-    class="page-list-link"
+    class="page-list-link text-break"
     data-path="{{ page.path }}">{{ decodeURIComponent(page.path) }}
   </a>
   <span class="page-list-meta">

+ 0 - 31
src/server/views/widget/user_page_header.html

@@ -1,31 +0,0 @@
-<header id="page-header" class="user-page-header">
-
-  <h4 id="revision-path"></h4>
-
-  <div class="users-info d-flex align-items-center">
-    <img src="{{ pageUser|picture }}" class="picture rounded-circle">
-    <div class="users-meta" style="flex: 1;">
-      <div class="d-flex align-items-center">
-        <h1>
-          {{ pageUser.name }}
-        </h1>
-      </div>
-      <div class="user-page-meta">
-        <ul>
-          <li class="user-page-username"><i class="icon-user"></i> {{ pageUser.username }}</li>
-          <li class="user-page-email">
-            <i class="icon-envelope"></i>
-            {% if pageUser.isEmailPublished %}
-              {{ pageUser.email }}
-            {% else %}
-              *****
-            {% endif %}
-          </li>
-          {% if pageUser.introduction %}
-          <li class="user-page-introduction"><p>{{ pageUser.introduction|nl2br }}</p></li>
-          {% endif %}
-        </ul>
-      </div>
-    </div>
-  </div>
-</header>