mirror of
https://github.com/nextcloud/server.git
synced 2026-06-29 12:24:50 +02:00
Fix table view
Signed-off-by: julia.kirschenheuter <julia.kirschenheuter@nextcloud.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1418,14 +1418,8 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
|
||||
.userActions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
position: sticky;
|
||||
right: 0px;
|
||||
min-width: 88px;
|
||||
background-color: var(--color-main-background);
|
||||
}
|
||||
|
||||
&.row--editable .userActions {
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
@@ -1469,10 +1463,6 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
|
||||
}
|
||||
|
||||
&:hover {
|
||||
input:not([type='submit']):not(:focus):not(:active) {
|
||||
border-color: var(--color-border) !important;
|
||||
}
|
||||
|
||||
&:not(#grid-header) {
|
||||
box-shadow: 5px 0 0 var(--color-primary-element) inset;
|
||||
}
|
||||
@@ -1482,8 +1472,7 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> div,
|
||||
> .displayName > form,
|
||||
> td,
|
||||
> form {
|
||||
grid-row: 1;
|
||||
display: inline-flex;
|
||||
|
||||
@@ -21,7 +21,11 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div id="app-content" class="user-list-grid" @scroll.passive="onScroll">
|
||||
<table id="app-content"
|
||||
role="grid"
|
||||
:aria-label="t('settings', 'User\'s table')"
|
||||
class="user-list-grid"
|
||||
@scroll.passive="onScroll">
|
||||
<NcModal v-if="showConfig.showNewUserForm" size="small" @close="closeModal">
|
||||
<form id="new-user"
|
||||
:disabled="loading.all"
|
||||
@@ -152,85 +156,92 @@
|
||||
</div>
|
||||
</form>
|
||||
</NcModal>
|
||||
<div id="grid-header"
|
||||
:class="{'sticky': scrolled && !showConfig.showNewUserForm}"
|
||||
class="row">
|
||||
<div id="headerAvatar" class="avatar" />
|
||||
<div id="headerName" class="name">
|
||||
<div class="subtitle">
|
||||
<strong>
|
||||
{{ t('settings', 'Display name') }}
|
||||
</strong>
|
||||
</div>
|
||||
{{ t('settings', 'Username') }}
|
||||
</div>
|
||||
<div id="headerPassword" class="password">
|
||||
{{ t('settings', 'Password') }}
|
||||
</div>
|
||||
<div id="headerAddress" class="mailAddress">
|
||||
{{ t('settings', 'Email') }}
|
||||
</div>
|
||||
<div id="headerGroups" class="groups">
|
||||
{{ t('settings', 'Groups') }}
|
||||
</div>
|
||||
<div v-if="subAdminsGroups.length>0 && settings.isAdmin"
|
||||
id="headerSubAdmins"
|
||||
class="subadmins">
|
||||
{{ t('settings', 'Group admin for') }}
|
||||
</div>
|
||||
<div id="headerQuota" class="quota">
|
||||
{{ t('settings', 'Quota') }}
|
||||
</div>
|
||||
<div v-if="showConfig.showLanguages"
|
||||
id="headerLanguages"
|
||||
class="languages">
|
||||
{{ t('settings', 'Language') }}
|
||||
</div>
|
||||
<tbody>
|
||||
<tr id="grid-header"
|
||||
:class="{'sticky': scrolled && !showConfig.showNewUserForm}"
|
||||
class="row">
|
||||
<th id="headerAvatar" class="avatar">
|
||||
<span class="hidden-visually"> {{ t('settings', 'Avatar') }} </span>
|
||||
</th>
|
||||
<th id="headerName" class="name">
|
||||
<div class="subtitle">
|
||||
<strong>
|
||||
{{ t('settings', 'Display name') }}
|
||||
</strong>
|
||||
</div>
|
||||
{{ t('settings', 'Username') }}
|
||||
</th>
|
||||
<th id="headerPassword" class="password">
|
||||
{{ t('settings', 'Password') }}
|
||||
</th>
|
||||
<th id="headerAddress" class="mailAddress">
|
||||
{{ t('settings', 'Email') }}
|
||||
</th>
|
||||
<th id="headerGroups" class="groups">
|
||||
{{ t('settings', 'Groups') }}
|
||||
</th>
|
||||
<th v-if="subAdminsGroups.length>0 && settings.isAdmin"
|
||||
id="headerSubAdmins"
|
||||
class="subadmins">
|
||||
{{ t('settings', 'Group admin for') }}
|
||||
</th>
|
||||
<th id="headerQuota" class="quota">
|
||||
{{ t('settings', 'Quota') }}
|
||||
</th>
|
||||
<th v-if="showConfig.showLanguages"
|
||||
id="headerLanguages"
|
||||
class="languages">
|
||||
{{ t('settings', 'Language') }}
|
||||
</th>
|
||||
|
||||
<div v-if="showConfig.showUserBackend || showConfig.showStoragePath"
|
||||
class="headerUserBackend userBackend">
|
||||
<div v-if="showConfig.showUserBackend" class="userBackend">
|
||||
{{ t('settings', 'User backend') }}
|
||||
</div>
|
||||
<div v-if="showConfig.showStoragePath"
|
||||
class="subtitle storageLocation">
|
||||
{{ t('settings', 'Storage location') }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showConfig.showLastLogin"
|
||||
class="headerLastLogin lastLogin">
|
||||
{{ t('settings', 'Last login') }}
|
||||
</div>
|
||||
<th v-if="showConfig.showUserBackend || showConfig.showStoragePath"
|
||||
class="headerUserBackend userBackend">
|
||||
<div v-if="showConfig.showUserBackend" class="userBackend">
|
||||
{{ t('settings', 'User backend') }}
|
||||
</div>
|
||||
<div v-if="showConfig.showStoragePath"
|
||||
class="subtitle storageLocation">
|
||||
{{ t('settings', 'Storage location') }}
|
||||
</div>
|
||||
</th>
|
||||
<th v-if="showConfig.showLastLogin"
|
||||
class="headerLastLogin lastLogin">
|
||||
{{ t('settings', 'Last login') }}
|
||||
</th>
|
||||
|
||||
<div class="userActions" />
|
||||
</div>
|
||||
<th class="userActions hidden-visually">
|
||||
{{ t('settings', 'User actions') }}
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<user-row v-for="user in filteredUsers"
|
||||
:key="user.id"
|
||||
:external-actions="externalActions"
|
||||
:groups="groups"
|
||||
:languages="languages"
|
||||
:quota-options="quotaOptions"
|
||||
:settings="settings"
|
||||
:show-config="showConfig"
|
||||
:sub-admins-groups="subAdminsGroups"
|
||||
:user="user"
|
||||
:is-dark-theme="isDarkTheme" />
|
||||
<InfiniteLoading ref="infiniteLoading" @infinite="infiniteHandler">
|
||||
<div slot="spinner">
|
||||
<div class="users-icon-loading icon-loading" />
|
||||
</div>
|
||||
<div slot="no-more">
|
||||
<div class="users-list-end" />
|
||||
</div>
|
||||
<div slot="no-results">
|
||||
<div id="emptycontent">
|
||||
<div class="icon-contacts-dark" />
|
||||
<h2>{{ t('settings', 'No users in here') }}</h2>
|
||||
<user-row v-for="user in filteredUsers"
|
||||
:key="user.id"
|
||||
:external-actions="externalActions"
|
||||
:groups="groups"
|
||||
:languages="languages"
|
||||
:quota-options="quotaOptions"
|
||||
:settings="settings"
|
||||
:show-config="showConfig"
|
||||
:sub-admins-groups="subAdminsGroups"
|
||||
:user="user"
|
||||
:is-dark-theme="isDarkTheme" />
|
||||
|
||||
<InfiniteLoading ref="infiniteLoading" @infinite="infiniteHandler">
|
||||
<div slot="spinner">
|
||||
<div class="users-icon-loading icon-loading" />
|
||||
</div>
|
||||
</div>
|
||||
</InfiniteLoading>
|
||||
</div>
|
||||
<div slot="no-more">
|
||||
<div class="users-list-end" />
|
||||
</div>
|
||||
<div slot="no-results">
|
||||
<div id="emptycontent">
|
||||
<div class="icon-contacts-dark" />
|
||||
<h2>{{ t('settings', 'No users in here') }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
</InfiniteLoading>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -642,4 +653,12 @@ export default {
|
||||
* prevent it). */
|
||||
width: 0;
|
||||
}
|
||||
|
||||
#app-content tbody tr {
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
background-color: var(--color-main-background);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -56,23 +56,23 @@
|
||||
:user="user"
|
||||
:is-dark-theme="isDarkTheme"
|
||||
:class="{'row--menu-opened': openedMenu}" />
|
||||
<div v-else
|
||||
<tr v-else
|
||||
:class="{
|
||||
'disabled': loading.delete || loading.disable,
|
||||
'row--menu-opened': openedMenu
|
||||
}"
|
||||
:data-id="user.id"
|
||||
class="row row--editable">
|
||||
<div :class="{'icon-loading-small': loading.delete || loading.disable || loading.wipe}"
|
||||
<td :class="{'icon-loading-small': loading.delete || loading.disable || loading.wipe}"
|
||||
class="avatar">
|
||||
<img v-if="!loading.delete && !loading.disable && !loading.wipe"
|
||||
:src="generateAvatar(user.id, isDarkTheme)"
|
||||
alt=""
|
||||
height="32"
|
||||
width="32">
|
||||
</div>
|
||||
</td>
|
||||
<!-- dirty hack to ellipsis on two lines -->
|
||||
<div v-if="user.backendCapabilities.setDisplayName" class="displayName">
|
||||
<td v-if="user.backendCapabilities.setDisplayName" class="displayName">
|
||||
<form :class="{'icon-loading-small': loading.displayName}"
|
||||
class="displayName"
|
||||
@submit.prevent="updateDisplayName">
|
||||
@@ -90,53 +90,56 @@
|
||||
type="submit"
|
||||
value="">
|
||||
</form>
|
||||
</div>
|
||||
<div v-else class="name">
|
||||
</td>
|
||||
<td v-else class="name">
|
||||
{{ user.id }}
|
||||
<div class="displayName subtitle">
|
||||
<div :title="user.displayname.length > 20 ? user.displayname : ''" class="cellText">
|
||||
{{ user.displayname }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form v-if="settings.canChangePassword && user.backendCapabilities.setPassword"
|
||||
:class="{'icon-loading-small': loading.password}"
|
||||
class="password"
|
||||
@submit.prevent="updatePassword">
|
||||
<label class="hidden-visually" :for="'password'+user.id+rand">{{ t('settings', 'Add new password') }}</label>
|
||||
<input :id="'password'+user.id+rand"
|
||||
ref="password"
|
||||
:disabled="loading.password || loading.all"
|
||||
:minlength="minPasswordLength"
|
||||
maxlength="469"
|
||||
:placeholder="t('settings', 'Add new password')"
|
||||
autocapitalize="off"
|
||||
autocomplete="new-password"
|
||||
autocorrect="off"
|
||||
required
|
||||
spellcheck="false"
|
||||
type="password"
|
||||
value="">
|
||||
<input class="icon-confirm" type="submit" value="">
|
||||
</form>
|
||||
<div v-else />
|
||||
<form :class="{'icon-loading-small': loading.mailAddress}"
|
||||
class="mailAddress"
|
||||
@submit.prevent="updateEmail">
|
||||
<label class="hidden-visually" :for="'mailAddress'+user.id+rand">{{ t('settings', 'Add new email address') }}</label>
|
||||
<input :id="'mailAddress'+user.id+rand"
|
||||
ref="mailAddress"
|
||||
:disabled="loading.mailAddress||loading.all"
|
||||
:placeholder="t('settings', 'Add new email address')"
|
||||
:value="user.email"
|
||||
autocapitalize="off"
|
||||
autocomplete="new-password"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
type="email">
|
||||
<input class="icon-confirm" type="submit" value="">
|
||||
</form>
|
||||
<div :class="{'icon-loading-small': loading.groups}" class="groups">
|
||||
</td>
|
||||
<td v-if="settings.canChangePassword && user.backendCapabilities.setPassword">
|
||||
<form :class="{'icon-loading-small': loading.password}"
|
||||
class="password"
|
||||
@submit.prevent="updatePassword">
|
||||
<label class="hidden-visually" :for="'password'+user.id+rand">{{ t('settings', 'Add new password') }}</label>
|
||||
<input :id="'password'+user.id+rand"
|
||||
ref="password"
|
||||
:disabled="loading.password || loading.all"
|
||||
:minlength="minPasswordLength"
|
||||
maxlength="469"
|
||||
:placeholder="t('settings', 'Add new password')"
|
||||
autocapitalize="off"
|
||||
autocomplete="new-password"
|
||||
autocorrect="off"
|
||||
required
|
||||
spellcheck="false"
|
||||
type="password"
|
||||
value="">
|
||||
<input class="icon-confirm" type="submit" value="">
|
||||
</form>
|
||||
</td>
|
||||
<td v-else />
|
||||
<td>
|
||||
<form :class="{'icon-loading-small': loading.mailAddress}"
|
||||
class="mailAddress"
|
||||
@submit.prevent="updateEmail">
|
||||
<label class="hidden-visually" :for="'mailAddress'+user.id+rand">{{ t('settings', 'Add new email address') }}</label>
|
||||
<input :id="'mailAddress'+user.id+rand"
|
||||
ref="mailAddress"
|
||||
:disabled="loading.mailAddress||loading.all"
|
||||
:placeholder="t('settings', 'Add new email address')"
|
||||
:value="user.email"
|
||||
autocapitalize="off"
|
||||
autocomplete="new-password"
|
||||
autocorrect="off"
|
||||
spellcheck="false"
|
||||
type="email">
|
||||
<input class="icon-confirm" type="submit" value="">
|
||||
</form>
|
||||
</td>
|
||||
<td :class="{'icon-loading-small': loading.groups}" class="groups">
|
||||
<label class="hidden-visually" :for="'groups'+user.id+rand">{{ t('settings', 'Add user to group') }}</label>
|
||||
<NcMultiselect :id="'groups'+user.id+rand"
|
||||
:close-on-select="false"
|
||||
@@ -157,8 +160,8 @@
|
||||
@tag="createGroup">
|
||||
<span slot="noResult">{{ t('settings', 'No results') }}</span>
|
||||
</NcMultiselect>
|
||||
</div>
|
||||
<div v-if="subAdminsGroups.length>0 && settings.isAdmin"
|
||||
</td>
|
||||
<td v-if="subAdminsGroups.length>0 && settings.isAdmin"
|
||||
:class="{'icon-loading-small': loading.subadmins}"
|
||||
class="subadmins">
|
||||
<label class="hidden-visually" :for="'subadmins'+user.id+rand">{{ t('settings', 'Set user as admin for') }}</label>
|
||||
@@ -178,8 +181,8 @@
|
||||
@select="addUserSubAdmin">
|
||||
<span slot="noResult">{{ t('settings', 'No results') }}</span>
|
||||
</NcMultiselect>
|
||||
</div>
|
||||
<div :title="usedSpace"
|
||||
</td>
|
||||
<td :title="usedSpace"
|
||||
:class="{'icon-loading-small': loading.quota}"
|
||||
class="quota">
|
||||
<label class="hidden-visually" :for="'quota'+user.id+rand">{{ t('settings', 'Select user quota') }}</label>
|
||||
@@ -196,8 +199,8 @@
|
||||
track-by="id"
|
||||
@input="setUserQuota"
|
||||
@tag="validateQuota" />
|
||||
</div>
|
||||
<div v-if="showConfig.showLanguages"
|
||||
</td>
|
||||
<td v-if="showConfig.showLanguages"
|
||||
:class="{'icon-loading-small': loading.languages}"
|
||||
class="languages">
|
||||
<label class="hidden-visually" :for="'language'+user.id+rand">{{ t('settings', 'Set the language') }}</label>
|
||||
@@ -213,14 +216,14 @@
|
||||
label="name"
|
||||
track-by="code"
|
||||
@input="setUserLanguage" />
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<!-- don't show this on edit mode -->
|
||||
<div v-if="showConfig.showStoragePath || showConfig.showUserBackend"
|
||||
<td v-if="showConfig.showStoragePath || showConfig.showUserBackend"
|
||||
class="storageLocation" />
|
||||
<div v-if="showConfig.showLastLogin" />
|
||||
<td v-if="showConfig.showLastLogin" />
|
||||
|
||||
<div class="userActions">
|
||||
<td class="userActions">
|
||||
<div v-if="!loading.all"
|
||||
class="toggleUserActions">
|
||||
<NcActions>
|
||||
@@ -242,8 +245,8 @@
|
||||
<div class="icon-checkmark" />
|
||||
{{ feedbackMessage }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -697,4 +700,11 @@ export default {
|
||||
.row::v-deep .multiselect__single {
|
||||
z-index: auto !important;
|
||||
}
|
||||
.displayName input,
|
||||
.password input,
|
||||
.mailAddress input {
|
||||
width: 100%;
|
||||
height: 44px!important;
|
||||
border: 2px solid var(--color-border-dark);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<div class="row"
|
||||
<tr class="row"
|
||||
:class="{'disabled': loading.delete || loading.disable}"
|
||||
:data-id="user.id">
|
||||
<div class="avatar" :class="{'icon-loading-small': loading.delete || loading.disable || loading.wipe}">
|
||||
<td class="avatar" :class="{'icon-loading-small': loading.delete || loading.disable || loading.wipe}">
|
||||
<img v-if="!loading.delete && !loading.disable && !loading.wipe"
|
||||
alt=""
|
||||
width="32"
|
||||
height="32"
|
||||
:src="generateAvatar(user.id, isDarkTheme)">
|
||||
</div>
|
||||
</td>
|
||||
<!-- dirty hack to ellipsis on two lines -->
|
||||
<div class="name">
|
||||
<td class="name">
|
||||
<div class="displayName subtitle">
|
||||
<div :title="user.displayname.length > 20 ? user.displayname : ''" class="cellText">
|
||||
<strong>
|
||||
@@ -19,20 +19,20 @@
|
||||
</div>
|
||||
</div>
|
||||
{{ user.id }}
|
||||
</div>
|
||||
<div />
|
||||
<div class="mailAddress">
|
||||
</td>
|
||||
<td />
|
||||
<td class="mailAddress">
|
||||
<div :title="user.email !== null && user.email.length > 20 ? user.email : ''" class="cellText">
|
||||
{{ user.email }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="groups">
|
||||
</td>
|
||||
<td class="groups">
|
||||
{{ userGroupsLabels }}
|
||||
</div>
|
||||
<div v-if="subAdminsGroups.length > 0 && settings.isAdmin" class="subAdminsGroups">
|
||||
</td>
|
||||
<td v-if="subAdminsGroups.length > 0 && settings.isAdmin" class="subAdminsGroups">
|
||||
{{ userSubAdminsGroupsLabels }}
|
||||
</div>
|
||||
<div class="userQuota">
|
||||
</td>
|
||||
<td class="userQuota">
|
||||
<div class="quota">
|
||||
{{ userQuota }} ({{ usedSpace }})
|
||||
<progress class="quota-user-progress"
|
||||
@@ -40,23 +40,23 @@
|
||||
:value="usedQuota"
|
||||
max="100" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showConfig.showLanguages" class="languages">
|
||||
</td>
|
||||
<td v-if="showConfig.showLanguages" class="languages">
|
||||
{{ userLanguage.name }}
|
||||
</div>
|
||||
<div v-if="showConfig.showUserBackend || showConfig.showStoragePath" class="userBackend">
|
||||
</td>
|
||||
<td v-if="showConfig.showUserBackend || showConfig.showStoragePath" class="userBackend">
|
||||
<div v-if="showConfig.showUserBackend" class="userBackend">
|
||||
{{ user.backend }}
|
||||
</div>
|
||||
<div v-if="showConfig.showStoragePath" :title="user.storageLocation" class="storageLocation subtitle">
|
||||
{{ user.storageLocation }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showConfig.showLastLogin" :title="userLastLoginTooltip" class="lastLogin">
|
||||
</td>
|
||||
<td v-if="showConfig.showLastLogin" :title="userLastLoginTooltip" class="lastLogin">
|
||||
{{ userLastLogin }}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<div class="userActions">
|
||||
<td class="userActions">
|
||||
<div v-if="canEdit && !loading.all" class="toggleUserActions">
|
||||
<NcActions>
|
||||
<NcActionButton icon="icon-rename"
|
||||
@@ -78,8 +78,8 @@
|
||||
<div class="icon-checkmark" />
|
||||
{{ feedbackMessage }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -202,4 +202,7 @@ export default {
|
||||
background-color: var(--color-main-background);
|
||||
border: 0;
|
||||
}
|
||||
.row .name {
|
||||
padding-left: 0px!important;
|
||||
}
|
||||
</style>
|
||||
|
||||
Vendored
+2
-2
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -82,7 +82,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface {
|
||||
* @return Locator
|
||||
*/
|
||||
public static function rowForUser($user) {
|
||||
return Locator::forThe()->css("div.user-list-grid div.row[data-id=$user]")->
|
||||
return Locator::forThe()->css("table.user-list-grid tr.row[data-id=$user]")->
|
||||
describedAs("Row for user $user in Users Settings");
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface {
|
||||
* @return Locator
|
||||
*/
|
||||
public static function theColumn($column) {
|
||||
return Locator::forThe()->xpath("//div[@class='user-list-grid']//div[normalize-space() = '$column']")->
|
||||
return Locator::forThe()->xpath("//table[@class='user-list-grid']//*[normalize-space() = '$column']")->
|
||||
describedAs("The $column column in Users Settings");
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface {
|
||||
* @return Locator
|
||||
*/
|
||||
public static function editModeOn($user) {
|
||||
return Locator::forThe()->css("div.user-list-grid div.row.row--editable[data-id=$user]")->
|
||||
return Locator::forThe()->css("table.user-list-grid tr.row.row--editable[data-id=$user]")->
|
||||
describedAs("I see the edit mode is on for the user $user in Users Settings");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user