Fix table view

Signed-off-by: julia.kirschenheuter <julia.kirschenheuter@nextcloud.com>
pull/37870/head
julia.kirschenheuter 2023-04-21 16:33:10 +07:00
parent 9d2d3d482b
commit cb852ef63b
11 changed files with 200 additions and 179 deletions

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 { .userActions {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
position: sticky;
right: 0px; right: 0px;
min-width: 88px; min-width: 88px;
background-color: var(--color-main-background);
}
&.row--editable .userActions {
z-index: 10;
} }
.subtitle { .subtitle {
@ -1469,10 +1463,6 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
} }
&:hover { &:hover {
input:not([type='submit']):not(:focus):not(:active) {
border-color: var(--color-border) !important;
}
&:not(#grid-header) { &:not(#grid-header) {
box-shadow: 5px 0 0 var(--color-primary-element) inset; box-shadow: 5px 0 0 var(--color-primary-element) inset;
} }
@ -1482,8 +1472,7 @@ doesnotexist:-o-prefocus, .strengthify-wrapper {
width: 100%; width: 100%;
} }
> div, > td,
> .displayName > form,
> form { > form {
grid-row: 1; grid-row: 1;
display: inline-flex; display: inline-flex;

@ -21,7 +21,11 @@
--> -->
<template> <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"> <NcModal v-if="showConfig.showNewUserForm" size="small" @close="closeModal">
<form id="new-user" <form id="new-user"
:disabled="loading.all" :disabled="loading.all"
@ -152,42 +156,45 @@
</div> </div>
</form> </form>
</NcModal> </NcModal>
<div id="grid-header" <tbody>
<tr id="grid-header"
:class="{'sticky': scrolled && !showConfig.showNewUserForm}" :class="{'sticky': scrolled && !showConfig.showNewUserForm}"
class="row"> class="row">
<div id="headerAvatar" class="avatar" /> <th id="headerAvatar" class="avatar">
<div id="headerName" class="name"> <span class="hidden-visually"> {{ t('settings', 'Avatar') }} </span>
</th>
<th id="headerName" class="name">
<div class="subtitle"> <div class="subtitle">
<strong> <strong>
{{ t('settings', 'Display name') }} {{ t('settings', 'Display name') }}
</strong> </strong>
</div> </div>
{{ t('settings', 'Username') }} {{ t('settings', 'Username') }}
</div> </th>
<div id="headerPassword" class="password"> <th id="headerPassword" class="password">
{{ t('settings', 'Password') }} {{ t('settings', 'Password') }}
</div> </th>
<div id="headerAddress" class="mailAddress"> <th id="headerAddress" class="mailAddress">
{{ t('settings', 'Email') }} {{ t('settings', 'Email') }}
</div> </th>
<div id="headerGroups" class="groups"> <th id="headerGroups" class="groups">
{{ t('settings', 'Groups') }} {{ t('settings', 'Groups') }}
</div> </th>
<div v-if="subAdminsGroups.length>0 && settings.isAdmin" <th v-if="subAdminsGroups.length>0 && settings.isAdmin"
id="headerSubAdmins" id="headerSubAdmins"
class="subadmins"> class="subadmins">
{{ t('settings', 'Group admin for') }} {{ t('settings', 'Group admin for') }}
</div> </th>
<div id="headerQuota" class="quota"> <th id="headerQuota" class="quota">
{{ t('settings', 'Quota') }} {{ t('settings', 'Quota') }}
</div> </th>
<div v-if="showConfig.showLanguages" <th v-if="showConfig.showLanguages"
id="headerLanguages" id="headerLanguages"
class="languages"> class="languages">
{{ t('settings', 'Language') }} {{ t('settings', 'Language') }}
</div> </th>
<div v-if="showConfig.showUserBackend || showConfig.showStoragePath" <th v-if="showConfig.showUserBackend || showConfig.showStoragePath"
class="headerUserBackend userBackend"> class="headerUserBackend userBackend">
<div v-if="showConfig.showUserBackend" class="userBackend"> <div v-if="showConfig.showUserBackend" class="userBackend">
{{ t('settings', 'User backend') }} {{ t('settings', 'User backend') }}
@ -196,14 +203,16 @@
class="subtitle storageLocation"> class="subtitle storageLocation">
{{ t('settings', 'Storage location') }} {{ t('settings', 'Storage location') }}
</div> </div>
</div> </th>
<div v-if="showConfig.showLastLogin" <th v-if="showConfig.showLastLogin"
class="headerLastLogin lastLogin"> class="headerLastLogin lastLogin">
{{ t('settings', 'Last login') }} {{ t('settings', 'Last login') }}
</div> </th>
<div class="userActions" /> <th class="userActions hidden-visually">
</div> {{ t('settings', 'User actions') }}
</th>
</tr>
<user-row v-for="user in filteredUsers" <user-row v-for="user in filteredUsers"
:key="user.id" :key="user.id"
@ -216,6 +225,7 @@
:sub-admins-groups="subAdminsGroups" :sub-admins-groups="subAdminsGroups"
:user="user" :user="user"
:is-dark-theme="isDarkTheme" /> :is-dark-theme="isDarkTheme" />
<InfiniteLoading ref="infiniteLoading" @infinite="infiniteHandler"> <InfiniteLoading ref="infiniteLoading" @infinite="infiniteHandler">
<div slot="spinner"> <div slot="spinner">
<div class="users-icon-loading icon-loading" /> <div class="users-icon-loading icon-loading" />
@ -230,7 +240,8 @@
</div> </div>
</div> </div>
</InfiniteLoading> </InfiniteLoading>
</div> </tbody>
</table>
</template> </template>
<script> <script>
@ -642,4 +653,12 @@ export default {
* prevent it). */ * prevent it). */
width: 0; width: 0;
} }
#app-content tbody tr {
&:hover,
&:focus,
&:active {
background-color: var(--color-main-background);
}
}
</style> </style>

