Move vue views from Card to Sections

This commit is contained in:
Johannes Zellner
2025-01-17 14:02:05 +01:00
parent 7907d05847
commit 5feb5ee015
10 changed files with 84 additions and 112 deletions

View File

@@ -37,12 +37,11 @@
</div>
</Dialog>
<h2 class="header header-with-button">
{{ $t('profile.apiTokens.title') }}
<Button @click="newDialog.open()" icon="fa fa-plus">{{ $t('profile.apiTokens.newApiToken') }}</Button>
</h2>
<Section :title="$t('profile.apiTokens.title')">
<template #header-buttons>
<Button @click="newDialog.open()" icon="fa fa-plus">{{ $t('profile.apiTokens.newApiToken') }}</Button>
</template>
<Card>
<p v-html="$t('profile.apiTokens.description', { apiDocsLink: 'https://docs.cloudron.io/api.html' })"></p>
<table class="table table-hover" style="margin: 0;">
<thead>
@@ -73,7 +72,7 @@
</tr>
</tbody>
</table>
</Card>
</Section>
</div>
</template>
@@ -89,7 +88,7 @@ import { ref, onMounted, computed, useTemplateRef } from 'vue';
import { Button, Dialog, InputDialog, FormGroup, Radiobutton, TextInput } from 'pankow';
import { copyToClipboard, prettyLongDate } from 'pankow/utils';
import { TOKEN_TYPES } from '../constants.js';
import Card from './Card.vue';
import Section from './Section.vue';
import TokensModel from '../models/TokensModel.js';
const tokensModel = TokensModel.create(API_ORIGIN, localStorage.token);

View File

@@ -36,11 +36,11 @@
</div>
</Dialog>
<h2 class="header header-with-button">
{{ $t('profile.appPasswords.title') }}
<Button @click="newDialog.open()" icon="fa fa-plus">{{ $t('profile.appPasswords.newPassword') }}</Button>
</h2>
<Card>
<Section :title="$t('profile.appPasswords.title')">
<template #header-buttons>
<Button @click="newDialog.open()" icon="fa fa-plus">{{ $t('profile.appPasswords.newPassword') }}</Button>
</template>
<p>{{ $t('profile.appPasswords.description') }}</p>
<table class="table table-hover">
<thead>
@@ -65,7 +65,7 @@
</tr>
</tbody>
</table>
</Card>
</Section>
</div>
</template>
@@ -80,7 +80,7 @@ const t = i18n.t;
import { ref, onMounted, useTemplateRef, computed } from 'vue';
import { Button, Dialog, Dropdown, FormGroup, TextInput, InputDialog } from 'pankow';
import { prettyLongDate, copyToClipboard } from 'pankow/utils';
import Card from './Card.vue';
import Section from './Section.vue';
import AppPasswordsModel from '../models/AppPasswordsModel.js';
import AppsModel from '../models/AppsModel.js';

View File

@@ -1,25 +0,0 @@
<template>
<hr style="border-color: #d8dee4; border-size: 1px"/>
<div class="card">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'Card'
};
</script>
<style scoped>
.card {
position: relative;
margin-bottom: 15px;
padding: 10px 15px;
border-radius: 10px;
}
</style>

View File

