Skip to content

Commit

Permalink
Merge pull request #16391 from davelopez/migrate_export_components_to_ts
Browse files Browse the repository at this point in the history
Migrate some Remote Files Export components to composition API + TS
  • Loading branch information
dannon authored Jul 26, 2023
2 parents 28fce78 + 9b20f77 commit 26031d6
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 189 deletions.
70 changes: 0 additions & 70 deletions client/src/components/Common/ExportForm.test.js

This file was deleted.

91 changes: 91 additions & 0 deletions client/src/components/Common/ExportForm.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { getLocalVue } from "@tests/jest/helpers";
import { mount } from "@vue/test-utils";

import ExportForm from "./ExportForm.vue";
import FilesInput from "@/components/FilesDialog/FilesInput.vue";

const localVue = getLocalVue(true);

describe("ExportForm.vue", () => {
let wrapper: any;

beforeEach(async () => {
wrapper = mount(ExportForm, {
propsData: {},
localVue,
});
});

it("should render a form with export button disabled because inputs are empty", async () => {
expectExportButtonDisabled();
});

it("should render a form with export button disabled because directory is empty", async () => {
const newValue = "export.tar.gz";
await setNameInput(newValue);

expectExportButtonDisabled();
});

it("should render a form with export button disabled because name is empty", async () => {
const newValue = "gxfiles://";
await setDirectoryInput(newValue);

expectExportButtonDisabled();
});

it("should allow export when all inputs are defined", async () => {
await setNameInput("export.tar.gz");
await setDirectoryInput("gxfiles://");

expectExportButtonEnabled();
});

it("should localize button text", async () => {
const newLocal = wrapper.find(".export-button").text();
expect(newLocal).toBeLocalizationOf("Export");
});

it("should emit 'export' event with correct inputs on export button click", async () => {
await setNameInput("export.tar.gz");
await setDirectoryInput("gxfiles://");
expect(wrapper.emitted()).not.toHaveProperty("export");

await wrapper.find(".export-button").trigger("click");

expect(wrapper.emitted()).toHaveProperty("export");
expect(wrapper.emitted()["export"][0][0]).toBe("gxfiles://");
expect(wrapper.emitted()["export"][0][1]).toBe("export.tar.gz");
});

it("should clear the inputs (hence disabling export) after export when clearInputAfterExport is enabled", async () => {
await wrapper.setProps({
clearInputAfterExport: true,
});
await setNameInput("export.tar.gz");
await setDirectoryInput("gxfiles://");

await wrapper.find(".export-button").trigger("click");

expectExportButtonDisabled();
});

function expectExportButtonDisabled() {
expect(wrapper.find(".export-button").exists()).toBeTruthy();
expect(wrapper.find(".export-button").attributes("disabled")).toBeTruthy();
}

function expectExportButtonEnabled() {
expect(wrapper.find(".export-button").exists()).toBeTruthy();
expect(wrapper.find(".export-button").attributes("disabled")).toBeFalsy();
}

async function setNameInput(newValue: string) {
const nameInput = wrapper.find("#name");
await nameInput.setValue(newValue);
}

async function setDirectoryInput(newValue: string) {
await wrapper.findComponent(FilesInput).vm.$emit("input", newValue);
}
});
127 changes: 59 additions & 68 deletions client/src/components/Common/ExportForm.vue
Original file line number Diff line number Diff line change
@@ -1,73 +1,64 @@
<script setup lang="ts">
import { BButton, BCol, BFormGroup, BFormInput, BRow } from "bootstrap-vue";
import { computed, ref } from "vue";
import localize from "@/utils/localization";
import FilesInput from "@/components/FilesDialog/FilesInput.vue";
interface Props {
what?: string;
clearInputAfterExport?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
what: "archive",
clearInputAfterExport: false,
});
const emit = defineEmits<{
(e: "export", directory: string, name: string): void;
}>();
const directory = ref<string>("");
const name = ref<string>("");
const canExport = computed(() => name.value.length > 0 && directory.value.length > 0);
const directoryDescription = computed(() => localize(`Select a 'remote files' directory to export ${props.what} to.`));
const nameDescription = computed(() => localize("Give the exported file a name."));
const namePlaceholder = computed(() => localize("Name"));
const doExport = () => {
emit("export", directory.value, name.value);
if (props.clearInputAfterExport) {
directory.value = "";
name.value = "";
}
};
</script>

