Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Improve loading UI and enable checkboxes by default
Signed-off-by: Christopher Ng <[email protected]>
  • Loading branch information
Pytal committed Apr 13, 2022
commit 7019a4fdbab3d35677a77d695a8ea349930c97ad
4 changes: 2 additions & 2 deletions js/user_migration-personal-settings.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/user_migration-personal-settings.js.map

Large diffs are not rendered by default.

146 changes: 79 additions & 67 deletions src/components/ExportSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,74 +24,77 @@
<div class="section">
<h2>{{ t('user_migration', 'Export') }}</h2>

<h3 class="settings-hint">
{{ t('user_migration', 'Please select the data you want to export') }}
</h3>

<div class="section__grid">
<!-- Base user data is permanently enabled -->
<div class="section__checkbox">
<CheckboxRadioSwitch :checked="true"
:disabled="true">
{{ t('user_migration', 'User information and settings') }}
</CheckboxRadioSwitch>
<em class="section__description">{{ t('user_migration', 'Basic user information including user ID and display name as well as your settings') }}</em>
<template v-if="!loading">
<h3 class="settings-hint">
{{ t('user_migration', 'Please select the data you want to export') }}
</h3>

<div class="section__grid">
<!-- Base user data is permanently enabled -->
<div class="section__checkbox">
<CheckboxRadioSwitch :checked="true"
:disabled="true">
{{ t('user_migration', 'User information and settings') }}
</CheckboxRadioSwitch>
<em class="section__description">{{ t('user_migration', 'Basic user information including user ID and display name as well as your settings') }}</em>
</div>
<div v-for="({id, displayName, description}) in migrators"
:key="id"
class="section__checkbox">
<CheckboxRadioSwitch name="migrators"
:value="id"
:checked.sync="selectedMigrators">
{{ displayName }}
</CheckboxRadioSwitch>
<em class="section__description">{{ description }}</em>
</div>
</div>
<div v-for="({id, displayName, description}) in sortedMigrators"
:key="id"
class="section__checkbox">
<CheckboxRadioSwitch name="migrators"
:value="id"
:checked.sync="selectedMigrators">
{{ displayName }}
</CheckboxRadioSwitch>
<em class="section__description">{{ description }}</em>
</div>
</div>

<div v-if="status.current !== 'export'"
class="section__status">
<Button type="secondary"
:aria-label="t('user_migration', 'Export your data')"
:disabled="status.current === 'import'"
@click.stop.prevent="startExport">
<template #icon>
<PackageDown title="" :size="20" />
</template>
{{ t('user_migration', 'Export') }}
</Button>
<div v-if="startingExport" class="icon-loading" />
</div>
<div v-else class="section__status">
<Button type="secondary"
:aria-label="t('user_migration', 'Show export status')"
:disabled="status.current === 'import'"
@click.stop.prevent="openModal">
{{ t('user_migration', 'Show status') }}
</Button>
<span class="settings-hint">{{ status.status === 'waiting' ? t('user_migration', 'Export queued') : t('user_migration', 'Export in progress…') }}</span>
</div>

<Modal v-if="modalOpened"
@close="closeModal">
<div class="section__modal">
<EmptyContent>
{{ modalMessage }}

<div v-if="status.current !== 'export'"
class="section__status">
<Button type="secondary"
:aria-label="t('user_migration', 'Export your data')"
:disabled="status.current === 'import'"
@click.stop.prevent="startExport">
<template #icon>
<PackageDown decorative />
<PackageDown title="" :size="20" />
</template>
<template v-if="status.status === 'started'" #desc>
{{ t('user_migration', 'Please do not use your account while exporting.') }}
</template>
</EmptyContent>
<div v-if="status.status === 'waiting' || status.status === 'started'"
class="section__icon icon-loading" />
<CheckCircleOutline v-else
class="section__icon"
title=""
:size="40" />
{{ t('user_migration', 'Export') }}
</Button>
<div v-if="startingExport" class="icon-loading" />
</div>
<div v-else class="section__status">
<Button type="secondary"
:aria-label="t('user_migration', 'Show export status')"
:disabled="status.current === 'import'"
@click.stop.prevent="openModal">
{{ t('user_migration', 'Show status') }}
</Button>
<span class="settings-hint">{{ status.status === 'waiting' ? t('user_migration', 'Export queued') : t('user_migration', 'Export in progress…') }}</span>
</div>
</Modal>

<Modal v-if="modalOpened"
@close="closeModal">
<div class="section__modal">
<EmptyContent>
{{ modalMessage }}
<template #icon>
<PackageDown decorative />
</template>
<template v-if="status.status === 'started'" #desc>
{{ t('user_migration', 'Please do not use your account while exporting.') }}
</template>
</EmptyContent>
<div v-if="status.status === 'waiting' || status.status === 'started'"
class="section__icon icon-loading" />
<CheckCircleOutline v-else
class="section__icon"
title=""
:size="40" />
</div>
</Modal>
</template>
<div v-else class="icon-loading" />
</div>
</template>