@@ -27,63 +27,61 @@
<template #header-buttons>
<Button @click="profileModel.logout()" icon="fa fa-sign-out">{{ $t('main.logout') }}</Button>
</template>
<template #body>
<div style="display: flex;">
<div style="width: 150px;">
<input type="file" ref="avatarFileInput" style="display: none" accept="image/*" @change="onAvatarChanged()"/>
<div class="settings-avatar" :style="`background-image: url('${user.avatarUrl}');`" @click="avatarFileInput.click()">
<i class="picture-edit-indicator fa fa-pencil-alt"></i>
</div>
</div>
<div style="flex-grow: 1;">
<table style="width: 100%;">
<tbody>
<tr>
<td class="text-muted">{{ $t('main.username') }}</td>
<td style="width: 100px; height: 34px;">{{ user.username }}</td>
<td style="width: 32px"></td>
</tr>
<tr>
<td class="text-muted">{{ $t('main.displayName') }}</td>
<td style="white-space: nowrap;">{{ user.displayName }}</td>
<td><Button small tool outline @click="onChangeDisplayName(user.displayName)" v-show="!user.source && !config.profileLocked" icon="fa fa-edit text-small" /></td>
</tr>
<tr>
<td class="text-muted">{{ $t('profile.primaryEmail') }}</td>
<td style="white-space: nowrap;">{{ user.email }}</td>
<td><Button small tool outline @click="onChangeEmail(user.email)" v-show="!user.source && !config.profileLocked" icon="fa fa-edit text-small" /></td>
</tr>
<tr>
<td class="text-muted">{{ $t('profile.passwordRecoveryEmail') }}</td>
<td style="white-space: nowrap;">{{ user.fallbackEmail }}</td>
<td><Button small tool outline @click="onChangeFallbackEmail(user.fallbackEmail)" v-show="!user.source && !config.profileLocked" icon="fa fa-edit text-small" /></td>
</tr>
<tr>
<td class="text-muted">{{ $t('profile.language') }}</td>
<td colspan="2" class="text-right"><Dropdown small tool outline v-model="language" :options="languages" option-label="display" option-key="id" @select="onSelectLanguage"/></td>
</tr>
<tr v-show="!user.source">
<td colspan="3" class="text-right">
<!-- <Button tool @click="onPasswordReset()">{{ $t('profile.passwordResetAction') }}</Button> -->
<Button tool @click="onPasswordChange()">{{ $t('profile.changePasswordAction') }}</Button>
<Button tool v-show="!user.source && !config.external2FA" @click="user.twoFactorAuthenticationEnabled ? onTwoFADisable() : onOpenTwoFASetupDialog()">{{ $t(user.twoFactorAuthenticationEnabled ? 'profile.disable2FAAction' : 'profile.enable2FAAction') }}</Button>
</td>
</tr>
</tbody>
</table>
<div style="display: flex;">
<div style="width: 150px;">
<input type="file" ref="avatarFileInput" style="display: none" accept="image/*" @change="onAvatarChanged()"/>
<div class="settings-avatar" :style="`background-image: url('${user.avatarUrl}');`" @click="avatarFileInput.click()">
<i class="picture-edit-indicator fa fa-pencil-alt"></i>
</div>
</div>
</template>
<div style="flex-grow: 1;">
<table style="width: 100%;">
<tbody>
<tr>
<td class="text-muted">{{ $t('main.username') }}</td>
<td style="width: 100px; height: 34px;">{{ user.username }}</td>
<td style="width: 32px"></td>
</tr>
<tr>
<td class="text-muted">{{ $t('main.displayName') }}</td>
<td style="white-space: nowrap;">{{ user.displayName }}</td>
<td><Button small tool outline @click="onChangeDisplayName(user.displayName)" v-show="!user.source && !config.profileLocked" icon="fa fa-edit text-small" /></td>
</tr>
<tr>
<td class="text-muted">{{ $t('profile.primaryEmail') }}</td>
<td style="white-space: nowrap;">{{ user.email }}</td>
<td><Button small tool outline @click="onChangeEmail(user.email)" v-show="!user.source && !config.profileLocked" icon="fa fa-edit text-small" /></td>
</tr>
<tr>
<td class="text-muted">{{ $t('profile.passwordRecoveryEmail') }}</td>
<td style="white-space: nowrap;">{{ user.fallbackEmail }}</td>
<td><Button small tool outline @click="onChangeFallbackEmail(user.fallbackEmail)" v-show="!user.source && !config.profileLocked" icon="fa fa-edit text-small" /></td>
</tr>
<tr>
<td class="text-muted">{{ $t('profile.language') }}</td>
<td colspan="2" class="text-right"><Dropdown small tool outline v-model="language" :options="languages" option-label="display" option-key="id" @select="onSelectLanguage"/></td>
</tr>
<tr v-show="!user.source">
<td colspan="3" class="text-right">
<!-- <Button tool @click="onPasswordReset()">{{ $t('profile.passwordResetAction') }}</Button> -->
<Button tool @click="onPasswordChange()">{{ $t('profile.changePasswordAction') }}</Button>
<Button tool v-show="!user.source && !config.external2FA" @click="user.twoFactorAuthenticationEnabled ? onTwoFADisable() : onOpenTwoFASetupDialog()">{{ $t(user.twoFactorAuthenticationEnabled ? 'profile.disable2FAAction' : 'profile.enable2FAAction') }}</Button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</Section>
<AppPasswords/>
<ApiTokens v-show="user.isAtLeastAdmin"/>
<h2 class="header">{{ $t('profile.loginTokens.title') }}</h2>
<Card>
<Section :title="$t('profile.loginTokens.title')">
<p>{{ $t('profile.loginTokens.description', { webadminTokenCount: webadminTokens.length, cliTokenCount: cliTokens.length }) }}</p>
<Button danger :loading="revokeTokensBusy" :disabled="revokeTokensBusy" @click="onRevokeAllWebAndCliTokens()">{{ $t('profile.loginTokens.logoutAll') }}</Button>
</Card>
</Section>
</div>
</template>
@@ -100,7 +98,6 @@ import { Button, Dropdown, Dialog, InputDialog, TextInput } from 'pankow';
import { TOKEN_TYPES } from '../constants.js';
import AppPasswords from './AppPasswords.vue';
import Section from './Section.vue';
import Card from './Card.vue';
import ApiTokens from './ApiTokens.vue';
import ProfileModel from '../models/ProfileModel.js';

