Bläddra i källkod

HUE-8926 [frontend] Move the user menu to the left sidebar

Johan Ahlen 6 år sedan
förälder
incheckning
82c5ccf669

+ 1 - 0
desktop/core/src/desktop/js/ko/bindings/ko.hueAppIcon.js

@@ -55,6 +55,7 @@ const APP_ICON_INDEX = {
   spark: `<svg class="hi hi-fw"><use xlink:href="#hi-spark"></use></svg>`,
   sqoop1: `<svg class="hi hi-fw"><use xlink:href="#hi-sqoop"></use></svg>`,
   sqoop: `<svg class="hi hi-fw"><use xlink:href="#hi-sqoop"></use></svg>`,
+  support: `<svg class="hi hi-fw"><use xlink:href="#hi-support"></use></svg>`,
   tables: `<i class="fa fa-fw fa-table"></i>`,
   text: `<i class="fa fa-fw fa-i-cursor"></i>`,
   warehouses: `<i class="altus-icon altus-adb-cluster" style="margin: 0 1px 0 3px"></i>`,

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 13
desktop/core/src/desktop/js/ko/components/appSwitcher/apps.v2.json


+ 126 - 8
desktop/core/src/desktop/js/ko/components/ko.sidebar.js

@@ -23,10 +23,77 @@ import huePubSub from 'utils/huePubSub';
 import I18n from 'utils/i18n';
 
 const TEMPLATE = `
+  <script type="text/html" id="sidebar-inner-item">
+    <!-- ko if: iconHtml -->
+    <div class="icon" data-bind="html: iconHtml"></div><span data-bind="text: displayName"></span>
+    <!-- /ko -->
+    <!-- ko ifnot: iconHtml -->
+    <div class="icon" data-bind="hueAppIcon: icon"></div><span data-bind="text: displayName"></span>
+    <!-- /ko -->
+  </script>
+
   <script type="text/html" id="sidebar-item">
-    <div class="item-wrapper"><a href="javascript: void(0);" data-bind="hueLink: item.url, publish: 'hue.sidebar.update.active', attr: { 'aria-label': item.displayName, 'data-tooltip': item.displayName }, css: { 'active': item.active }" class="item">
-      <div class="icon" data-bind="hueAppIcon: item.icon"></div><span data-bind="text: item.displayName"></span>
-    </a></div>
+    <div class="item-wrapper" data-bind="css: itemClass">
+      <!-- ko if: click -->
+      <a href="javascript: void(0);" data-bind="click: click, attr: { 'aria-label': displayName, 'data-tooltip': displayName }, css: { 'active': active }" class="item">
+        <!-- ko template: 'sidebar-inner-item' --><!-- /ko -->
+      </a>
+      <!-- /ko -->
+      <!-- ko ifnot: click -->
+      <a href="javascript: void(0);" data-bind="hueLink: url, publish: 'hue.sidebar.update.active', attr: { 'aria-label': displayName, 'data-tooltip': displayName }, css: { 'active': active }" class="item">
+        <!-- ko template: 'sidebar-inner-item' --><!-- /ko -->
+      </a>
+      <!-- /ko -->
+      <!-- ko if: subMenuTemplate -->
+      <!-- ko template: subMenuTemplate --><!-- /ko -->
+      <!-- /ko -->
+    </div>
+  </script>
+  
+  <script type="text/html" id="user-sub-menu-template">
+    <div class="sidebar-menu user-menu" data-bind="css: { 'open' : $component.userMenuOpen }">
+      <div class="menu">
+        <div class="menu-header">
+          <div class="user-icon" style="background-color: #fff">${window.LOGGED_USERNAME[0].toUpperCase()}</div>
+          <div>
+            <div>${window.LOGGED_USERNAME}</div>
+          </div>
+        </div>
+        <ul class="sidebar-nav-list">
+          <!-- ko if: window.USER_VIEW_EDIT_USER_ENABLED -->
+          <li><a href="javascript:void(0);" data-bind="hueLink: '/useradmin/users/edit/${
+            window.LOGGED_USERNAME
+          }', attr: { 'title': window.IS_LDAP_SETUP ? ${I18n('View Profile')} : ${I18n(
+  'Edit Profile'
+)}">${I18n('My Profile')}</a></li>
+          <!-- /ko -->
+          <!-- ko if: window.USER_IS_ADMIN -->
+          <li><a href="javascript: void(0);" data-bind="hueLink: '/useradmin/users/'">${I18n(
+            'Manage Users'
+          )}</a></li>
+          <li><a href="javascript: void(0);" data-bind="hueLink: '/about/'">${I18n(
+            'Administration'
+          )}</a></li>
+          <!-- /ko -->
+          <li><a href="javascript: void(0);" data-bind="hueLink: '/accounts/logout'" title="${I18n(
+            'Sign out'
+          )}" >${I18n('Sign out')}</a></li>
+        </ul>
+      </div>
+    </div>
+  </script>
+  
+  <script type="text/html" id="support-sub-menu-template">
+    <div class="sidebar-menu support-menu" data-bind="css: { 'open' : $component.supportMenuOpen }">
+      <div class="menu">
+        <ul class="sidebar-nav-list">
+          <li><a href="javascript:void(0)" data-bind="publish: 'show.welcome.tour'">${I18n(
+            'Welcome Tour'
+          )}</a></li>
+          <li><a href="http://gethue.com" target="_blank">${I18n('Help')}</a></li>
+        </ul>
+      </div>
+    </div>
   </script>
 
   <!-- ko if: window.DISPLAY_APP_SWITCHER -->
@@ -40,19 +107,22 @@ const TEMPLATE = `
   </div>
   <!-- /ko -->
   <div class="hue-sidebar-body">
-    <!-- ko foreach: {data: items, as: 'item'} -->
-      <!-- ko if: item.isCategory -->
+    <!-- ko foreach: items -->
+      <!-- ko if: isCategory -->
         <!-- ko ifnot: $index() === 0 -->
         <div class="item-spacer"></div>
         <!-- /ko -->
-        <!-- ko template: {name: 'sidebar-item', foreach: item.children, as: 'item'} --><!-- /ko -->
+        <!-- ko template: {name: 'sidebar-item', foreach: children } --><!-- /ko -->
       <!-- /ko -->
-      <!-- ko ifnot: item.isCategory -->
+      <!-- ko ifnot: isCategory -->
         <!-- ko template: { name: 'sidebar-item' } --><!-- /ko -->
       <!-- /ko -->
     <!-- /ko -->
   </div>
   <div class="hue-sidebar-footer">
+    <!-- ko foreach: footerItems -->
+    <!-- ko template: { name: 'sidebar-item' } --><!-- /ko -->
+    <!-- /ko -->
     <a class="hue-sidebar-trigger" data-bind="toggle: collapsed">
       <svg><use xlink:href="#hi-collapse-nav"></use></svg>
     </a>
@@ -68,8 +138,11 @@ class SidebarItem {
     this.children = options.children;
     this.name = options.name;
     this.type = options.type;
-
     this.active = ko.observable(false);
+    this.click = options.click;
+    this.subMenuTemplate = options.subMenuTemplate;
+    this.iconHtml = options.iconHtml;
+    this.itemClass = options.itemClass;
   }
 }
 
