Merge pull request #8496 from nextcloud/ext-strg-design-fixes

External storage design fixes and update
This commit is contained in:
Morris Jobke 2018-02-27 15:59:06 +01:00 committed by GitHub
commit 77927442a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 126 additions and 112 deletions

View File

@ -18,9 +18,11 @@
#externalStorage td.status > span { #externalStorage td.status > span {
display: inline-block; display: inline-block;
height: 16px; height: 28px;
width: 16px; width: 28px;
vertical-align: text-bottom; vertical-align: text-bottom;
border-radius: 50%;
cursor: pointer;
} }
td.mountPoint, td.backend { width:160px; } td.mountPoint, td.backend { width:160px; }
@ -30,9 +32,25 @@ td.mountPoint, td.backend { width:160px; }
#addMountPoint>td.applicable { visibility:hidden; } #addMountPoint>td.applicable { visibility:hidden; }
#addMountPoint>td.hidden { visibility:hidden; } #addMountPoint>td.hidden { visibility:hidden; }
#externalStorage .icon-settings { #externalStorage td {
padding: 11px 20px; height: 50px;
vertical-align: text-bottom; &.mountOptionsToggle,
&.remove,
&.save {
position: relative;
padding: 0 !important;
width: 44px;
[class^='icon-'],
[class*=' icon-'] {
opacity: 0.5;
padding: 14px;
vertical-align: text-bottom;
cursor: pointer;
&:hover {
opacity: 1;
}
}
}
} }
#selectBackend { #selectBackend {
@ -57,9 +75,9 @@ td.mountPoint, td.backend { width:160px; }
} }
#externalStorage td.configuration label { #externalStorage td.configuration label {
min-width: 144px; /* 130px plus 2x7px padding */ width: 100%;
display: inline-block; display: inline-flex;
margin-right: 6px; align-items: center;
} }
#externalStorage td.configuration input.disabled-success { #externalStorage td.configuration input.disabled-success {
@ -72,10 +90,6 @@ td.mountPoint, td.backend { width:160px; }
top: 3px; top: 3px;
} }
#externalStorage td.status .success {
border-radius: 50%;
}
#userMountingBackends { #userMountingBackends {
padding-left: 25px; padding-left: 25px;
} }
@ -111,10 +125,6 @@ td.mountPoint, td.backend { width:160px; }
width: auto; width: auto;
} }
#externalStorage .mountOptionsDropdown {
margin-right: 40px;
}
.nav-icon-external-storage { .nav-icon-external-storage {
background-image: url('../img/app-dark.svg?v=1'); background-image: url('../img/app-dark.svg?v=1');
} }

View File