View File

@@ -1,12 +1,12 @@
<template>
<div>
<h1 class="section-header">
<h2 class="section-header">
{{ title }}
<slot name="header-buttons"></slot>
</h1>
</h2>
<hr class="section-divider"/>
<div class="section-body">
<slot name="body"></slot>
<slot></slot>
</div>
</div>
</template>
@@ -25,6 +25,8 @@ export default {
<style scoped>
.section-header {
padding-left: 15px;
padding-right: 15px;
}
.section-divider {
@@ -34,6 +36,12 @@ export default {
margin-bottom: 10px;
}
@media (prefers-color-scheme: dark) {
.section-divider {
border-color: #495057;
}
}
.section-body {
position: relative;
margin-bottom: 15px;

View File

@@ -2,13 +2,11 @@
<div class="content">
<h1 class="section-header">{{ $t('support.title') }}</h1>
<h3 class="section-header">{{ $t('support.help.title') }}</h3>
<Card>
<Section :title="$t('support.help.title')">
<div v-html="description"></div>
</Card>
</Section>
<h3 class="section-header">{{ $t('support.remoteSupport.title') }}</h3>
<Card>
<Section :title="$t('support.remoteSupport.title')">
<h2 class="text-center" v-show="!ready"><i class="fa fa-circle-notch fa-spin"></i></h2>
<div v-show="ready">
<p>{{ $t('support.remoteSupport.description') }}</p>
@@ -18,7 +16,7 @@
<b class="pull-left text-danger text-bold" v-show="toggleSshSupportError">{{ toggleSshSupportError }}</b>
<Button :danger="sshSupportEnabled ? true : null" @click="toggleSshSupport()">{{ sshSupportEnabled ? $t('support.remoteSupport.disableAction') : $t('support.remoteSupport.enableAction') }}</Button>
</div>
</Card>
</Section>
</div>
</template>
@@ -27,7 +25,7 @@
import { fetcher, Button } from 'pankow';
import { marked } from 'marked';
import Card from './Card.vue';
import Section from './Section.vue';
const API_ORIGIN = import.meta.env.VITE_API_ORIGIN ? import.meta.env.VITE_API_ORIGIN : window.location.origin;
const accessToken = localStorage.token;
@@ -36,7 +34,7 @@ export default {
name: 'SupportView',
components: {
Button,
Card
Section
},
data() {
return {

View File

@@ -79,9 +79,11 @@
</form>
</Dialog>
<h1 class="section-header">{{ $t('volumes.title') }} <Button @click="openVolumeDialog()" icon="fa fa-plus">{{ $t('volumes.addVolumeAction') }}</Button></h1>
<Section :title="$t('volumes.title')">
<template #header-buttons>
<Button @click="openVolumeDialog()" icon="fa fa-plus">{{ $t('volumes.addVolumeAction') }}</Button>
</template>
<Card>
<div v-html="$t('volumes.description')"></div>
<br/>
<TableView :columns="columns" :model="volumes" :busy="busy">
@@ -104,7 +106,7 @@
</div>
</template>
</TableView>
</Card>
</Section>
</div>
</template>
@@ -112,7 +114,7 @@
import { Button, ButtonGroup, Checkbox, Dialog, Dropdown, FormGroup, InputDialog, NumberInput, PasswordInput, TableView, TextInput } from 'pankow';
import Card from './Card.vue';
import Section from './Section.vue';
import { createVolumesModel } from '../models/VolumesModel.js';
@@ -126,7 +128,7 @@ export default {
components: {
Button,
ButtonGroup,
Card,
Section,
Checkbox,
Dialog,
Dropdown,