Migration redesign (#119)

* migration redesign init

* new color picker

* changelog

* added UI language selection

* fix layout issue on recipe editor

* remove git as dependency

* added UI editor for original URL

* CI/CD Tests

* test: fixed migration routes

Co-authored-by: Hayden <hay-kot@pm.me>
This commit is contained in:
Hayden
2021-01-23 19:53:39 -09:00
committed by GitHub
parent 138093d062
commit 079ebd8ee1
32 changed files with 549 additions and 367 deletions

View File

@@ -16,11 +16,11 @@
v-for="backup in backups"
:key="backup.name"
>
<v-card @click="openDialog(backup)">
<v-card hover outlined @click="openDialog(backup)">
<v-card-text>
<v-row align="center">
<v-col cols="12" sm="2">
<v-icon color="primary"> mdi-backup-restore </v-icon>
<v-icon large color="primary"> mdi-backup-restore </v-icon>
</v-col>
<v-col cols="12" sm="10">
<div>

View File

@@ -34,6 +34,8 @@
:backups="availableBackups"
/>
<SuccessFailureAlert
ref="report"
title="Back Restore Report"
success-header="Successfully Imported"
:success="successfulImports"
failed-header="Failed Imports"
@@ -91,6 +93,7 @@ export default {
this.backupLoading = false;
this.successfulImports = successful;
this.failedImports = failed;
this.$refs.report.open();
},
},
};

View File

@@ -0,0 +1,50 @@
<template>
<v-card>
<v-card-title> General Settings </v-card-title>
<v-divider></v-divider>
<v-card-text>
<v-row>
<v-col>
<v-select
v-model="selectedLang"
:items="langOptions"
item-text="name"
item-value="value"
label="Language"
>
</v-select>
</v-col>
<v-spacer></v-spacer>
<v-spacer></v-spacer>
</v-row>
</v-card-text>
</v-card>
</template>
<script>
export default {
data() {
return {
langOptions: [],
selectedLang: "en",
};
},
mounted() {
this.getOptions();
},
watch: {
selectedLang() {
this.$store.commit("setLang", this.selectedLang);
},
},
methods: {
getOptions() {
this.langOptions = this.$store.getters.getAllLangs;
this.selectedLang = this.$store.getters.getActiveLang;
},
},
};
</script>
<style>
</style>

View File

@@ -0,0 +1,97 @@
<template>
<v-card class="my-2" :loading="loading">
<v-card-title>
{{ title }}
<v-spacer></v-spacer>
<span>
<UploadBtn
class="mt-1"
:url="`/api/migrations/${folder}/upload/`"
@uploaded="$emit('refresh')"
/>
</span>
</v-card-title>
<v-card-text> {{ description }}</v-card-text>
<div v-if="available[0]">
<v-card
outlined
v-for="migration in available"
:key="migration.name"
class="ma-2"
>
<v-card-text>
<v-row align="center">
<v-col cols="12" sm="2">
<v-icon large color="primary"> mdi-import </v-icon>
</v-col>
<v-col cols="12" sm="10">
<div>
<strong>{{ migration.name }}</strong>
</div>
<div>{{ readableTime(migration.date) }}</div>
</v-col>
</v-row>
</v-card-text>
<v-card-actions class="mt-n6">
<v-spacer></v-spacer>
<v-btn color="error" text @click="deleteMigration(migration.name)">
Delete
</v-btn>
<v-btn color="accent" text @click="importMigration(migration.name)">
Import
</v-btn>
</v-card-actions>
</v-card>
</div>
<div v-else>
<v-card class="text-center ma-2">
<v-card-text>
No Migration Data Avaiable
</v-card-text>
</v-card>
</div>
<br />
</v-card>
</template>
<script>
import UploadBtn from "../../UI/UploadBtn";
import utils from "../../../utils";
import api from "../../../api";
export default {
props: {
folder: String,
title: String,
description: String,
available: Array,
},
components: {
UploadBtn,
},
data() {
return {
loading: false,
};
},
methods: {
deleteMigration(file_name) {
api.migrations.delete(this.folder, file_name);
this.$emit("refresh");
},
async importMigration(file_name) {
this.loading == true;
let response = await api.migrations.import(this.folder, file_name);
console.log(response);
this.$emit("imported", response.successful, response.failed);
this.loading == false;
},
readableTime(timestamp) {
let date = new Date(timestamp);
return utils.getDateAsText(date);
},
},
};
</script>
<style>
</style>

View File