Expand Down Expand Up @@ -123,6 +126,10 @@ export default {
},

props: {
loading: {
type: Boolean,
default: true,
},
migrators: {
type: Array,
default: () => [],
Expand Down Expand Up @@ -150,10 +157,15 @@ export default {
}
return t('user_migration', 'Export completed successfully')
},
},

sortedMigrators() {
// TODO sort migrators?
return this.migrators
watch: {
migrators: {
deep: true,
immediate: true,
handler(migrators, oldMigrators) {
this.selectedMigrators = migrators.map(({ id }) => id)
},
},
},

Expand Down
103 changes: 55 additions & 48 deletions src/components/ImportSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,57 +24,60 @@
<div class="section">
<h2>{{ t('user_migration', 'Import') }}</h2>

<h3 class="section__hint settings-hint">
{{ t('user_migration', 'Please note that existing data may be overwritten') }}
</h3>

<!-- TODO use server API -->

<div v-if="status.current !== 'import'"
class="section__status">
<Button type="secondary"
:aria-label="t('user_migration', 'Import your data')"
:disabled="status.current === 'export'"
@click.stop.prevent="pickImportFile">
<template #icon>
<PackageUp title="" :size="20" />
</template>
{{ t('user_migration', 'Import') }}
</Button>
<div v-if="startingImport" class="icon-loading" />
</div>
<div v-else class="section__status">
<Button type="secondary"
:aria-label="t('user_migration', 'Show import status')"
:disabled="status.current === 'export'"
@click.stop.prevent="openModal">
{{ t('user_migration', 'Show status') }}
</Button>
<span class="settings-hint">{{ status.status === 'waiting' ? t('user_migration', 'Import queued') : t('user_migration', 'Import in progress…') }}</span>
</div>

<span class="section__picker-error error">{{ filePickerError }}</span>

<Modal v-if="modalOpened"
@close="closeModal">
<div class="section__modal">
<EmptyContent>
{{ modalMessage }}
<template v-if="!loading">
<h3 class="section__hint settings-hint">
{{ t('user_migration', 'Please note that existing data may be overwritten') }}
</h3>

<!-- TODO use server API -->

<div v-if="status.current !== 'import'"
class="section__status">
<Button type="secondary"
:aria-label="t('user_migration', 'Import your data')"
:disabled="status.current === 'export'"
@click.stop.prevent="pickImportFile">
<template #icon>
<PackageUp decorative />
<PackageUp title="" :size="20" />
</template>
<template v-if="status.status === 'started'" #desc>
{{ t('user_migration', 'Please do not use your account while importing.') }}
</template>
</EmptyContent>
<div v-if="status.status === 'waiting' || status.status === 'started'"
class="section__icon icon-loading" />
<CheckCircleOutline v-else
class="section__icon"
title=""
:size="40" />
{{ t('user_migration', 'Import') }}
</Button>
<div v-if="startingImport" class="icon-loading" />
</div>
<div v-else class="section__status">
<Button type="secondary"
:aria-label="t('user_migration', 'Show import status')"
:disabled="status.current === 'export'"
@click.stop.prevent="openModal">
{{ t('user_migration', 'Show status') }}
</Button>
<span class="settings-hint">{{ status.status === 'waiting' ? t('user_migration', 'Import queued') : t('user_migration', 'Import in progress…') }}</span>
</div>
</Modal>

<span class="section__picker-error error">{{ filePickerError }}</span>

<Modal v-if="modalOpened"
@close="closeModal">
<div class="section__modal">
<EmptyContent>
{{ modalMessage }}
<template #icon>
<PackageUp decorative />
</template>
<template v-if="status.status === 'started'" #desc>
{{ t('user_migration', 'Please do not use your account while importing.') }}
</template>
</EmptyContent>
<div v-if="status.status === 'waiting' || status.status === 'started'"
class="section__icon icon-loading" />
<CheckCircleOutline v-else
class="section__icon"
title=""
:size="40" />
</div>
</Modal>
</template>
<div v-else class="icon-loading" />
</div>
</template>

Expand Down Expand Up @@ -109,6 +112,10 @@ export default {
},

props: {
loading: {
type: Boolean,
default: true,
},
status: {
type: Object,
default: () => ({}),
Expand Down
8 changes: 6 additions & 2 deletions src/views/Personal/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@

<template>
<section>
<ExportSection :status="status"
<ExportSection :loading="loading"
:migrators="migrators"
:status="status"
@refresh-status="onRefreshStatus" />
<ImportSection :status="status"
<ImportSection :loading="loading"
:status="status"
@refresh-status="onRefreshStatus" />
</section>
</template>
Expand All @@ -52,6 +54,7 @@ export default {

data() {
return {
loading: true,
migrators: [],
status: { current: null },
}
Expand All @@ -60,6 +63,7 @@ export default {
async created() {
await this.fetchMigrators()
await this.fetchStatus()
this.loading = false
setInterval(this.fetchStatus, STATUS_POLLING_INTERVAL * 1000)
},

Expand Down