Ensure HeaderBar and Profile view use the same profile object so avatar gets synced
This commit is contained in:
@@ -203,9 +203,16 @@ ProfileModel.onChange(ProfileModel.KEYS.AVATAR, (value) => {
|
||||
profile.value.avatarUrl = value;
|
||||
});
|
||||
|
||||
async function refreshProfile() {
|
||||
const [error, result] = await profileModel.get();
|
||||
if (error) return console.error(error);
|
||||
profile.value = result;
|
||||
}
|
||||
|
||||
provide('subscriptionRequiredDialog', subscriptionRequiredDialog);
|
||||
provide('features', features);
|
||||
provide('profile', profile);
|
||||
provide('refreshProfile', refreshProfile);
|
||||
|
||||
onMounted(async () => {
|
||||
let [error, result] = await provisionModel.status();
|
||||
@@ -222,9 +229,7 @@ onMounted(async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
[error, result] = await profileModel.get();
|
||||
if (error) return console.error(error);
|
||||
profile.value = result;
|
||||
await refreshProfile();
|
||||
|
||||
// ensure language from profile if set
|
||||
if (profile.value.language) await setLanguage(profile.value.language);
|
||||
@@ -304,7 +309,7 @@ onMounted(async () => {
|
||||
</SideBar>
|
||||
|
||||
<div style="flex-grow: 1; display: flex; flex-direction: column; overflow: hidden; height: 100%;">
|
||||
<Headerbar :config="config" :subscription="subscription" :profile="profile"/>
|
||||
<Headerbar :config="config" :subscription="subscription"/>
|
||||
|
||||
<div style="display: flex; justify-content: center; overflow: auto; flex-grow: 1; padding: 0 6px; position: relative;">
|
||||
<AppsView v-if="view === VIEWS.APPS" />
|
||||
|
||||
@@ -12,7 +12,9 @@ import { prettyDate, prettyLongDate } from '@cloudron/pankow/utils';
|
||||
import NotificationsModel from '../models/NotificationsModel.js';
|
||||
import ServicesModel from '../models/ServicesModel.js';
|
||||
|
||||
const props = defineProps(['config', 'profile', 'subscription']);
|
||||
const props = defineProps(['config', 'subscription']);
|
||||
|
||||
const profile = inject('profile');
|
||||
|
||||
const helpButton = useTemplateRef('helpButton');
|
||||
const helpPopover = useTemplateRef('helpPopover');
|
||||
@@ -95,7 +97,7 @@ const description = marked.parse(t('support.help.description', {
|
||||
}));
|
||||
|
||||
onMounted(async () => {
|
||||
if (props.profile.isAtLeastAdmin) await refresh();
|
||||
if (profile.isAtLeastAdmin) await refresh();
|
||||
|
||||
await trackPlatformStatus();
|
||||
});
|
||||
|
||||
@@ -59,7 +59,7 @@ function create() {
|
||||
result.body.isAtLeastOwner = [ ROLES.OWNER ].indexOf(result.body.role) !== -1;
|
||||
|
||||
result.body.backgroundImageUrl = result.body.hasBackgroundImage ? `${API_ORIGIN}/api/v1/profile/background_image?access_token=${accessToken}&bustcache=${Date.now()}` : '';
|
||||
result.body.avatarUrl = `${API_ORIGIN}/api/v1/profile/avatar/${result.body.id}`;
|
||||
result.body.avatarUrl = `${API_ORIGIN}/api/v1/profile/avatar/${result.body.id}?ts=${Date.now()}`;
|
||||
|
||||
profileCached = result.body;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useI18n } from 'vue-i18n';
|
||||
const { t } = useI18n();
|
||||
|
||||
import { ref, onMounted, useTemplateRef } from 'vue';
|
||||
import { ref, onMounted, useTemplateRef, inject } from 'vue';
|
||||
import { Button, SingleSelect, Dialog, InputDialog, TextInput, InputGroup, FormGroup } from '@cloudron/pankow';
|
||||
import { setLanguage } from '../i18n.js';
|
||||
import { TOKEN_TYPES } from '../constants.js';
|
||||
@@ -28,8 +28,10 @@ const profileModel = ProfileModel.create();
|
||||
const cloudronModel = CloudronModel.create();
|
||||
const tokensModel = TokensModel.create();
|
||||
|
||||
const profile = inject('profile');
|
||||
const refreshProfile = inject('refreshProfile');
|
||||
|
||||
const config = ref({});
|
||||
const user = ref({});
|
||||
const inputDialog = useTemplateRef('inputDialog');
|
||||
const primaryEmailDialog = useTemplateRef('primaryEmailDialog');
|
||||
const fallbackEmailDialog = useTemplateRef('fallbackEmailDialog');
|
||||
@@ -46,13 +48,6 @@ async function onSelectLanguage(lang) {
|
||||
await setLanguage(lang);
|
||||
}
|
||||
|
||||
async function refreshProfile() {
|
||||
const [error, result] = await profileModel.get();
|
||||
if (error) return console.error(error);
|
||||
|
||||
user.value = result;
|
||||
}
|
||||
|
||||
// Profile edits
|
||||
async function onChangeDisplayName(currentDisplayName) {
|
||||
const displayName = await inputDialog.value.prompt({
|
||||
@@ -216,43 +211,43 @@ onMounted(async () => {
|
||||
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 20px">
|
||||
<div style="width: 128px;">
|
||||
<ImagePicker :src="user.avatarUrl" fallback-src="/img/avatar-default-symbolic.svg" :disabled="config.profileLocked" :size="512" :save-handler="onAvatarSubmit" display-width="128px"/>
|
||||
<ImagePicker :src="profile.avatarUrl" fallback-src="/img/avatar-default-symbolic.svg" :disabled="config.profileLocked" :size="512" :save-handler="onAvatarSubmit" display-width="128px"/>
|
||||
</div>
|
||||
<div style="flex-grow: 1;">
|
||||
<SettingsItem>
|
||||
<FormGroup>
|
||||
<label>{{ $t('main.username') }}</label>
|
||||
<div>{{ user.username }}</div>
|
||||
<div>{{ profile.username }}</div>
|
||||
</FormGroup>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem>
|
||||
<FormGroup>
|
||||
<label>{{ $t('main.displayName') }}</label>
|
||||
<div>{{ user.displayName }}</div>
|
||||
<div>{{ profile.displayName }}</div>
|
||||
</FormGroup>
|
||||
<div style="display: flex; align-items: center">
|
||||
<Button tool plain @click="onChangeDisplayName(user.displayName)" v-show="user.username && !user.source && !config.profileLocked">{{ $t('main.dialog.edit') }}</Button>
|
||||
<Button tool plain @click="onChangeDisplayName(profile.displayName)" v-show="profile.username && !profile.source && !config.profileLocked">{{ $t('main.dialog.edit') }}</Button>
|
||||
</div>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem>
|
||||
<FormGroup>
|
||||
<label>{{ $t('profile.primaryEmail') }}</label>
|
||||
<div>{{ user.email }}</div>
|
||||
<div>{{ profile.email }}</div>
|
||||
</FormGroup>
|
||||
<div style="display: flex; align-items: center">
|
||||
<Button tool plain @click="onChangeEmail(user.email)" v-show="user.username && !user.source && !config.profileLocked">{{ $t('main.dialog.edit') }}</Button>
|
||||
<Button tool plain @click="onChangeEmail(profile.email)" v-show="profile.username && !profile.source && !config.profileLocked">{{ $t('main.dialog.edit') }}</Button>
|
||||
</div>
|
||||
</SettingsItem>
|
||||
|
||||
<SettingsItem>
|
||||
<FormGroup>
|
||||
<label>{{ $t('profile.passwordRecoveryEmail') }}</label>
|
||||
<div>{{ user.fallbackEmail || 'unset' }}</div>
|
||||
<div>{{ profile.fallbackEmail || 'unset' }}</div>
|
||||
</FormGroup>
|
||||
<div style="display: flex; align-items: center">
|
||||
<Button tool plain @click="onChangeFallbackEmail(user.fallbackEmail)" v-show="user.username && !user.source && !config.profileLocked">{{ $t('main.dialog.edit') }}</Button>
|
||||
<Button tool plain @click="onChangeFallbackEmail(profile.fallbackEmail)" v-show="profile.username && !profile.source && !config.profileLocked">{{ $t('main.dialog.edit') }}</Button>
|
||||
</div>
|
||||
</SettingsItem>
|
||||
|
||||
@@ -267,15 +262,15 @@ onMounted(async () => {
|
||||
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<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>
|
||||
<Button tool v-show="!profile.source && !config.external2FA" @click="profile.twoFactorAuthenticationEnabled ? onTwoFADisable() : onOpenTwoFASetupDialog()">{{ $t(profile.twoFactorAuthenticationEnabled ? 'profile.disable2FAAction' : 'profile.enable2FAAction') }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
<NotificationSettings v-if="user.isAtLeastAdmin"/>
|
||||
<NotificationSettings v-if="profile.isAtLeastAdmin"/>
|
||||
<AppPasswords/>
|
||||
<ApiTokens v-if="user.isAtLeastAdmin"/>
|
||||
<ApiTokens v-if="profile.isAtLeastAdmin"/>
|
||||
|
||||
<Section :title="$t('profile.loginTokens.title')">
|
||||
<p>{{ $t('profile.loginTokens.description', { webadminTokenCount: webadminTokens.length, cliTokenCount: cliTokens.length }) }}</p>
|
||||
|
||||
Reference in New Issue
Block a user