@ -12,31 +12,43 @@
// TODO: move to a separate file // TODO: move to a separate file
var MOUNT_OPTIONS_DROPDOWN_TEMPLATE = var MOUNT_OPTIONS_DROPDOWN_TEMPLATE =
'<div class="drop dropdown mountOptionsDropdown">' + '<div class="popovermenu open">'+
// FIXME: options are hard-coded for now // FIXME: options are hard-coded for now
' <div class="optionRow">' + ' <ul>'+
' <input id="mountOptionsEncrypt" name="encrypt" type="checkbox" value="true" checked="checked"/>' + ' <li class="optionRow">'+
' <label for="mountOptionsEncrypt">{{t "files_external" "Enable encryption"}}</label>' + ' <span class="menuitem">'+
' </div>' + ' <input id="mountOptionsEncrypt" class="checkbox" name="encrypt" type="checkbox" value="true" checked="checked"/>'+
' <div class="optionRow">' + ' <label for="mountOptionsEncrypt">{{t "files_external" "Enable encryption"}}</label>'+
' <input id="mountOptionsPreviews" name="previews" type="checkbox" value="true" checked="checked"/>' + ' </span>'+
' <label for="mountOptionsPreviews">{{t "files_external" "Enable previews"}}</label>' + ' </li>'+
' </div>' + ' <li class="optionRow">'+
' <div class="optionRow">' + ' <span class="menuitem">'+
' <input id="mountOptionsSharing" name="enable_sharing" type="checkbox" value="true"/>' + ' <input id="mountOptionsPreviews" class="checkbox" name="previews" type="checkbox" value="true" checked="checked"/>'+
' <label for="mountOptionsSharing">{{t "files_external" "Enable sharing"}}</label>' + ' <label for="mountOptionsPreviews">{{t "files_external" "Enable previews"}}</label>'+
' </div>' + ' </span>'+
' <div class="optionRow">' + ' </li>'+
' <label for="mountOptionsFilesystemCheck">{{t "files_external" "Check for changes"}}</label>' + ' <li class="optionRow">'+
' <select id="mountOptionsFilesystemCheck" name="filesystem_check_changes" data-type="int">' + ' <span class="menuitem">'+
' <option value="0">{{t "files_external" "Never"}}</option>' + ' <input id="mountOptionsSharing" class="checkbox" name="enable_sharing" type="checkbox" value="true"/>'+
' <option value="1" selected="selected">{{t "files_external" "Once every direct access"}}</option>' + ' <label for="mountOptionsSharing">{{t "files_external" "Enable sharing"}}</label>'+
' </select>' + ' </span>'+
' </div>' + ' </li>'+
' <div class="optionRow">' + ' <li class="optionRow">'+
' <input id="mountOptionsEncoding" name="encoding_compatibility" type="checkbox" value="true"/>' + ' <span class="menuitem icon-search">'+
' <label for="mountOptionsEncoding">{{mountOptionsEncodingLabel}}</label>' + ' <label for="mountOptionsFilesystemCheck">{{t "files_external" "Check for changes"}}</label>'+
' </div>' + ' <select id="mountOptionsFilesystemCheck" name="filesystem_check_changes" data-type="int">'+
' <option value="0">{{t "files_external" "Never"}}</option>'+
' <option value="1" selected="selected">{{t "files_external" "Once every direct access"}}</option>'+
' </select>'+
' </span>'+
' </li>'+
' <li class="optionRow">'+
' <span class="menuitem">'+
' <input id="mountOptionsEncoding" class="checkbox" name="encoding_compatibility" type="checkbox" value="true"/>'+
' <label for="mountOptionsEncoding">{{mountOptionsEncodingLabel}}</label>'+
' </span>'+
' </li>'+
' </ul>'+
'</div>'; '</div>';
/** /**
@ -716,15 +728,15 @@ MountConfigListView.prototype = _.extend({
self.recheckStorageConfig($(this).closest('tr')); self.recheckStorageConfig($(this).closest('tr'));
}); });
this.$el.on('click', 'td.remove>img', function() { this.$el.on('click', 'td.remove>.icon-delete', function() {
self.deleteStorageConfig($(this).closest('tr')); self.deleteStorageConfig($(this).closest('tr'));
}); });
this.$el.on('click', 'td.save>img', function () { this.$el.on('click', 'td.save>.icon-checkmark', function () {
self.saveStorageConfig($(this).closest('tr')); self.saveStorageConfig($(this).closest('tr'));
}); });
this.$el.on('click', 'td.mountOptionsToggle>img', function() { this.$el.on('click', 'td.mountOptionsToggle>.icon-settings-dark', function() {
self._showMountOptionsDropdown($(this).closest('tr')); self._showMountOptionsDropdown($(this).closest('tr'));
}); });
@ -1220,24 +1232,28 @@ MountConfigListView.prototype = _.extend({
*/ */
updateStatus: function($tr, status, message) { updateStatus: function($tr, status, message) {
var $statusSpan = $tr.find('.status span'); var $statusSpan = $tr.find('.status span');
$statusSpan.removeClass('loading-small success indeterminate error');
switch (status) { switch (status) {
case null: case null:
// remove status // remove status
break; break;
case StorageConfig.Status.IN_PROGRESS: case StorageConfig.Status.IN_PROGRESS:
$statusSpan.addClass('loading-small'); $statusSpan.attr('class', 'icon-loading-small');
break; break;
case StorageConfig.Status.SUCCESS: case StorageConfig.Status.SUCCESS:
$statusSpan.addClass('success'); $statusSpan.attr('class', 'success icon-checkmark-white');
break; break;
case StorageConfig.Status.INDETERMINATE: case StorageConfig.Status.INDETERMINATE:
$statusSpan.addClass('indeterminate'); $statusSpan.attr('class', 'indeterminate icon-info-white');
break; break;
default: default:
$statusSpan.addClass('error'); $statusSpan.attr('class', 'error icon-error-white');
}
if (typeof message === 'string') {
$statusSpan.attr('title', message);
$statusSpan.tooltip();
} else {
$statusSpan.tooltip('destroy');
} }
$statusSpan.attr('data-original-title', (typeof message === 'string') ? message : '');
}, },
/** /**
@ -1279,11 +1295,6 @@ MountConfigListView.prototype = _.extend({
* @param {Object} $tr configuration row * @param {Object} $tr configuration row
*/ */
_showMountOptionsDropdown: function($tr) { _showMountOptionsDropdown: function($tr) {
if (this._preventNextDropdown) {
// prevented because the click was on the toggle
this._preventNextDropdown = false;
return;
}
var self = this; var self = this;
var storage = this.getStorageConfig($tr); var storage = this.getStorageConfig($tr);
var $toggle = $tr.find('.mountOptionsToggle'); var $toggle = $tr.find('.mountOptionsToggle');
@ -1300,15 +1311,7 @@ MountConfigListView.prototype = _.extend({
dropDown.show($toggle, storage.mountOptions || [], visibleOptions); dropDown.show($toggle, storage.mountOptions || [], visibleOptions);
$('body').on('mouseup.mountOptionsDropdown', function(event) { $('body').on('mouseup.mountOptionsDropdown', function(event) {
var $target = $(event.target); var $target = $(event.target);
if ($toggle.has($target).length) { if ($target.closest('.popovermenu').length) {
// why is it always so hard to make dropdowns behave ?
// this prevents the click on the toggle to cause
// the dropdown to reopen itself
// (preventDefault doesn't work here because the click
// event is already in the queue and cannot be cancelled)
self._preventNextDropdown = true;
}
if ($target.closest('.dropdown').length) {
return; return;
} }
dropDown.hide(); dropDown.hide();

View File

@ -106,6 +106,7 @@
<?php if ($_['visibilityType'] === BackendService::VISIBILITY_ADMIN) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?> <?php if ($_['visibilityType'] === BackendService::VISIBILITY_ADMIN) print_unescaped('<th>'.$l->t('Available for').'</th>'); ?>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>&nbsp;</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -115,7 +116,7 @@
<?php endif; ?> <?php endif; ?>
> >
<td class="status"> <td class="status">
<span></span> <span data-placement="right" title="<?php p($l->t('Click to recheck the configuration')); ?>"></span>
</td> </td>
<td class="mountPoint"><input type="text" name="mountPoint" value="" <td class="mountPoint"><input type="text" name="mountPoint" value=""
placeholder="<?php p($l->t('Folder name')); ?>"> placeholder="<?php p($l->t('Folder name')); ?>">
@ -148,25 +149,14 @@
</td> </td>
<?php endif; ?> <?php endif; ?>
<td class="mountOptionsToggle hidden"> <td class="mountOptionsToggle hidden">
<img class="svg" <div class="icon-settings-dark" title="<?php p($l->t('Advanced settings')); ?>"></div>
title="<?php p($l->t('Advanced settings')); ?>"
alt="<?php p($l->t('Advanced settings')); ?>"
src="<?php print_unescaped(image_path('core', 'actions/settings.svg')); ?>"
/>
<input type="hidden" class="mountOptions" value="" /> <input type="hidden" class="mountOptions" value="" />
</td> </td>
<td class="remove hidden"> <td class="remove hidden">
<img class="svg" <div class="icon-delete" title="<?php p($l->t('Delete')); ?>"></div>
alt="<?php p($l->t('Delete')); ?>"
title="<?php p($l->t('Delete')); ?>"
src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"
/>
</td> </td>
<td class="save hidden"> <td class="save hidden">
<img alt="<?php p($l->t('Save')); ?>" <div class="icon-checkmark" title="<?php p($l->t('Save')); ?>"></div>
title="<?php p($l->t('Save')); ?>"
src="<?php print_unescaped(image_path('core', 'actions/checkmark.svg')); ?>"
/>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -45,9 +45,16 @@ describe('OCA.External.Settings tests', function() {
'<td class="applicable">' + '<td class="applicable">' +
'<input type="hidden" class="applicableUsers">' + '<input type="hidden" class="applicableUsers">' +
'</td>' + '</td>' +
'<td class="mountOptionsToggle"><input type="hidden" class="mountOptions"/><img class="svg action"/></td>' + '<td class="mountOptionsToggle">'+
'<td class="remove"><img alt="Delete" title="Delete" class="svg action"/></td>' + '<div class="icon-settings-dark" title="Advanced settings" deluminate_imagetype="unknown"></div>'+
'<td class="save"><img alt="Save" title="Save" class="svg action"/></td>' + '<input type="hidden" class="mountOptions"/>'+
'</td>'+
'<td class="remove">'+
'<div class="icon-delete" title="Delete" deluminate_imagetype="unknown"></div>'+
'</td>'+
'<td class="save">'+
'<div class="icon-checkmark" title="Save" deluminate_imagetype="unknown"></div>'+
'</td>'+
'</tr>' + '</tr>' +
'</tbody>' + '</tbody>' +
'</table>' '</table>'
@ -206,7 +213,7 @@ describe('OCA.External.Settings tests', function() {
expect($mountOptionsField.length).toEqual(1); expect($mountOptionsField.length).toEqual(1);
$mountOptionsField.val(JSON.stringify({previews:true})); $mountOptionsField.val(JSON.stringify({previews:true}));
var $saveButton = $tr.find('td.save img'); var $saveButton = $tr.find('td.save .icon-checkmark');
$saveButton.click(); $saveButton.click();
expect(fakeServer.requests.length).toEqual(1); expect(fakeServer.requests.length).toEqual(1);
@ -231,17 +238,17 @@ describe('OCA.External.Settings tests', function() {
// TODO: respond and check data-id // TODO: respond and check data-id
}); });
it('saves storage after closing mount options dropdown', function() { it('saves storage after closing mount options popovermenu', function() {
$tr.find('.mountOptionsToggle img').click(); $tr.find('.mountOptionsToggle .icon-settings-dark').click();
$tr.find('[name=previews]').trigger(new $.Event('keyup', {keyCode: 97})); $tr.find('[name=previews]').trigger(new $.Event('keyup', {keyCode: 97}));
$tr.find('input[data-parameter=field1]').val('test'); $tr.find('input[data-parameter=field1]').val('test');
// does not save inside the dropdown // does not save inside the popovermenu
expect(fakeServer.requests.length).toEqual(0); expect(fakeServer.requests.length).toEqual(0);
$('body').mouseup(); $('body').mouseup();
// but after closing the dropdown // but after closing the popovermenu
expect(fakeServer.requests.length).toEqual(1); expect(fakeServer.requests.length).toEqual(1);
}); });
// TODO: status indicator // TODO: status indicator
@ -313,7 +320,7 @@ describe('OCA.External.Settings tests', function() {
describe('recheck storages', function() { describe('recheck storages', function() {
// TODO // TODO
}); });
describe('mount options dropdown', function() { describe('mount options popovermenu', function() {
var $tr; var $tr;
var $td; var $td;
@ -323,45 +330,45 @@ describe('OCA.External.Settings tests', function() {
selectBackend('\\OC\\TestBackend'); selectBackend('\\OC\\TestBackend');
}); });
it('shows dropdown when clicking on toggle button, hides when clicking outside', function() { it('shows popovermenu when clicking on toggle button, hides when clicking outside', function() {
$td.find('img').click(); $td.find('.icon-settings-dark').click();
expect($td.find('.dropdown').length).toEqual(1); expect($td.find('.popovermenu.open').length).toEqual(1);
$('body').mouseup(); $('body').mouseup();
expect($td.find('.dropdown').length).toEqual(0); expect($td.find('.popovermenu.open').length).toEqual(0);
}); });
it('doesnt show the encryption option when encryption is disabled', function () { it('doesnt show the encryption option when encryption is disabled', function () {
view._encryptionEnabled = false; view._encryptionEnabled = false;
$td.find('img').click(); $td.find('.icon-settings-dark').click();
expect($td.find('.dropdown [name=encrypt]:visible').length).toEqual(0); expect($td.find('.popovermenu [name=encrypt]:visible').length).toEqual(0);
$('body').mouseup(); $('body').mouseup();
expect($td.find('.dropdown').length).toEqual(0); expect($td.find('.popovermenu.open').length).toEqual(0);
}); });
it('reads config from mountOptions field', function() { it('reads config from mountOptions field', function() {
$tr.find('input.mountOptions').val(JSON.stringify({previews:false})); $tr.find('input.mountOptions').val(JSON.stringify({previews:false}));
$td.find('img').click(); $td.find('.icon-settings-dark').click();
expect($td.find('.dropdown [name=previews]').prop('checked')).toEqual(false); expect($td.find('.popovermenu [name=previews]').prop('checked')).toEqual(false);
$('body').mouseup(); $('body').mouseup();
$tr.find('input.mountOptions').val(JSON.stringify({previews:true})); $tr.find('input.mountOptions').val(JSON.stringify({previews:true}));
$td.find('img').click(); $td.find('.icon-settings-dark').click();
expect($td.find('.dropdown [name=previews]').prop('checked')).toEqual(true); expect($td.find('.popovermenu [name=previews]').prop('checked')).toEqual(true);
}); });
it('writes config into mountOptions field', function() { it('writes config into mountOptions field', function() {
$td.find('img').click(); $td.find('.icon-settings-dark').click();
// defaults to true // defaults to true
var $field = $td.find('.dropdown [name=previews]'); var $field = $td.find('.popovermenu [name=previews]');
expect($field.prop('checked')).toEqual(true); expect($field.prop('checked')).toEqual(true);
$td.find('.dropdown [name=filesystem_check_changes]').val(0); $td.find('.popovermenu [name=filesystem_check_changes]').val(0);
$('body').mouseup(); $('body').mouseup();
expect(JSON.parse($tr.find('input.mountOptions').val())).toEqual({ expect(JSON.parse($tr.find('input.mountOptions').val())).toEqual({

View File

@ -845,6 +845,10 @@ kbd {
line-height: 1.6em; line-height: 1.6em;
padding: 8px 0; padding: 8px 0;
} }
> select {
margin: 0;
margin-left: 6px;
}
/* Add padding if contains icon+text */ /* Add padding if contains icon+text */
&:not(:empty) { &:not(:empty) {
padding-right: 10px !important; padding-right: 10px !important;
@ -853,17 +857,17 @@ kbd {
width: 16px; width: 16px;
padding: 0 10px; padding: 0 10px;
} }
/* checkbox/radio fixes */
> input.radio + label,
> input.checkbox + label { > input.checkbox + label {
padding: 0 !important; padding: 0 !important;
&::before { width: 100%;
margin: -2px 12px 0;
}
} }
> input.radio + label { > input.checkbox + label::before {
padding: 0 !important; margin: -2px 12px 0;
&::before { }
margin: -2px 11px 0; > input.radio + label::before {
} margin: -2px 11px 0;
} }
} }
> button { > button {

View File

@ -1112,14 +1112,14 @@ table.grid td.date {
span { span {
&.success { &.success {
background: #37ce02; background-color: $color-success;
border-radius: $border-radius; border-radius: $border-radius;
} }
&.error { &.error {
background: #ce3702; background-color: $color-error;
} }
&.indeterminate { &.indeterminate {
background: #e6db00; background-color: $color-warning;
border-radius: 40% 0; border-radius: 40% 0;
} }
} }