Browse Source

Reworked admin maintenance area (needed for restarting screen).

Martin Edenhofer 8 years ago
parent
commit
cb5fd0c2c0

+ 10 - 7
app/assets/javascripts/app/controllers/_settings/area.coffee

@@ -132,10 +132,14 @@ class App.SettingsAreaLogo extends App.Controller
     @render()
     @render()
 
 
   render: ->
   render: ->
-    @html App.view('settings/logo')(
+    localElement = $(App.view('settings/logo')(
       setting: @setting
       setting: @setting
+    ))
+    localElement.find('.js-loginPreview').html( App.view('generic/login_preview')(
       logoUrl: @logoUrl()
       logoUrl: @logoUrl()
-    )
+      logoChange: true
+    ))
+    @html localElement
 
 
   onLogoPick: (event) =>
   onLogoPick: (event) =>
     reader = new FileReader()
     reader = new FileReader()
@@ -146,8 +150,7 @@ class App.SettingsAreaLogo extends App.Controller
     file = event.target.files[0]
     file = event.target.files[0]
 
 
     # if no file is given, about in file upload was used
     # if no file is given, about in file upload was used
-    if !file
-      return
+    return if !file
 
 
     maxSiteInMb = 8
     maxSiteInMb = 8
     if file.size && file.size > 1024 * 1024 * maxSiteInMb
     if file.size && file.size > 1024 * 1024 * maxSiteInMb
@@ -189,9 +192,9 @@ class App.SettingsAreaLogo extends App.Controller
               msg:     App.i18n.translateContent('Update successful!')
               msg:     App.i18n.translateContent('Update successful!')
               timeout: 2000
               timeout: 2000
             }
             }