<template>
<div class="export-to-remote-file">
<b-form-group
id="fieldset-directory"
label-for="directory"
:description="directoryDescription | localize"
class="mt-3">
<BFormGroup id="fieldset-directory" label-for="directory" :description="directoryDescription" class="mt-3">
<FilesInput id="directory" v-model="directory" mode="directory" :require-writable="true" />
</b-form-group>
<b-form-group id="fieldset-name" label-for="name" :description="nameDescription | localize" class="mt-3">
<b-form-input id="name" v-model="name" :placeholder="namePlaceholder | localize" required></b-form-input>
</b-form-group>
<b-row align-h="end">
<b-col
><b-button class="export-button" variant="primary" :disabled="!canExport" @click.prevent="doExport">{{
exportButtonText | localize
}}</b-button></b-col
>
</b-row>
</BFormGroup>
<BFormGroup id="fieldset-name" label-for="name" :description="nameDescription" class="mt-3">
<BFormInput id="name" v-model="name" :placeholder="namePlaceholder" required />
</BFormGroup>
<BRow align-h="end">
<BCol>
<BButton
v-localize
class="export-button"
variant="primary"
:disabled="!canExport"
@click.prevent="doExport">
Export
</BButton>
</BCol>
</BRow>
</div>
</template>

<script>
import FilesInput from "components/FilesDialog/FilesInput.vue";
export default {
components: {
FilesInput,
},
props: {
what: {
type: String,
default: "archive",
},
clearInputAfterExport: {
type: Boolean,
default: false,
},
},
data() {
return {
directory: null,
name: null,
};
},
computed: {
directoryDescription() {
return `Select a 'remote files' directory to export ${this.what} to.`;
},
nameDescription() {
return "Give the exported file a name.";
},
namePlaceholder() {
return "Name";
},
exportButtonText() {
return "Export";
},
canExport() {
return !!this.name && !!this.directory;
},
},
methods: {
doExport() {
this.$emit("export", this.directory, this.name);
if (this.clearInputAfterExport) {
this.directory = null;
this.name = null;
}
},
},
};
</script>
95 changes: 45 additions & 50 deletions client/src/components/FilesDialog/FilesInput.vue
Original file line number Diff line number Diff line change
@@ -1,55 +1,50 @@
<template>
<BFormInput v-model="localValue" class="directory-form-input" :placeholder="placeholder" @click="selectFile">
</BFormInput>
</template>

<script>
<script setup lang="ts">
import { BFormInput } from "bootstrap-vue";
import { filesDialog } from "utils/data";
export default {
components: { BFormInput },
props: {
value: {
type: String,
},
mode: {
type: String,
default: "file",
},
requireWritable: {
type: Boolean,
default: false,
},
},
data() {
return {
localValue: this.value,
};
},
computed: {
placeholder() {
return `Click to select ${this.mode}`;
},
},
watch: {
localValue(newValue) {
this.$emit("input", newValue);
},
value(newValue) {
this.localValue = newValue;
},
import { computed } from "vue";
import { filesDialog } from "@/utils/data";
interface Props {
value: string;
mode?: "file" | "directory";
requireWritable?: boolean;
}
interface SelectableFile {
url: string;
}
const props = withDefaults(defineProps<Props>(), {
mode: "file",
requireWritable: false,
});
const emit = defineEmits<{
(e: "input", value: string): void;
}>();
const currentValue = computed({
get() {
return props.value;
},
methods: {
selectFile() {
const props = {
mode: this.mode,
requireWritable: this.requireWritable,
};
filesDialog((selected) => {
this.localValue = selected?.url;
}, props);
},
set(newValue) {
emit("input", newValue);
},
});
const selectFile = () => {
const dialogProps = {
mode: props.mode,
requireWritable: props.requireWritable,
};
filesDialog((selected: SelectableFile) => {
currentValue.value = selected?.url;
}, dialogProps);
};
const placeholder = `Click to select ${props.mode}`;
</script>

<template>
<BFormInput v-model="currentValue" class="directory-form-input" :placeholder="placeholder" @click="selectFile" />
</template>
Loading

0 comments on commit 26031d6

Please sign in to comment.