Просмотр исходного кода

Merge branch 'support/reactify-login-page-accessable-ex-auth-url' into support/reactify-login-page-adjust-layout

# Conflicts:
#	src/client/js/components/LoginForm.jsx
yusuketk 5 лет назад
Родитель
Сommit
2c02851e82

+ 4 - 4
src/client/js/components/Admin/UserManagement.jsx

@@ -159,8 +159,8 @@ class UserManagement extends React.Component {
         <h2>{t('User_Management')}</h2>
         <div className="border-top border-bottom">
 
-          <div className="d-flex justify-content-start align-items-center my-2">
-            <div className="d-flex align-items-baseline">
+          <div className="row d-flex justify-content-start align-items-center my-2">
+            <div className="col-md-4 d-flex align-items-center my-2">
               <i className="icon-magnifier mr-1"></i>
               <span className="search-typeahead">
                 <input
@@ -172,7 +172,7 @@ class UserManagement extends React.Component {
               </span>
             </div>
 
-            <div className="mx-5">
+            <div className="col-md-6 my-2">
               <div className="form-inline">
                 {this.renderCheckbox('all', 'All', 'primary')}
                 {this.renderCheckbox('registered', 'Approval Pending', 'info')}
@@ -188,7 +188,7 @@ class UserManagement extends React.Component {
               </div>
             </div>
 
-            <div>
+            <div className="col-md-2 my-2">
               <button
                 type="button"
                 className="btn btn-outline-secondary btn-sm"

+ 82 - 72
src/client/js/components/LoginForm.jsx

@@ -3,55 +3,43 @@ import PropTypes from 'prop-types';
 
 import { withTranslation } from 'react-i18next';
 
+import { createSubscribedElement } from './UnstatedUtils';
+import AppContainer from '../services/AppContainer';
+
 class LoginForm extends React.Component {
 
   constructor(props) {
     super(props);
 
-    this.isRegistrationEnabled = false;
-    this.registrationMode = 'Closed';
-    this.registrationWhiteList = [];
-    this.isLocalStrategySetup = false;
-    this.isLdapStrategySetup = false;
-    this.objOfIsExternalAuthEnableds = {};
+    this.state = {
+      isRegistering: false,
+    };
 
     this.switchForm = this.switchForm.bind(this);
+    this.handleLoginWithExternalAuth = this.handleLoginWithExternalAuth.bind(this);
     this.renderLocalOrLdapLoginForm = this.renderLocalOrLdapLoginForm.bind(this);
     this.renderExternalAuthLoginForm = this.renderExternalAuthLoginForm.bind(this);
     this.renderExternalAuthInput = this.renderExternalAuthInput.bind(this);
     this.renderRegisterForm = this.renderRegisterForm.bind(this);
+
+    const { hash } = window.location;
+    if (hash === '#register') {
+      this.state.isRegistering = true;
+    }
   }
 
-  componentWillMount() {
-    // [TODO][GW-1913] get params from server with axios
-    this.isRegistrationEnabled = true;
-    this.registrationMode = 'Open';
-    this.registrationWhiteList = [];
-    this.isLocalStrategySetup = true;
-    this.isLdapStrategySetup = true;
-    this.objOfIsExternalAuthEnableds = {
-      google: true,
-      github: true,
-      facebook: true,
-      twitter: true,
-      oidc: true,
-      saml: true,
-      basic: true,
-    };
+  switchForm() {
+    this.setState({ isRegistering: !this.state.isRegistering });
   }
 
-  // for flip [TODO][GW-1865] use state or react component for flip
-  switchForm(e) {
-    if (e.target.id === 'register') {
-      $('#login-dialog').addClass('to-flip');
-    }
-    else {
-      $('#login-dialog').removeClass('to-flip');
-    }
+  handleLoginWithExternalAuth(e) {
+    const auth = e.currentTarget.id;
+    const csrf = this.props.appContainer.csrfToken;
+    window.location.href = `/passport/${auth}?_csrf=${csrf}`;
   }
 
   renderLocalOrLdapLoginForm() {
-    const { t, csrf } = this.props;
+    const { t, appContainer, isLdapStrategySetup } = this.props;
 
     return (
       <form role="form" action="/login" method="post">
@@ -62,7 +50,7 @@ class LoginForm extends React.Component {
             </span>
           </div>
           <input type="text" className="form-control" placeholder="Username or E-mail" name="loginForm[username]" />
-          {this.isLdapStrategySetup && (
+          {isLdapStrategySetup && (
             <div className="input-group-append">
               <small className="input-group-text text-success">
                 <i className="icon-fw icon-check"></i> LDAP
@@ -81,8 +69,7 @@ class LoginForm extends React.Component {
         </div>
 
         <div className="input-group mt-5">
-          {/* [TODO][GW-1913] An AppContainer gets csrf data */}
-          <input type="hidden" name="_csrf" value={csrf} />
+          <input type="hidden" name="_csrf" value={appContainer.csrfToken} />
           <button type="submit" id="login" className="btn btn-fill login mx-auto">
             <div className="eff"></div>
             <span className="btn-label">
@@ -96,7 +83,7 @@ class LoginForm extends React.Component {
   }
 
   renderExternalAuthInput(auth) {
-    const { t, csrf } = this.props;
+    const { t } = this.props;
     const authIconNames = {
       google: 'google',
       github: 'github',
@@ -108,26 +95,22 @@ class LoginForm extends React.Component {
     };
 
     return (
-      <div className="col-6">
-        {/* [TODO][GW-1913] use onClick, and delete form tag */}
-        <form key={auth} role="form" action={`/passport/${auth}`} className="mb-2">
-          {/* [TODO][GW-1913] An AppContainer gets csrf data */}
-          <input type="hidden" name="_csrf" value={csrf} />
-          <button type="submit" className="btn btn-fill" id={auth}>
-            <div className="eff"></div>
-            <span className="btn-label">
-              <i className={`fa fa-${authIconNames[auth]}`}></i>
-            </span>
-            <span className="btn-label-text">{t('Sign in')}</span>
-          </button>
-          <div className="small text-right">by {auth} Account</div>
-        </form>
+      <div key={auth} className="col-6 mb-2">
+        <button type="button" className="btn btn-fill" id={auth} onClick={this.handleLoginWithExternalAuth}>
+          <div className="eff"></div>
+          <span className="btn-label">
+            <i className={`fa fa-${authIconNames[auth]}`}></i>
+          </span>
+          <span className="btn-label-text">{t('Sign in')}</span>
+        </button>
+        <div className="small text-right">by {auth} Account</div>
       </div>
     );
   }
 
   renderExternalAuthLoginForm() {
-    const isExternalAuthCollapsible = this.isLocalStrategySetup || this.isLdapStrategySetup;
+    const { isLocalStrategySetup, isLdapStrategySetup, objOfIsExternalAuthEnableds } = this.props;
+    const isExternalAuthCollapsible = isLocalStrategySetup || isLdapStrategySetup;
     const collapsibleClass = isExternalAuthCollapsible ? 'collapse collapse-external-auth collapse-anchor' : '';
 
     return (
@@ -135,8 +118,8 @@ class LoginForm extends React.Component {
         <div className="border-top border-bottom">
           <div id="external-auth" className={`external-auth ${collapsibleClass}`}>
             <div className="row mt-2">
-              {Object.keys(this.objOfIsExternalAuthEnableds).map(auth => {
-                if (!this.objOfIsExternalAuthEnableds[auth]) {
+              {Object.keys(objOfIsExternalAuthEnableds).map((auth) => {
+                if (!objOfIsExternalAuthEnableds[auth]) {
                   return;
                 }
                 return this.renderExternalAuthInput(auth);
@@ -161,10 +144,19 @@ class LoginForm extends React.Component {
   }
 
   renderRegisterForm() {
-    const { t, csrf } = this.props;
+    const {
+      t,
+      username,
+      name,
+      email,
+      appContainer,
+      registrationMode,
+      registrationWhiteList,
+    } = this.props;
+
     return (
       <div className="back">
-        {this.registrationMode === 'Restricted' && (
+        {registrationMode === 'Restricted' && (
           <p className="alert alert-warning">
             {t('page_register.notice.restricted')}
             <br />
@@ -178,7 +170,7 @@ class LoginForm extends React.Component {
                 <i className="icon-user"></i>
               </span>
             </div>
-            <input type="text" className="form-control" placeholder={t('User ID')} name="registerForm[username]" defaultValue={this.props.username} required />
+            <input type="text" className="form-control" placeholder={t('User ID')} name="registerForm[username]" defaultValue={username} required />
           </div>
           <p className="form-text text-danger">
             <span id="help-block-username"></span>
@@ -190,7 +182,7 @@ class LoginForm extends React.Component {
                 <i className="icon-tag"></i>
               </span>
             </div>
-            <input type="text" className="form-control" placeholder={t('Name')} name="registerForm[name]" defaultValue={this.props.name} required />
+            <input type="text" className="form-control" placeholder={t('Name')} name="registerForm[name]" defaultValue={name} required />
           </div>
 
           <div className="input-group">
@@ -199,17 +191,17 @@ class LoginForm extends React.Component {
                 <i className="icon-envelope"></i>
               </span>
             </div>
-            <input type="email" className="form-control" placeholder={t('Email')} name="registerForm[email]" defaultValue={this.props.email} required />
+            <input type="email" className="form-control" placeholder={t('Email')} name="registerForm[email]" defaultValue={email} required />
           </div>
 
-          {this.registrationWhiteList.length > 0 && (
+          {registrationWhiteList.length > 0 && (
             <>
               <p className="form-text">{t('page_register.form_help.email')}</p>
               <ul>
-                {this.registrationWhiteList.map((elem) => {
+                {registrationWhiteList.map((elem) => {
                   return (
-                    <li>
-                      <code>{{ elem }}</code>
+                    <li key={elem}>
+                      <code>{elem}</code>
                     </li>
                   );
                 })}
@@ -227,8 +219,7 @@ class LoginForm extends React.Component {
           </div>
 
           <div className="input-group justify-content-center mt-5">
-            {/* [TODO][GW-1913] An AppContainer gets csrf data */}
-            <input type="hidden" name="_csrf" value={csrf} />
+            <input type="hidden" name="_csrf" value={appContainer.csrfToken} />
             <button type="submit" className="btn btn-fill" id="register">
               <div className="eff"></div>
               <span className="btn-label">
@@ -243,7 +234,7 @@ class LoginForm extends React.Component {
 
         <div className="row">
           <div className="text-right col-12 py-1">
-            <a href="#login" id="login" className="link-switch" onClick={this.handleClick}>
+            <a href="#login" id="login" className="link-switch" onClick={this.switchForm}>
               <i className="icon-fw icon-login"></i>
               {t('Sign in is here')}
             </a>
@@ -254,11 +245,17 @@ class LoginForm extends React.Component {
   }
 
   render() {
-    const { t, isRegistering } = this.props;
+    const {
+      t,
+      isLocalStrategySetup,
+      isLdapStrategySetup,
+      isRegistrationEnabled,
+      objOfIsExternalAuthEnableds,
+    } = this.props;
 
-    const isLocalOrLdapStrategiesEnabled = this.isLocalStrategySetup || this.isLdapStrategySetup;
-    const registerFormClass = isRegistering ? 'to-flip' : '';
-    const isSomeExternalAuthEnabled = Object.values(this.objOfIsExternalAuthEnableds).some(elem => elem);
+    const isLocalOrLdapStrategiesEnabled = isLocalStrategySetup || isLdapStrategySetup;
+    const registerFormClass = this.state.isRegistering ? 'to-flip' : '';
+    const isSomeExternalAuthEnabled = Object.values(objOfIsExternalAuthEnableds).some(elem => elem);
 
     return (
       <div className={`login-dialog mx-auto flipper ${registerFormClass}`} id="login-dialog">
@@ -267,7 +264,7 @@ class LoginForm extends React.Component {
             <div className="front">
               {isLocalOrLdapStrategiesEnabled && this.renderLocalOrLdapLoginForm()}
               {isSomeExternalAuthEnabled && this.renderExternalAuthLoginForm()}
-              {this.isRegistrationEnabled && (
+              {isRegistrationEnabled && (
                 <div className="row">
                   <div className="col-12 text-right py-2">
                     <a href="#register" id="register" className="link-switch" onClick={this.switchForm}>
@@ -277,7 +274,7 @@ class LoginForm extends React.Component {
                 </div>
               )}
             </div>
-            {this.isRegistrationEnabled && this.renderRegisterForm()}
+            {isRegistrationEnabled && this.renderRegisterForm()}
           </div>
         </div>
         <a href="https://growi.org" className="link-growi-org pl-3">
@@ -289,14 +286,27 @@ class LoginForm extends React.Component {
 
 }
 
+/**
+ * Wrapper component for using unstated
+ */
+const LoginFormWrapper = (props) => {
+  return createSubscribedElement(LoginForm, props, [AppContainer]);
+};
+
 LoginForm.propTypes = {
   // i18next
   t: PropTypes.func.isRequired,
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   isRegistering: PropTypes.bool,
   username: PropTypes.string,
   name: PropTypes.string,
   email: PropTypes.string,
-  csrf: PropTypes.string,
+  isRegistrationEnabled: PropTypes.bool,
+  registrationMode: PropTypes.string,
+  registrationWhiteList: PropTypes.array,
+  isLocalStrategySetup: PropTypes.bool,
+  isLdapStrategySetup: PropTypes.bool,
+  objOfIsExternalAuthEnableds: PropTypes.object,
 };
 
-export default withTranslation()(LoginForm);
+export default withTranslation()(LoginFormWrapper);

+ 1 - 1
src/client/js/components/PageEditor/CodeMirrorEditor.jsx

@@ -567,7 +567,7 @@ export default class CodeMirrorEditor extends AbstractEditor {
           ? (
             <div className="text-right">
               {cheatsheetModalButton}
-              <div className="mb-2">
+              <div className="mb-2 d-none d-md-block">
                 <SimpleCheatsheet />
               </div>
             </div>

+ 9 - 2
src/client/js/components/StaffCredit/StaffCredit.jsx

@@ -49,6 +49,13 @@ export default class StaffCredit extends React.Component {
         const scrollTargetHeight = target.children().innerHeight();
         const duration = scrollTargetHeight / scrollSpeed;
         target.animate({ scrollTop: scrollTargetHeight }, duration, 'linear');
+
+        target.slimScroll({
+          height: target.innerHeight(),
+          // Able to scroll after automatic schooling is complete so set "bottom" to allow scrolling from the bottom.
+          start: 'bottom',
+          color: '#FFFFFF',
+        });
       }
       else {
         // add UserCommand
@@ -97,7 +104,7 @@ export default class StaffCredit extends React.Component {
         });
         return (
           <React.Fragment key={`${contributor.sectionName}-fragment`}>
-            <div className={`row staff-credit-my-10 ${contributor.additionalClass}`} key={`${contributor.sectionName}-row`}>
+            <div className={`row ${contributor.additionalClass}`} key={`${contributor.sectionName}-row`}>
               <h2 className="col-md-12 dev-team mt-5 staff-credit-mb-10" key={contributor.sectionName}>{contributor.sectionName}</h2>
               {memberGroups}
             </div>
@@ -106,7 +113,7 @@ export default class StaffCredit extends React.Component {
         );
       });
       return (
-        <div className="text-center" onClick={this.deleteCredit}>
+        <div className="text-center staff-credit-pb-10" onClick={this.deleteCredit}>
           <h1 className="staff-credit-mb-10">GROWI Contributors</h1>
           <div className="clearfix"></div>
           {credit}

+ 32 - 10
src/client/js/nologin.jsx

@@ -1,9 +1,12 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
+import { Provider } from 'unstated';
 import { I18nextProvider } from 'react-i18next';
 
 import i18nFactory from './util/i18n';
 
+import AppContainer from './services/AppContainer';
+
 import InstallerForm from './components/InstallerForm';
 import LoginForm from './components/LoginForm';
 
@@ -27,22 +30,41 @@ if (installerFormElem) {
 // render loginForm
 const loginFormElem = document.getElementById('login-form');
 if (loginFormElem) {
-  const isRegistering = loginFormElem.dataset.isRegistering === 'true';
+  const appContainer = new AppContainer();
+
   const username = loginFormElem.dataset.username;
   const name = loginFormElem.dataset.name;
   const email = loginFormElem.dataset.email;
-  // [TODO][GW-1913] An AppContainer gets csrf data
-  const csrf = loginFormElem.dataset.csrf;
+  const isRegistrationEnabled = loginFormElem.dataset.isRegistrationEnabled === 'true';
+  const registrationMode = loginFormElem.dataset.registrationMode;
+  const registrationWhiteList = loginFormElem.dataset.registrationWhiteList.split(',');
+  const isLocalStrategySetup = loginFormElem.dataset.isLocalStrategySetup === 'true';
+  const isLdapStrategySetup = loginFormElem.dataset.isLdapStrategySetup === 'true';
+  const objOfIsExternalAuthEnableds = {
+    google: loginFormElem.dataset.isGoogleAuthEnabled === 'true',
+    github: loginFormElem.dataset.isGithubAuthEnabled === 'true',
+    facebook: loginFormElem.dataset.isFacebookAuthEnabled === 'true',
+    twitter: loginFormElem.dataset.isTwitterAuthEnabled === 'true',
+    saml: loginFormElem.dataset.isSamlAuthEnabled === 'true',
+    oidc: loginFormElem.dataset.isOidcAuthEnabled === 'true',
+    basic: loginFormElem.dataset.isBasicAuthEnabled === 'true',
+  };
 
   ReactDOM.render(
     <I18nextProvider i18n={i18n}>
-      <LoginForm
-        isRegistering={isRegistering}
-        username={username}
-        name={name}
-        email={email}
-        csrf={csrf}
-      />
+      <Provider inject={[appContainer]}>
+        <LoginForm
+          username={username}
+          name={name}
+          email={email}
+          isRegistrationEnabled={isRegistrationEnabled}
+          registrationMode={registrationMode}
+          registrationWhiteList={registrationWhiteList}
+          isLocalStrategySetup={isLocalStrategySetup}
+          isLdapStrategySetup={isLdapStrategySetup}
+          objOfIsExternalAuthEnableds={objOfIsExternalAuthEnableds}
+        />
+      </Provider>
     </I18nextProvider>,
     loginFormElem,
   );

+ 18 - 10
src/client/styles/scss/_layout_kibela.scss

@@ -1,4 +1,11 @@
+$navbar-height-adjustment: 10px;
+
 body.kibela {
+  /* navbar for kibela */
+  #page-wrapper {
+    margin-top: 60px;
+  }
+
   /* Logo */
   .logo {
     .logo-mark {
@@ -40,13 +47,13 @@ body.kibela {
 
   .kibela-block {
     position: relative;
-    top: 20px;
+    top: 10px;
     right: 100px;
     bottom: 0px;
     left: 0px;
     z-index: absolute;
-    max-width: 840px;
-    height: 8em;
+    max-width: 1024px;
+    min-height: 8em;
     margin: auto;
     border-radius: 0.35em;
   }
@@ -59,6 +66,10 @@ body.kibela {
       display: none;
     }
 
+    &.grw-subnav-user-page {
+      min-height: 128px;
+    }
+
     @media screen and (max-width: 765px) {
       padding-top: 30px;
     }
@@ -119,10 +130,13 @@ body.kibela {
       + 1px //                    .page-editor-footer border-top
       + 60px; //                  .page-editor-footer min-height
 
-    @include expand-editor($header-plus-footer);
+    @include expand-editor($header-plus-footer, $navbar-height-adjustment);
 
     .kibela-block {
+      top: 0px;
       max-width: unset;
+      padding-top: 0px;
+      border: 0px;
     }
 
     .tab-content {
@@ -153,9 +167,3 @@ body.kibela {
     }
   }
 }
-
-.on-edit {
-  .kibela-block {
-    border: 0px;
-  }
-}

+ 2 - 1
src/client/styles/scss/_mixins.scss

@@ -17,7 +17,8 @@
   }
 }
 
-@mixin expand-editor($editor-header-plus-footer) {
+@mixin expand-editor($editor-header-plus-footer, $navbar-height-adjustment: 0px) {
+  $grw-navbar-height: $grw-navbar-height + $navbar-height-adjustment;
   $header-plus-footer: $grw-navbar-height + $editor-header-plus-footer + 2px; // add .main padding-top
 
   $editor-margin: $header-plus-footer //

+ 4 - 0
src/client/styles/scss/_staff_credit.scss

@@ -60,4 +60,8 @@
     @extend .staff-credit-mt-10;
     @extend .staff-credit-mb-10;
   }
+
+  .staff-credit-pb-10 {
+    padding-bottom: 6rem;
+  }
 }

+ 5 - 1
src/client/styles/scss/_wiki.scss

@@ -11,7 +11,11 @@ div.body {
 
 .wiki {
   font-size: 15px;
-  line-height: 1.8em;
+
+  // override line-height except hljs and child of it.
+  :not(pre*) {
+    line-height: 1.8em;
+  }
 
   h1,
   h2,

+ 8 - 3
src/client/styles/scss/theme/_apply-colors-kibela.scss

@@ -20,7 +20,7 @@ body.kibela {
   }
 
   /* kibela block */
-  .kibela-block {
+  .kibela-border-top {
     border-top: solid 0.4em $thickborder;
   }
 
@@ -161,8 +161,13 @@ body.kibela {
 
   /* navbar */
   .grw-navbar {
-    .nav-item > .nav-link:hover {
-      color: $color-link-nabvar-hover;
+    .nav-item > .nav-link {
+      &:hover {
+        color: $color-link-nabvar-hover;
+      }
+      &:focus {
+        color: $color-link-nabvar;
+      }
     }
   }
 

+ 3 - 2
src/server/views/layout-kibela/base/layout.html

@@ -11,11 +11,12 @@
 
   <div class="row body m-0 p-0">
 
-    <div id="main" class="main col-12 kibela-block round-corner border-0 {% if page %}{{ css.grant(page) }}{% endif %}{% block main_css_class %}{% endblock %}">
+    <div id="main" class="main col-12 kibela-block round-corner {% if page %}{{ css.grant(page) }}{% endif %}{% block main_css_class %}{% endblock %}">
       <div class="row grw-subnav d-edit-none">
-        <div class="col-9 px-0 mx-0 kibela-block">
+        <div class="col px-0 mx-0 bg-white kibela-border-top round-corner">
           {% block content_header %} {% endblock %}
         </div>
+        <div class="col-xl-3 col-lg-4"></div>
       </div>
       <!-- /.grw-subnav -->
 

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

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

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

@@ -110,7 +110,7 @@
       <li class="nav-item d-none d-md-block">
         <a class="nav-link create-page" href="#" data-target="#create-page" data-toggle="modal">
           <i class="icon-pencil mr-2"></i>
-          {{ t('New') }}
+          <span>{{ t('New') }}</span>
         </a>
       </li>
       <li class="nav-item d-none d-md-block">

+ 17 - 4
src/server/views/login.html

@@ -104,15 +104,28 @@
           </div>
         </div>
       </div>
-        {% set isRegistrationEnabled = passportService.isLocalStrategySetup && getConfig('crowi', 'security:registrationMode') != 'Closed' %}
 
-      <!-- [TODO][GW-1913] An AppContainer gets csrf data -->
-      <div id="login-form"
+      {% set registrationMode = getConfig('crowi', 'security:registrationMode') %}
+      {% set isRegistrationEnabled = passportService.isLocalStrategySetup && registrationMode != 'Closed' %}
+
+      <div
+        id="login-form"
         data-is-registering="{{ req.query.register or req.body.registerForm or isRegistering }}"
         data-username ="{{ req.body.registerForm.username }}"
         data-name ="{{ req.body.registerForm.name }}"
         data-email ="{{ req.body.registerForm.email }}"
-        data-csrf="{{ csrf() }}"
+        data-is-registration-enabled="{{ isRegistrationEnabled }}"
+        data-registration-mode = "{{ registrationMode }}"
+        data-registration-white-list = "{{ getConfig('crowi', 'security:registrationWhiteList') }}"
+        data-is-local-strategy-setup = "{{ passportService.isLocalStrategySetup }}"
+        data-is-ldap-strategy-setup = "{{ passportService.isLdapStrategySetup}}"
+        data-is-google-auth-enabled = "{{ getConfig('crowi', 'security:passport-google:isEnabled') }}"
+        data-is-github-auth-enabled = "{{ getConfig('crowi', 'security:passport-github:isEnabled') }}"
+        data-is-facebook-auth-enabled = "{{ getConfig('crowi', 'security:passport-facebook:isEnabled') }}"
+        data-is-twitter-auth-enabled = "{{ getConfig('crowi', 'security:passport-twitter:isEnabled') }}"
+        data-is-saml-auth-enabled = "{{ getConfig('crowi', 'security:passport-saml:isEnabled') }}"
+        data-is-oidc-auth-enabled = "{{ getConfig('crowi', 'security:passport-oidc:isEnabled') }}"
+        data-is-basic-auth-enabled = "{{ getConfig('crowi', 'security:passport-basic:isEnabled') }}"
       ></div>
     </div>
   </div>

+ 10 - 11
src/server/views/widget/page_tabs.html

@@ -47,25 +47,24 @@
     Right Tabs
   #}
 
+  {# to place right side #}
+  <div class="mr-auto"></div>
+
   <!-- presentation -->
   {% if not page.isPortal() %}
-    <li class="nav-item ml-md-auto">
+    <li class="nav-item">
       <a href="?presentation=1" class="nav-link toggle-presentation">
-        <i class="icon-film"></i><span class="hidden-xs"> {{ t('Presentation Mode') }}</span>
+        <i class="icon-film"></i><span class="d-none d-md-inline"> {{ t('Presentation Mode') }}</span>
       </a>
     </li>
   {% endif %}
 
   <!-- revision-history -->
-  {% if page.isPortal() %}
-    <li class="nav-item ml-md-auto">
-    {% else %}
-    <li class="nav-item">
-  {% endif %}
-        <a class="nav-link" href="#revision-history" role="tab" data-toggle="tab">
-          <i class="icon-layers"></i><span class="hidden-xs"> {{ t('History') }}</span>
-        </a>
-      </li>
+  <li class="nav-item">
+    <a class="nav-link" href="#revision-history" role="tab" data-toggle="tab">
+      <i class="icon-layers"></i><span class="d-none d-md-inline"> {{ t('History') }}</span>
+    </a>
+  </li>
 
   <!-- icon-options-vertical -->
   {% if !isTrashPage() %}

+ 1 - 1
src/server/views/widget/system-version.html

@@ -1,4 +1,4 @@
-<div class="system-version hidden-xs">
+<div class="system-version d-none d-md-block">
   <span>
     <a href="https://growi.org">GROWI</a> {{ growiVersion() }}
   </span>