-
-            for key, value of data.settings
-              App.Config.set( key, value )
+            for setting in data.settings
+              value = App.Setting.get(setting.name)
+              App.Config.set(name, value)
           else
           else
             App.Event.trigger 'notify', {
             App.Event.trigger 'notify', {
               type:    'error'
               type:    'error'

+ 19 - 1
app/assets/javascripts/app/controllers/login.coffee

@@ -21,6 +21,20 @@ class Index extends App.ControllerContent
     @render()
     @render()
     @navupdate '#login'
     @navupdate '#login'
 
 
+    # observe config changes related to login page
+    @bind('config_update_local', (data) =>
+      return if data.name != 'maintenance_mode' &&
+        data.name != 'maintenance_login' &&
+        data.name != 'maintenance_login_message' &&
+        data.name != 'user_lost_password' &&
+        data.name != 'user_create_account' &&
+        data.name != 'product_name' &&
+        data.name != 'product_logo' &&
+        data.name != 'fqdn'
+      @render()
+      'rerender'
+    )
+
   render: (data = {}) ->
   render: (data = {}) ->
     auth_provider_all = {
     auth_provider_all = {
       facebook: {
       facebook: {
@@ -100,11 +114,15 @@ class Index extends App.ControllerContent
       @navigate '#/'
       @navigate '#/'
 
 
   error: (xhr, statusText, error) =>
   error: (xhr, statusText, error) =>
+    detailsRaw = xhr.responseText
+    details = {}
+    if !_.isEmpty(detailsRaw)
+      details = JSON.parse(detailsRaw)
 
 
     # add notify
     # add notify
     @notify
     @notify
       type:      'error'
       type:      'error'
-      msg:       App.i18n.translateContent('Wrong Username and Password combination.')
+      msg:       App.i18n.translateContent(details.error || 'Wrong Username and Password combination.')
       removeAll: true
       removeAll: true
 
 
     # rerender login page
     # rerender login page

+ 54 - 11
app/assets/javascripts/app/controllers/maintenance.coffee

@@ -1,6 +1,13 @@
 class Index extends App.ControllerContent
 class Index extends App.ControllerContent
   events:
   events:
-    'submit form': 'sendMessage'
+    'change .js-modeSetting input': 'setMode'
+    'change .js-loginSetting input': 'setLogin'
+    'blur .js-Login': 'updateMessage'
+    'submit .js-Message': 'sendMessage'
+
+  elements:
+    '.js-modeSetting input': 'modeSetting'
+    '.js-loginSetting input': 'loginSetting'
 
 
   constructor: ->
   constructor: ->
     super
     super
@@ -10,20 +17,56 @@ class Index extends App.ControllerContent
 
 
     @title 'Maintenance', true
     @title 'Maintenance', true
 
 
-    @render()
+    @subscribeId = App.Setting.subscribe(@render, initFetch: true, clear: false)
+
+  release: =>
+    App.Setting.unsubscribe(@subscribeId)
+
+  render: =>
+    localElement = $(App.view('maintenance')())
+    localElement.find('.js-loginPreview').html( App.view('generic/login_preview')(
+      logoUrl: @logoUrl()
+    ))
+
+    localElement.find('.js-textarea').ce({
+      mode:      'richtext'
+      multiline: true
+      maxlength: 20000
+    })
+
+    @html localElement
+
+  setMode: (e) =>
+    value = @modeSetting.prop('checked')
+    return if value && !confirm('Sure?')
+    App.Setting.set('maintenance_mode', value)
+    App.WebSocket.send(
+      event:'maintenance'
+      data:
+        type: 'mode'
+        on: value
+    )
+
+  setLogin: (e) =>
+    value = @loginSetting.prop('checked')
+    App.Setting.set('maintenance_login', value)
 
 
-  render: ->
-    @html App.view('maintenance')()
+  updateMessage: (e) =>
+    e.preventDefault()
+    params = @formParam(e.target)
+    App.Setting.set('maintenance_login_message', params.message)
+    @notify
+      type:      'success'
+      msg:       App.i18n.translateContent('Update successful!')
+      removeAll: true
 
 
   sendMessage: (e) ->
   sendMessage: (e) ->
     e.preventDefault()
     e.preventDefault()
     params = @formParam(e.target)
     params = @formParam(e.target)
-    App.Event.trigger(
-      'ws:send'
-        event: 'broadcast'
-        data:
-          event: 'session:maintenance'
-          data:  params
+    params.type = 'message'
+    App.WebSocket.send(
+      event:'maintenance'
+      data: params
     )
     )
     @notify
     @notify
       type:      'success'
       type:      'success'
@@ -31,4 +74,4 @@ class Index extends App.ControllerContent
       removeAll: true
       removeAll: true
     @render()
     @render()
 
 
-App.Config.set( 'Maintenance', { prio: 3600, name: 'Maintenance', parent: '#system', target: '#system/maintenance', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
+App.Config.set('Maintenance', { prio: 3600, name: 'Maintenance', parent: '#system', target: '#system/maintenance', controller: Index, role: ['Admin'] }, 'NavBarAdmin')

+ 8 - 5
app/assets/javascripts/app/controllers/signup.coffee

@@ -81,18 +81,21 @@ class Index extends App.ControllerContent
     # add notify
     # add notify
     @notify
     @notify
       type:      'success'
       type:      'success'
-      msg:       'Thanks for joining. Email sent to "' + @params.email + '". Please verify your email address.'
+      msg:       App.i18n.translateContent('Thanks for joining. Email sent to "%s". Please verify your email address.', @params.email)
       removeAll: true
       removeAll: true
 
 
     # redirect to #
     # redirect to #
     @navigate '#'
     @navigate '#'
 
 
   error: (xhr, statusText, error) =>
   error: (xhr, statusText, error) =>
+    detailsRaw = xhr.responseText
+    details = {}
+    if !_.isEmpty(detailsRaw)
+      details = JSON.parse(detailsRaw)
 
 
-    # add notify
     @notify
     @notify
-      type:      'warning'
-      msg:       'Wrong Username and Password combination.'
+      type:      'error'
+      msg:       App.i18n.translateContent(details.error || 'Wrong Username and Password combination.')
       removeAll: true
       removeAll: true
 
 
-App.Config.set( 'signup', Index, 'Routes' )
+App.Config.set('signup', Index, 'Routes')

+ 12 - 0
app/assets/javascripts/app/controllers/widget/app_config_update.coffee

@@ -0,0 +1,12 @@
+class Widget extends App.Controller
+  constructor: ->
+    super
+
+    App.Event.bind(
+      'config_update'
+      (data) ->
+        App.Config.set(data.name, data.value)
+        App.Event.trigger('config_update_local', data)
+    )
+
+App.Config.set('app_config_update', Widget, 'Widgets')

+ 0 - 33
app/assets/javascripts/app/controllers/widget/app_version.coffee

@@ -1,33 +0,0 @@
-class Widget extends App.Controller
-  constructor: ->
-    super
-
-    App.Event.bind(
-      'app_version'
-      (data) =>
-        @render(data)
-      'app_version'
-    )
-
-  render: (data) =>
-    return if @message
-    return if @appVersion is data.app_version
-    if !@appVersion
-      @appVersion = data.app_version
-      return
-    @appVersion = data.app_version
-    localAppVersion = @appVersion.split(':')
-    return if localAppVersion[1] isnt 'true'
-    message = =>
-      @message = new App.SessionMessage(
-        head:         'New Version'
-        message:      'A new version of Zammad is available, please reload your browser.'
-        keyboard:     false
-        backdrop:     true
-        buttonClose:  false
-        buttonSubmit: 'Continue session'
-        forceReload:  true
-      )
-    @delay(message, 2000)
-
-App.Config.set('app_version', Widget, 'Widgets')

+ 70 - 7
app/assets/javascripts/app/controllers/widget/maintenance.coffee

@@ -2,11 +2,19 @@ class Widget extends App.Controller
   constructor: ->
   constructor: ->
     super
     super
 
 
-    # bind on event to show message
     App.Event.bind(
     App.Event.bind(
-      'session:maintenance'
+      'maintenance'
       (data) =>
       (data) =>
-        @showMessage(data)
+        if data.type is 'message'
+          @showMessage(data)
+        if data.type is 'mode'
+          @maintanaceMode(data)
+        if data.type is 'app_version'
+          @maintanaceAppVersion(data)
+        if data.type is 'config_changed'
+          @maintanaceConfigChanged(data)
+        if data.type is 'restart'
+          @maintanaceRestart(data)
       'maintenance'
       'maintenance'
     )
     )
 
 
@@ -17,13 +25,10 @@ class Widget extends App.Controller
     else
     else
       button = 'Close'
       button = 'Close'
 
 
-    # convert to html and linkify
-    message.message = App.Utils.textCleanup(message.message)
-    message.message = App.Utils.text2html(message.message)
-
     new App.SessionMessage(
     new App.SessionMessage(
       head:          message.head
       head:          message.head
       contentInline: message.message
       contentInline: message.message
+      small:         true
       keyboard:      true
       keyboard:      true
       backdrop:      true
       backdrop:      true
       buttonClose:   true
       buttonClose:   true
@@ -31,4 +36,62 @@ class Widget extends App.Controller
       forceReload:   message.reload
       forceReload:   message.reload
     )
     )
 
 
+  maintanaceMode: (data = {}) =>
+    return if data.on isnt true
+    return if !@authenticate(true)
+    @navigate '#logout'
+
+  #App.Event.trigger('maintenance', {type:'restart'})
+  maintanaceRestart: (data) =>
+    return if @messageRestart
+    @messageRestart = new App.SessionMessage(
+      head:         'Restarting...'
+      message:      'Zammad is restarting... waiting...'
+      keyboard:     false
+      backdrop:     false
+      buttonClose:  false
+      buttonSubmit: false
+      small:        true
+      forceReload:  true
+    )
+
+    # disconnect
+
+    # try if backend is reachable again
+
+    # reload app
+
+  maintanaceConfigChanged: (data) =>
+    return if @messageConfigChanged
+    @messageConfigChanged = new App.SessionMessage(
+      head:         'Config has changed'
+      message:      'The configuration of Zammad has changed, please reload your browser.'
+      keyboard:     false
+      backdrop:     true
+      buttonClose:  false
+      buttonSubmit: 'Continue session'
+      forceReload:  true
+    )
+
+  maintanaceAppVersion: (data) =>
+    return if @messageAppVersion
+    return if @appVersion is data.app_version
+    if !@appVersion
+      @appVersion = data.app_version
+      return
+    @appVersion = data.app_version
+    localAppVersion = @appVersion.split(':')
+    return if localAppVersion[1] isnt 'true'
+    message = =>
+      @messageAppVersion = new App.SessionMessage(
+        head:         'New Version'
+        message:      'A new version of Zammad is available, please reload your browser.'
+        keyboard:     false
+        backdrop:     true
+        buttonClose:  false
+        buttonSubmit: 'Continue session'
+        forceReload:  true
+      )
+    @delay(message, 2000)
+
 App.Config.set('maintenance', Widget, 'Widgets')
 App.Config.set('maintenance', Widget, 'Widgets')

+ 1 - 1
app/assets/javascripts/app/models/setting.coffee

@@ -27,8 +27,8 @@ class App.Setting extends App.Model
           msg:     App.i18n.translateContent(details.error_human || details.error || 'Unable to update object!')
           msg:     App.i18n.translateContent(details.error_human || details.error || 'Unable to update object!')
           timeout: 2000
           timeout: 2000
         }
         }
-    setting.save(options)
     App.Config.set(name, value)
     App.Config.set(name, value)
+    setting.save(options)
 
 
   @preferencesPost: (setting) ->
   @preferencesPost: (setting) ->
     return if !setting.preferences
     return if !setting.preferences

+ 43 - 0
app/assets/javascripts/app/views/generic/login_preview.jst.eco

@@ -0,0 +1,43 @@
+<div class="login branding centered darkBackground vertical">
+
+  <% if @C('maintenance_mode'): %>
+    <div class="hero-unit alert alert--danger"><%- @T('Zammad is currently in maintenance mode. Only administrators can login. Please wait until the maintenance window is over.') %></div>
+  <% end %>
+
+  <% if !@logoChange || @C('maintenance_login'): %>
+  <form>
+    <div contenteditable id="maintenance-message" data-name="message" class="hero-unit alert alert--success js-textarea js-Login" <% if !@C('maintenance_login'): %>style="opacity: 0.5;"<% end %>><%- @C('maintenance_login_message') %></div>
+  </form>
+  <% end %>
+
+  <div class="hero-unit">
+
+    <% if @logoChange: %>
+      <img class="logo-preview" src="<%= @logoUrl %>">
+      <div class="logo-preview-placeholder"><%- @T('Your Logo') %></div>
+      <div class="centered">
+        <div class="btn btn--success fileUpload"><%- @T('Change') %><input type="file" class="js-upload" name="logo" accept="image/*"></div>
+      </div>
+    <% else: %>
+      <img class="company-logo" src="<%= @logoUrl %>">
+    <% end %>
+
+    <div class="form-group">
+      <label for="username"><%- @Ti('Username / email') %></label>
+      <input id="username" name="username" type="text" class="form-control" value="<%= @S('login') %>" autocapitalize="off" disabled="disabled"/>
+    </div>
+
+    <div class="form-group">
+      <label for="password"><%- @Ti('Password') %></label>
+      <input id="password" name="password" type="password" class="form-control" value="some_pass" disabled="disabled"/>
+    </div>
+
+    <div class="form-group">
+      <label><input name="remember_me" value="1" type="checkbox" disabled="disabled"/> <%- @T('Remember me') %></label>
+    </div>
+
+    <div class="form-controls">
+      <button class="btn btn--primary" type="submit" disabled="disabled"><%- @T('Sign in') %></button>
+    </div>
+  </div>
+</div>

+ 22 - 15
app/assets/javascripts/app/views/login.jst.eco

@@ -1,56 +1,63 @@
 <div class="login fullscreen">
 <div class="login fullscreen">
   <div class="fullscreen-center">
   <div class="fullscreen-center">
     <div class="fullscreen-body">
     <div class="fullscreen-body">
-      <p><%- @T( 'Login with %s', @C( 'fqdn' ) ) %></p>
+      <p><%- @T('Login with %s', @C('fqdn')) %></p>
+
+      <% if @C('maintenance_mode'): %>
+        <div class="hero-unit alert alert--danger js-maintenanceMode"><%- @T('Zammad is currently in maintenance mode. Only administrators can login. Please wait until the maintenance window is over.') %></div>
+      <% end %>
+      <% if @C('maintenance_login') && @C('maintenance_login_message'): %>
+        <div class="hero-unit alert alert--success js-maintenanceLogin"><%- @C('maintenance_login_message') %></div>
+      <% end %>
 
 
       <div class="hero-unit">
       <div class="hero-unit">
-        <img class="company-logo" src="<%= @logoUrl %>" alt="<%= @C( 'product_name' ) %>">
+        <img class="company-logo" src="<%= @logoUrl %>" alt="<%= @C('product_name') %>">
         <form id="login">
         <form id="login">
           <div class="form-group">
           <div class="form-group">
             <div class="formGroup-label">
             <div class="formGroup-label">
-              <label for="username"><%- @Ti( 'Username / email' ) %></label>
+              <label for="username"><%- @Ti('Username / email') %></label>
             </div>
             </div>
             <input id="username" name="username" type="text" class="form-control" value="<%= @item.username %>" autocapitalize="off" />
             <input id="username" name="username" type="text" class="form-control" value="<%= @item.username %>" autocapitalize="off" />
           </div>
           </div>
 
 
           <div class="form-group">
           <div class="form-group">
             <div class="formGroup-label">
             <div class="formGroup-label">
-              <label for="password"><%- @Ti( 'Password' ) %></label>
+              <label for="password"><%- @Ti('Password') %></label>
             </div>
             </div>
             <input id="password" name="password" type="password" class="form-control"/>
             <input id="password" name="password" type="password" class="form-control"/>
           </div>
           </div>
 
 
           <div class="form-group">
           <div class="form-group">
     <!--
     <!--
-            <label for="remember_me"><%- @Ti( 'Remember me' ) %></label>
+            <label for="remember_me"><%- @Ti('Remember me') %></label>
             <input id="remember_me" name="remember_me" value="1" type="checkbox"/>
             <input id="remember_me" name="remember_me" value="1" type="checkbox"/>
     -->
     -->
             <label class="inline-label checkbox-replacement">
             <label class="inline-label checkbox-replacement">
               <input name="remember_me" value="1" type="checkbox">
               <input name="remember_me" value="1" type="checkbox">
               <%- @Icon('checkbox', 'icon-unchecked') %>
               <%- @Icon('checkbox', 'icon-unchecked') %>
               <%- @Icon('checkbox-checked', 'icon-checked') %>
               <%- @Icon('checkbox-checked', 'icon-checked') %>
-              <span class="label-text"><%- @T( 'Remember me' ) %></span>
+              <span class="label-text"><%- @T('Remember me') %></span>
             </label>
             </label>
           </div>
           </div>
 
 
           <div class="form-controls">
           <div class="form-controls">
-            <button class="btn btn--primary" type="submit"><%- @T( 'Sign in' ) %></button>
+            <button class="btn btn--primary" type="submit"><%- @T('Sign in') %></button>
 
 
             <% if @C('user_lost_password'): %>
             <% if @C('user_lost_password'): %>
-              <a href="#password_reset" class="btn btn--text btn--secondary align-right"><%- @T( 'Forgot password?' ) %></a>
+              <a href="#password_reset" class="btn btn--text btn--secondary align-right"><%- @T('Forgot password?') %></a>
             <% end %>
             <% end %>
           </div>
           </div>
 
 
-          <% if !_.isEmpty( @auth_providers ): %>
+          <% if !_.isEmpty(@auth_providers): %>
           <div class="separator">
           <div class="separator">
-            <span class="separator-text"><%- @T( 'or sign in using' ) %></span>
+            <span class="separator-text"><%- @T('or sign in using') %></span>
           </div>
           </div>
 
 
           <div class="auth-providers">
           <div class="auth-providers">
             <% for auth_provider in @auth_providers: %>
             <% for auth_provider in @auth_providers: %>
               <a class="auth-provider auth-provider--<%= auth_provider.class %>" href="<%= auth_provider.url %>">
               <a class="auth-provider auth-provider--<%= auth_provider.class %>" href="<%= auth_provider.url %>">
                 <%- @Icon("#{auth_provider.class}-button", 'provider-icon') %>
                 <%- @Icon("#{auth_provider.class}-button", 'provider-icon') %>
-                <span class="provider-name"><%- @T( auth_provider.name ) %></span>
+                <span class="provider-name"><%- @T(auth_provider.name) %></span>
               </a>
               </a>
             <% end %>
             <% end %>
           </div>
           </div>
@@ -59,23 +66,23 @@
       </div>
       </div>
 
 
       <p>
       <p>
-        <%- @T( "You're already registered with your email adress if you've been in touch with our support team.") %><br>
+        <%- @T("You're already registered with your email adress if you've been in touch with our support team.") %><br>
         <% if @C('user_lost_password'): %>
         <% if @C('user_lost_password'): %>
-          <%- @T( "You can request your password") %> <a href="#password_reset"><%- @T( "here") %></a>.
+          <%- @T('You can request your password') %> <a href="#password_reset"><%- @T('here') %></a>.
         <% end %>
         <% end %>
       </p>
       </p>
 
 
     <% if @C('user_create_account'): %>
     <% if @C('user_create_account'): %>
       <hr>
       <hr>
       <p>
       <p>
-        <a href="#signup"><%- @T( 'Register as a new customer' ) %></a>
+        <a href="#signup"><%- @T('Register as a new customer') %></a>
       </p>
       </p>
     <% end %>
     <% end %>
     </div>
     </div>
   </div>
   </div>
   <div class="poweredBy">
   <div class="poweredBy">
     <%- @Icon('logo') %>
     <%- @Icon('logo') %>
-    <%- @T("Powered by") %>
+    <%- @T('Powered by') %>
     <%- @Icon('logotype', 'logotype') %>
     <%- @Icon('logotype', 'logotype') %>
   </div>
   </div>
 </div>
 </div>

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