@@ -1,44 +1,96 @@
<template>
<v-card :loading="loading">
<v-card-title class="headline"> {{$t('migration.recipe-migration')}} </v-card-title>
<v-divider></v-divider>
<div>
<SuccessFailureAlert
title="Migration Report"
ref="report"
failedHeader="Failed Imports"
:failed="failed"
successHeader="Successful Imports"
:success="success"
/>
<v-card :loading="loading">
<v-card-title class="headline">
{{ $t("migration.recipe-migration") }}
</v-card-title>
<v-divider></v-divider>
</v-card>
<v-tabs v-model="tab">
<v-tab>Chowdown</v-tab>
<v-tab>Nextcloud Recipes</v-tab>
<v-tab-item>
<ChowdownCard @loading="loading = true" @finished="finished" />
</v-tab-item>
<v-tab-item>
<NextcloudCard @loading="loading = true" @finished="finished" />
</v-tab-item>
</v-tabs>
</v-card>
<v-row dense>
<v-col
:sm="6"
:md="6"
:lg="4"
:xl="3"
v-for="migration in migrations"
:key="migration.title"
>
<MigrationCard
:title="migration.title"
:folder="migration.urlVariable"
:description="migration.description"
:available="migration.availableImports"
@refresh="getAvailableMigrations"
@imported="showReport"
/>
</v-col>
</v-row>
</div>
</template>
<script>
import ChowdownCard from "./ChowdownCard";
import NextcloudCard from "./NextcloudCard";
// import SuccessFailureAlert from "../../UI/SuccessFailureAlert";
// import TimePicker from "./Webhooks/TimePicker";
import MigrationCard from "./MigrationCard";
import SuccessFailureAlert from "../../UI/SuccessFailureAlert";
import api from "../../../api";
export default {
components: {
ChowdownCard,
NextcloudCard,
MigrationCard,
SuccessFailureAlert,
},
data() {
return {
tab: null,
loading: false,
success: [],
failed: [],
migrations: {
nextcloud: {
title: "Nextcloud Cookbook",
description: "migrate data from a nextcloud cookbook intance",
urlVariable: "nextcloud",
availableImports: [],
},
chowdown: {
title: "Chowdown",
description: "Migrate From Chowdown",
urlVariable: "chowdown",
availableImports: [],
},
},
};
},
mounted() {
this.getAvailableMigrations();
},
methods: {
finished() {
this.loading = false;
this.$store.dispatch("requestRecentRecipes");
},
async getAvailableMigrations() {
let response = await api.migrations.getMigrations();
response.forEach(element => {
if (element.type === "nextcloud") {
this.migrations.nextcloud.availableImports = element.files;
} else if (element.type === "chowdown") {
this.migrations.chowdown.availableImports = element.files;
}
});
},
showReport(successful, failed) {
this.success = successful;
this.failed = failed;
this.$refs.report.open();
},
},
};
</script>

View File

@@ -1,36 +1,28 @@
<template>
<div>
<v-btn block :color="value" @click="dialog = true">
{{ buttonText }}
</v-btn>
<v-dialog v-model="dialog" width="400">
<v-card>
<v-card-title> {{ buttonText }} {{$t('settings.color')}} </v-card-title>
<v-card-text>
<v-text-field v-model="color"> </v-text-field>
<v-row>
<v-col></v-col>
<v-col>
<v-color-picker
dot-size="28"
hide-inputs
hide-mode-switch
mode="hexa"
:show-swatches="swatches"
swatches-max-height="300"
v-model="color"
@change="updateColor"
></v-color-picker>
</v-col>
<v-col></v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-btn text @click="toggleSwatches"> {{$t('settings.swatches')}} </v-btn>
<v-btn text @click="dialog = false"> {{$t('general.select')}} </v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<div class="text-center">
<h3>{{ buttonText }}</h3>
</div>
<v-text-field v-model="color" hide-details class="ma-0 pa-0" solo>
<template v-slot:append>
<v-menu
v-model="menu"
top
nudge-bottom="105"
nudge-left="16"
:close-on-content-click="false"
>
<template v-slot:activator="{ on }">
<div :style="swatchStyle" v-on="on" swatches-max-height="300" />
</template>
<v-card>
<v-card-text class="pa-0">
<v-color-picker v-model="color" flat show-swatches />
</v-card-text>
</v-card>
</v-menu>
</template>
</v-text-field>
</div>
</template>
@@ -44,21 +36,30 @@ export default {
return {
dialog: false,
swatches: false,
color: "#FF00FF",
color: "#1976D2",
mask: "!#XXXXXXXX",
menu: false,
};
},
computed: {
swatchStyle() {
const { value, menu } = this;
return {
backgroundColor: value,
cursor: "pointer",
height: "30px",
width: "30px",
borderRadius: menu ? "50%" : "4px",
transition: "border-radius 200ms ease-in-out",
};
},
},
watch: {
color() {
this.updateColor();
},
},
methods: {
toggleSwatches() {
if (this.swatches) {
this.swatches = false;
} else this.swatches = true;
},
updateColor() {
this.$emit("input", this.color);
},