@@ -78,6 +151,34 @@ class Sidebar {
     this.$element = $(element);
 
     this.collapsed = ko.observable();
+    this.userMenuOpen = ko.observable(false);
+    this.supportMenuOpen = ko.observable(false);
+
+    this.userMenuOpen.subscribe(newVal => {
+      if (newVal) {
+        window.setTimeout(() => {
+          $(document).on('click.userMenu', () => {
+            this.userMenuOpen(false);
+          });
+        }, 0);
+        this.supportMenuOpen(false);
+      } else {
+        $(document).off('click.userMenu');
+      }
+    });
+
+    this.supportMenuOpen.subscribe(newVal => {
+      if (newVal) {
+        window.setTimeout(() => {
+          $(document).on('click.supportMenu', () => {
+            this.supportMenuOpen(false);
+          });
+        }, 0);
+        this.userMenuOpen(false);
+      } else {
+        $(document).off('click.supportMenu');
+      }
+    });
 
     this.collapsed.subscribe(newVal => {
       if (newVal) {
@@ -90,9 +191,26 @@ class Sidebar {
     apiHelper.withTotalStorage('hue.sidebar', 'collabse', this.collapsed, true);
 
     this.items = ko.observableArray();
+    this.footerItems = [
+      new SidebarItem({
+        displayName: 'Support',
+        icon: 'support',
+        click: () => this.supportMenuOpen(!this.supportMenuOpen()),
+        subMenuTemplate: 'support-sub-menu-template'
+      }),
+      new SidebarItem({
+        displayName: window.LOGGED_USERNAME,
+        itemClass: 'shepherd-user-menu',
+        iconHtml: '<div class="user-icon">' + window.LOGGED_USERNAME[0].toUpperCase() + '</div>',
+        click: () => this.userMenuOpen(!this.userMenuOpen()),
+        subMenuTemplate: 'user-sub-menu-template'
+      })
+    ];
     this.lastAppName = undefined;
 
     const updateActive = () => {
+      this.userMenuOpen(false);
+      this.supportMenuOpen(false);
       this.items().forEach(item => {
         item.children.forEach(child => {
           let active = false;

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue-embedded.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue.css


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue3-extra.css


+ 97 - 59
desktop/core/src/desktop/static/desktop/less/components/hue-sidebar.less

@@ -21,11 +21,11 @@
 @gradient-start: @cui-gray-800;
 @header-bg-open: @hue-primary-color-dark;
 @header-bg: @hue-primary-color-dark;
-@help-drawer-width: 400px;
+@default-drawer-width: 400px;
 @item-active-border: @hue-primary-color-dark;
 @item-color: rgb(173, 178, 182);
 @sidebar-background-color: #333e45;
-@sidebar-collapsed-item-height: 42px;
+@sidebar-collapsed-item-height: 35px;
 @sidebar-collapsed-icon-height: 22px;
 @sidebar-icon-height: 20px;
 @sidebar-collapsed-width: 56px;
@@ -49,6 +49,9 @@
   overflow: hidden;
   transition: all @animation-duration-base;
 
+  .hi {
+    margin-bottom: 0;
+  }
 
   * {
     -webkit-font-smoothing: antialiased;
@@ -217,8 +220,7 @@
       .flex-box-pack(end);
 
       justify-content: flex-end;
-      margin-top: 12px;
-      height: 52px;
+      height: 50px;
       padding: 0 16px;
 
       svg {
@@ -243,7 +245,12 @@
     align-items: center;
     justify-content: center;
     color: @sidebar-background-color;
+    background-color: @item-color;
     text-transform: uppercase;
+
+    &:hover {
+      background-color: @cui-white;
+    }
   }
 
   &.collapsed {
@@ -347,77 +354,108 @@
     height: 15px;
   }
 
-  .hue-drawer.help-drawer {
-    left: -@help-drawer-width;
-    width: @help-drawer-width;
+  &:not(.collapsed) .sidebar-menu {
+    left: @sidebar-width + 8px;
+  }
+
+  &.collapsed .sidebar-menu {
+    left: @sidebar-collapsed-width + 8px;
+  }
+
+  .sidebar-menu {
+    z-index: 1010;
+    display: none;
+    position: fixed;
+    background-color: @cui-gray-800;
+    color: @cui-white;
+    font-size: 14px;
+    border-radius: 3px;
+    box-shadow: rgba(0, 0, 0, 0.2) 0 2px 4px 0;
+    white-space: nowrap;
+    padding: 4px 8px;
+    top: auto;
+    height: auto;
+    bottom: 20px;
+    transition: none;
+
+    &.open {
+      display: block;
+    }
+
+    &.support-menu {
+      bottom: 38px;
+    }
 
     .menu {
       display: flex;
       height: 100%;
       flex-direction: column;
-    }
 
-    .menu-header {
-      height: @sidebar-header-height;
-      border-bottom: 1px solid @cui-gray-100;
-      display: flex;
-      align-items: center;
-      justify-content: space-between;
-      flex-shrink: 0;
-      padding: 0 24px;
+      .menu-header {
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        padding: 10px 16px 20px 16px;
+
+        .user-icon {
+          width: 36px;
+          height: 36px;
+          margin-right: 12px;
+          font-size: 22px;
+          flex-shrink: 0;
+        }
 
-      img {
-        height: 20px;
-        width: 20px;
+        > div {
+          text-overflow: ellipsis;
+          white-space: nowrap;
+          overflow: hidden;
+        }
+
+        small {
+          font-size: 12px;
+        }
       }
-    }
 
-    .menu-body {
-      padding: 24px;
-      border-bottom: 1px solid @cui-gray-100;
-      flex-grow: 1;
-      min-height: 0;
-      overflow: auto;
-    }
+      ul.sidebar-nav-list {
+        list-style: none;
+        margin: 4px 0;
+        padding: 0;
 
-    .menu-footer {
-      flex-shrink: 0;
+        li {
+          margin-left: -8px;
+          margin-right: -8px;
+        }
 
-      h2 {
-        padding: 24px 24px 0 24px;
+        li a {
+          height: 32px;
+          display: flex;
+          align-items: center;
+          color: @cui-white;
+          padding: 0 24px;
+
+          &:hover {
+            background-color: @hue-primary-color-dark;
+          }
+
+          svg {
+            margin-left: 8px;
+            font-size: 16px;
+          }
+        }
       }
-    }
-  }
 
-  // User Drawer
-  .hue-drawer.user-drawer {
-    top: auto;
-    height: auto;
-    bottom: 20px;
-    transition: none;
-
-    .menu-header {
-      display: flex;
-      flex-direction: row;
-      align-items: center;
-      padding: 10px 16px 20px 16px;
-
-      .user-icon {
-        width: 36px;
-        height: 36px;
-        margin-right: 12px;
-        font-size: 22px;
-        flex-shrink: 0;
+      .menu-body {
+        flex-grow: 1;
+        min-height: 0;
+        overflow: auto;
       }
 
-      > div {
-        text-overflow: ellipsis;
-        white-space: nowrap;
-        overflow: hidden;
-      }
+      .menu-footer {
+        flex-shrink: 0;
 
-      small {
-        font-size: 12px;
+        h2 {
+          padding: 24px 24px 0 24px;
+        }
       }
     }
   }

+ 12 - 0
desktop/core/src/desktop/templates/global_js_constants.mako

@@ -18,6 +18,7 @@
   from django.utils.translation import ugettext as _
 
   from desktop import conf
+  from desktop.auth.backend import is_admin;
   from desktop.conf import APP_SWITCHER_ALTUS_BASE_URL, APP_SWITCHER_MOW_BASE_URL, DISPLAY_APP_SWITCHER, IS_EMBEDDED, IS_K8S_ONLY, IS_MULTICLUSTER_ONLY, USE_NEW_SIDE_PANELS, VCS
   from desktop.models import hue_version, _get_apps, get_cluster_config
 
@@ -140,6 +141,7 @@
     'Add tags...': '${ _('Add tags...') }',
     'Add': '${ _('Add') }',
     'Admin': '${ _('Admin') }',
+    'Administration': '${ _('Administration') }',
     'aggregate': '${ _('aggregate') }',
     'Aggregate': '${ _('Aggregate') }',
     'alias': '${ _('alias') }',
@@ -211,6 +213,7 @@
     'Documents': '${ _('Documents') }',
     'Drop a SQL file here': '${_('Drop a SQL file here')}',
     'Drop iPython/Zeppelin notebooks here': '${_('Drop iPython/Zeppelin notebooks here')}',
+    'Edit Profile': '${ _('Edit Profile') }',
     'Edit tags': '${ _('Edit tags') }',
     'Edit this privilege': '${ _('Edit this privilege') }',
     'Edit': '${ _('Edit') }',
@@ -253,6 +256,7 @@
     'Go to column:': '${_('Go to column:')}',
     'group by': '${ _('group by') }',
     'Heatmap': '${ _('Heatmap') }',
+    'Help': '${ _('Help') }',
     'Hide advanced': '${_('Hide advanced')}',
     'Hive Query': '${_('Hive Query')}',
     'Identifiers': '${ _('Identifiers') }',
@@ -281,6 +285,7 @@
     'Loading metrics...': '${ _('Loading metrics...') }',
     'Lock this row': '${_('Lock this row')}',
     'MapReduce Job': '${_('MapReduce Job')}',
+    'Manage Users': '${ _('Manage Users') }',
     'Manual refresh': '${_('Manual refresh')}',
     'max': '${ _('max') }',
     'Memory': '${ _('Memory') }',
@@ -294,6 +299,7 @@
     'Missing value configuration.': '${ _('Missing value configuration.') }',
     'Missing x axis configuration.': '${ _('Missing x axis configuration.') }',
     'Missing y axis configuration.': '${ _('Missing y axis configuration.') }',
+    'My Profile': '${ _('My Profile') }',
     'Name': '${ _('Name') }',
     'Namespace': '${ _('Namespace') }',
     'Namespaces': '${ _('Namespaces') }',
@@ -406,6 +412,7 @@
     'Show row details': '${_('Show row details')}',
     'Show sample': '${_('Show sample')}',
     'Show view SQL': '${_('Show view SQL')}',
+    'Sign out': '${ _('Sign out') }',
     'Size': '${ _('Size') }',
     'Solr Search': '${ _('Solr Search') }',
     'Sources': '${ _('Sources') }',
@@ -449,11 +456,13 @@
     'Values': '${ _('Values') }',
     'variable': '${ _('variable') }',
     'Variables': '${ _('Variables') }',
+    'View Profile': '${ _('View Profile') }',
     'View': '${ _('View') }',
     'view': '${ _('view') }',
     'Views': '${ _('Views') }',
     'virtual': '${ _('virtual') }',
     'WARNING: This can be both resource and time-intensive.': '${ _('WARNING: This can be both resource and time-intensive.') }',
+    'Welcome Tour': '${ _('Welcome Tour') }',
     'With grant option': '${ _('With grant option') }',
     'With grant': '${ _('With grant') }',
     'Workflow': '${ _('Workflow') }',
@@ -484,6 +493,9 @@
     layerOptions: JSON.parse('${ leaflet['layer_options'] |n,unicode }')
   };
 
+  window.USER_VIEW_EDIT_USER_ENABLED = '${ user.has_hue_permission(action="access_view:useradmin:edit_user", app="useradmin") or is_admin(user) }' === 'True';
+  window.USER_IS_ADMIN = '${ is_admin(user) }' === 'True';
+  window.IS_LDAP_SETUP = '${ 'desktop.auth.backend.LdapBackend' in conf.AUTH.BACKEND.get() }' === 'True';
   window.LOGGED_USERNAME = '${ user.username }';
   window.LOGGED_USER_ID = ${ user.id };
 

+ 2 - 32
desktop/core/src/desktop/templates/hue.mako

@@ -253,36 +253,6 @@ ${ hueIcons.symbols() }
         </div>
 
         <div class="top-nav-right">
-          % if user.is_authenticated() and section != 'login' and (cluster != ANALYTIC_DB or IS_MULTICLUSTER_ONLY.get()):
-          <div class="dropdown navbar-dropdown pull-right">
-            % if IS_MULTICLUSTER_ONLY.get():
-              ##<!-- ko component: { name: 'hue-app-switcher', params: { onPrem: ko.observable(false) } } --><!-- /ko -->
-            % endif
-
-            <%
-              view_profile = user.has_hue_permission(action="access_view:useradmin:edit_user", app="useradmin") or is_admin(user)
-            %>
-            <button class="btn btn-flat" data-toggle="dropdown" data-bind="click: function(){ huePubSub.publish('hide.jobs.panel'); huePubSub.publish('hide.history.panel'); }">
-              <i class="fa fa-user"></i> ${ user.username } <span class="caret"></span>
-            </button>
-            <ul class="dropdown-menu">
-              % if view_profile:
-              <li><a href="javascript:void(0)" data-bind="hueLink: '/useradmin/users/edit/${ user.username }'" title="${ _('View Profile') if is_ldap_setup else _('Edit Profile') }"><i class="fa fa-fw fa-user"></i> ${_('My Profile')}</a></li>
-              % endif
-              % if is_admin(user):
-              <li data-bind="hueLink: '/useradmin/users/'"><a href="javascript: void(0);"><i class="fa fa-fw fa-group"></i> ${_('Manage Users')}</a></li>
-              % endif
-              % if is_admin(user):
-              <li><a data-bind="hueLink: '/about/'" href="javascript: void(0);"><span class="dropdown-no-icon">${_('Administration')}</span></a></li>
-              % endif
-              <li><a href="javascript:void(0)" onclick="huePubSub.publish('show.welcome.tour')"><span class="dropdown-no-icon">${_('Welcome Tour')}</span></a></li>
-              <li><a href="http://gethue.com" target="_blank"><span class="dropdown-no-icon">${_('Help')}</span></a></li>
-              <li class="divider"></li>
-              <li><a title="${_('Sign out')}" data-bind="hueLink: '/accounts/logout'" href="javascript: void(0);"><i class="fa fa-fw fa-sign-out"></i> ${ _('Sign out') }</a></li>
-            </ul>
-          </div>
-          % endif
-
           % if has_multi_clusters():
             <select data-bind="options: clusters, optionsText: 'name', value: 'id'" class="input-small" style="margin-top:8px">
             </select>
@@ -581,8 +551,8 @@ ${ smart_unicode(login_modal(request).content) | n,unicode }
 
     %if is_admin(user):
       tour.addStep('admin', {
-        text: '${ _ko('As a superuser, you can check system configuration from the username drop down and install sample data and jobs for your users.') }',
-        attachTo: '.top-nav-right .dropdown bottom'
+        text: '${ _ko('As a superuser, you can check system configuration from the user menu and install sample data and jobs for your users.') }',
+        attachTo: '.hue-sidebar .shepherd-user-menu right'
       });
     %endif
 

+ 6 - 0
desktop/core/src/desktop/templates/hue_icons.mako

@@ -351,6 +351,12 @@
       <path d="M29.425 22.96l1.387-2.96h1.188l-2 12h-30v-2.32l10.361-12.225-10.361-10.361v-7.094h30.625l1.375 8h-1.074l-0.585-1.215c-1.104-2.293-1.934-2.785-4.341-2.785h-20.688l11.033 11.033-9.294 10.967h16.949c3.625 0 4.583-1.299 5.425-3.040z"></path>
     </symbol>
 
+    <symbol id="hi-support" viewBox="0 0 24 24">
+      <g transform="scale(1.2) translate(-2.1, -2.1)">
+        <path d="M11.768 15.68a1.16 1.16 0 1 0 0 2.32 1.16 1.16 0 0 0 0-2.32zm-.91-1.457c0-.724.09-.967.269-1.397.18-.43.535-.902 1.066-1.417.529-.514.865-.88 1.007-1.098.217-.331.326-.69.326-1.075 0-.511-.126-.9-.38-1.168-.252-.27-.623-.404-1.113-.404-.467 0-.845.132-1.13.394-.285.264-.428.62-.428 1.069H8.493c.01-.963.338-1.725.982-2.285C10.12 6.28 10.973 6 12.033 6c1.093 0 1.945.278 2.557.833.612.555.918 1.33.918 2.327 0 .887-.414 1.76-1.24 2.62l-1.003.989c-.36.409-.544.67-.555 1.454h-1.851zM12 4c-4.411 0-8 3.589-8 8 0 4.41 3.589 8 8 8 4.412 0 8-3.59 8-8 0-4.411-3.588-8-8-8zm0 18C6.487 22 2 17.514 2 12S6.487 2 12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10z" fill="currentColor" fill-rule="evenodd"></path>
+      </g>
+    </symbol>
+
     <symbol id="hi-sigma-stream" viewBox="0 0 32 32">
       <g>
         <path d="m24.29172,19.54425l1.13561,-2.50675l0.97268,0l-1.6375,10.1625l-24.5625,0l0,-1.96475l8.48307,-10.35304l-8.48307,-8.77447l0,-6.00773l25.07422,0l1.12578,6.775l-0.87933,0l-0.47897,-1.02896c-0.9039,-1.94189 -1.58346,-2.35854 -3.55419,-2.35854l-16.9383,0l9.03327,9.34357l-7.60946,9.28768l13.87699,0c2.96797,0 3.75233,-1.10009 4.44172,-2.5745l-0.00001,-0.00001z"></path>

Vissa filer visades inte eftersom för många filer har ändrats