@ -56,23 +56,23 @@
:user="user" :user="user"
:is-dark-theme="isDarkTheme" :is-dark-theme="isDarkTheme"
:class="{'row--menu-opened': openedMenu}" /> :class="{'row--menu-opened': openedMenu}" />
<div v-else <tr v-else
:class="{ :class="{
'disabled': loading.delete || loading.disable, 'disabled': loading.delete || loading.disable,
'row--menu-opened': openedMenu 'row--menu-opened': openedMenu
}" }"
:data-id="user.id" :data-id="user.id"
class="row row--editable"> 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"> class="avatar">
<img v-if="!loading.delete && !loading.disable && !loading.wipe" <img v-if="!loading.delete && !loading.disable && !loading.wipe"
:src="generateAvatar(user.id, isDarkTheme)" :src="generateAvatar(user.id, isDarkTheme)"
alt="" alt=""
height="32" height="32"
width="32"> width="32">
</div> </td>
<!-- dirty hack to ellipsis on two lines --> <!-- 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}" <form :class="{'icon-loading-small': loading.displayName}"
class="displayName" class="displayName"
@submit.prevent="updateDisplayName"> @submit.prevent="updateDisplayName">
@ -90,17 +90,17 @@
type="submit" type="submit"
value=""> value="">
</form> </form>
</div> </td>
<div v-else class="name"> <td v-else class="name">
{{ user.id }} {{ user.id }}
<div class="displayName subtitle"> <div class="displayName subtitle">
<div :title="user.displayname.length > 20 ? user.displayname : ''" class="cellText"> <div :title="user.displayname.length > 20 ? user.displayname : ''" class="cellText">
{{ user.displayname }} {{ user.displayname }}
</div> </div>
</div> </div>
</div> </td>
<form v-if="settings.canChangePassword && user.backendCapabilities.setPassword" <td v-if="settings.canChangePassword && user.backendCapabilities.setPassword">
:class="{'icon-loading-small': loading.password}" <form :class="{'icon-loading-small': loading.password}"
class="password" class="password"
@submit.prevent="updatePassword"> @submit.prevent="updatePassword">
<label class="hidden-visually" :for="'password'+user.id+rand">{{ t('settings', 'Add new password') }}</label> <label class="hidden-visually" :for="'password'+user.id+rand">{{ t('settings', 'Add new password') }}</label>
@ -119,7 +119,9 @@
value=""> value="">
<input class="icon-confirm" type="submit" value=""> <input class="icon-confirm" type="submit" value="">
</form> </form>
<div v-else /> </td>
<td v-else />
<td>
<form :class="{'icon-loading-small': loading.mailAddress}" <form :class="{'icon-loading-small': loading.mailAddress}"
class="mailAddress" class="mailAddress"
@submit.prevent="updateEmail"> @submit.prevent="updateEmail">
@ -136,7 +138,8 @@
type="email"> type="email">
<input class="icon-confirm" type="submit" value=""> <input class="icon-confirm" type="submit" value="">
</form> </form>
<div :class="{'icon-loading-small': loading.groups}" class="groups"> </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> <label class="hidden-visually" :for="'groups'+user.id+rand">{{ t('settings', 'Add user to group') }}</label>
<NcMultiselect :id="'groups'+user.id+rand" <NcMultiselect :id="'groups'+user.id+rand"
:close-on-select="false" :close-on-select="false"
@ -157,8 +160,8 @@
@tag="createGroup"> @tag="createGroup">
<span slot="noResult">{{ t('settings', 'No results') }}</span> <span slot="noResult">{{ t('settings', 'No results') }}</span>
</NcMultiselect> </NcMultiselect>
</div> </td>
<div v-if="subAdminsGroups.length>0 && settings.isAdmin" <td v-if="subAdminsGroups.length>0 && settings.isAdmin"
:class="{'icon-loading-small': loading.subadmins}" :class="{'icon-loading-small': loading.subadmins}"
class="subadmins"> class="subadmins">
<label class="hidden-visually" :for="'subadmins'+user.id+rand">{{ t('settings', 'Set user as admin for') }}</label> <label class="hidden-visually" :for="'subadmins'+user.id+rand">{{ t('settings', 'Set user as admin for') }}</label>
@ -178,8 +181,8 @@
@select="addUserSubAdmin"> @select="addUserSubAdmin">
<span slot="noResult">{{ t('settings', 'No results') }}</span> <span slot="noResult">{{ t('settings', 'No results') }}</span>
</NcMultiselect> </NcMultiselect>
</div> </td>
<div :title="usedSpace" <td :title="usedSpace"
:class="{'icon-loading-small': loading.quota}" :class="{'icon-loading-small': loading.quota}"
class="quota"> class="quota">
<label class="hidden-visually" :for="'quota'+user.id+rand">{{ t('settings', 'Select user quota') }}</label> <label class="hidden-visually" :for="'quota'+user.id+rand">{{ t('settings', 'Select user quota') }}</label>
@ -196,8 +199,8 @@
track-by="id" track-by="id"
@input="setUserQuota" @input="setUserQuota"
@tag="validateQuota" /> @tag="validateQuota" />
</div> </td>
<div v-if="showConfig.showLanguages" <td v-if="showConfig.showLanguages"
:class="{'icon-loading-small': loading.languages}" :class="{'icon-loading-small': loading.languages}"
class="languages"> class="languages">
<label class="hidden-visually" :for="'language'+user.id+rand">{{ t('settings', 'Set the language') }}</label> <label class="hidden-visually" :for="'language'+user.id+rand">{{ t('settings', 'Set the language') }}</label>
@ -213,14 +216,14 @@
label="name" label="name"
track-by="code" track-by="code"
@input="setUserLanguage" /> @input="setUserLanguage" />
</div> </td>
<!-- don't show this on edit mode --> <!-- don't show this on edit mode -->
<div v-if="showConfig.showStoragePath || showConfig.showUserBackend" <td v-if="showConfig.showStoragePath || showConfig.showUserBackend"
class="storageLocation" /> class="storageLocation" />
<div v-if="showConfig.showLastLogin" /> <td v-if="showConfig.showLastLogin" />
<div class="userActions"> <td class="userActions">
<div v-if="!loading.all" <div v-if="!loading.all"
class="toggleUserActions"> class="toggleUserActions">
<NcActions> <NcActions>
@ -242,8 +245,8 @@
<div class="icon-checkmark" /> <div class="icon-checkmark" />
{{ feedbackMessage }} {{ feedbackMessage }}
</div> </div>
</div> </td>
</div> </tr>
</template> </template>
<script> <script>
@ -697,4 +700,11 @@ export default {
.row::v-deep .multiselect__single { .row::v-deep .multiselect__single {
z-index: auto !important; z-index: auto !important;
} }
.displayName input,
.password input,
.mailAddress input {
width: 100%;
height: 44px!important;
border: 2px solid var(--color-border-dark);
}
</style> </style>

@ -1,16 +1,16 @@
<template> <template>
<div class="row" <tr class="row"
:class="{'disabled': loading.delete || loading.disable}" :class="{'disabled': loading.delete || loading.disable}"
:data-id="user.id"> :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" <img v-if="!loading.delete && !loading.disable && !loading.wipe"
alt="" alt=""
width="32" width="32"
height="32" height="32"
:src="generateAvatar(user.id, isDarkTheme)"> :src="generateAvatar(user.id, isDarkTheme)">
</div> </td>
<!-- dirty hack to ellipsis on two lines --> <!-- dirty hack to ellipsis on two lines -->
<div class="name"> <td class="name">
<div class="displayName subtitle"> <div class="displayName subtitle">
<div :title="user.displayname.length > 20 ? user.displayname : ''" class="cellText"> <div :title="user.displayname.length > 20 ? user.displayname : ''" class="cellText">
<strong> <strong>
@ -19,20 +19,20 @@
</div> </div>
</div> </div>
{{ user.id }} {{ user.id }}
</div> </td>
<div /> <td />
<div class="mailAddress"> <td class="mailAddress">
<div :title="user.email !== null && user.email.length > 20 ? user.email : ''" class="cellText"> <div :title="user.email !== null && user.email.length > 20 ? user.email : ''" class="cellText">
{{ user.email }} {{ user.email }}
</div> </div>
</div> </td>
<div class="groups"> <td class="groups">
{{ userGroupsLabels }} {{ userGroupsLabels }}
</div> </td>
<div v-if="subAdminsGroups.length > 0 && settings.isAdmin" class="subAdminsGroups"> <td v-if="subAdminsGroups.length > 0 && settings.isAdmin" class="subAdminsGroups">
{{ userSubAdminsGroupsLabels }} {{ userSubAdminsGroupsLabels }}
</div> </td>
<div class="userQuota"> <td class="userQuota">
<div class="quota"> <div class="quota">
{{ userQuota }} ({{ usedSpace }}) {{ userQuota }} ({{ usedSpace }})
<progress class="quota-user-progress" <progress class="quota-user-progress"
@ -40,23 +40,23 @@
:value="usedQuota" :value="usedQuota"
max="100" /> max="100" />
</div> </div>
</div> </td>
<div v-if="showConfig.showLanguages" class="languages"> <td v-if="showConfig.showLanguages" class="languages">
{{ userLanguage.name }} {{ userLanguage.name }}
</div> </td>
<div v-if="showConfig.showUserBackend || showConfig.showStoragePath" class="userBackend"> <td v-if="showConfig.showUserBackend || showConfig.showStoragePath" class="userBackend">
<div v-if="showConfig.showUserBackend" class="userBackend"> <div v-if="showConfig.showUserBackend" class="userBackend">
{{ user.backend }} {{ user.backend }}
</div> </div>
<div v-if="showConfig.showStoragePath" :title="user.storageLocation" class="storageLocation subtitle"> <div v-if="showConfig.showStoragePath" :title="user.storageLocation" class="storageLocation subtitle">
{{ user.storageLocation }} {{ user.storageLocation }}
</div> </div>
</div> </td>
<div v-if="showConfig.showLastLogin" :title="userLastLoginTooltip" class="lastLogin"> <td v-if="showConfig.showLastLogin" :title="userLastLoginTooltip" class="lastLogin">
{{ userLastLogin }} {{ userLastLogin }}
</div> </td>
<div class="userActions"> <td class="userActions">
<div v-if="canEdit && !loading.all" class="toggleUserActions"> <div v-if="canEdit && !loading.all" class="toggleUserActions">
<NcActions> <NcActions>
<NcActionButton icon="icon-rename" <NcActionButton icon="icon-rename"
@ -78,8 +78,8 @@
<div class="icon-checkmark" /> <div class="icon-checkmark" />
{{ feedbackMessage }} {{ feedbackMessage }}
</div> </div>
</div> </td>
</div> </tr>
</template> </template>
<script> <script>
@ -202,4 +202,7 @@ export default {
background-color: var(--color-main-background); background-color: var(--color-main-background);
border: 0; border: 0;
} }
.row .name {
padding-left: 0px!important;
}
</style> </style>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -82,7 +82,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface {
* @return Locator * @return Locator
*/ */
public static function rowForUser($user) { 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"); describedAs("Row for user $user in Users Settings");
} }
@ -144,7 +144,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface {
* @return Locator * @return Locator
*/ */
public static function theColumn($column) { 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"); describedAs("The $column column in Users Settings");
} }
@ -170,7 +170,7 @@ class UsersSettingsContext implements Context, ActorAwareInterface {
* @return Locator * @return Locator
*/ */
public static function editModeOn($user) { 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"); describedAs("I see the edit mode is on for the user $user in Users Settings");
} }