Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 1 addition & 4 deletions ui/src/components/User/UserWarning.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
data-test="device-chooser-component"
/>

<Welcome
:has-namespaces
data-test="welcome-component"
/>
<Welcome data-test="welcome-component" />

<BillingWarning
v-model="showBillingWarning"
Expand Down
21 changes: 12 additions & 9 deletions ui/src/components/Welcome/Welcome.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
</template>

<script setup lang="ts">
import { computed, ref, watch } from "vue";
import { computed, onMounted, ref, watch } from "vue";
import WelcomeFirstScreen from "./WelcomeFirstScreen.vue";
import WelcomeSecondScreen from "./WelcomeSecondScreen.vue";
import WelcomeThirdScreen from "./WelcomeThirdScreen.vue";
Expand All @@ -106,8 +106,6 @@ interface StepConfig {
action: () => void | Promise<void>;
}

const props = defineProps<{ hasNamespaces: boolean }>();

const showDialog = ref(false);
const authStore = useAuthStore();
const namespacesStore = useNamespacesStore();
Expand All @@ -119,17 +117,14 @@ const firstPendingDevice = ref<IDevice>();
const pollingTimer = ref<PollingTimer | undefined>(undefined);
const hasDeviceDetected = ref(false);
const tenantId = computed(() => namespacesStore.currentNamespace.tenant_id);
const hasNamespaces = computed(() => namespacesStore.namespaceList.length > 0);

const namespaceHasBeenShown = () => (
(JSON.parse(localStorage.getItem("namespacesWelcome") ?? "{}") as Record<string, boolean>)[tenantId.value] !== undefined);

const hasDevices = computed(() => (
statsStore.stats.registered_devices !== 0
|| statsStore.stats.pending_devices !== 0
|| statsStore.stats.rejected_devices !== 0
));
const hasDevices = ref(false);

const shouldShowWelcome = computed(() => props.hasNamespaces && !namespaceHasBeenShown() && !hasDevices.value);
const shouldShowWelcome = computed(() => hasNamespaces.value && !namespaceHasBeenShown() && !hasDevices.value);

watch(shouldShowWelcome, (newValue) => {
if (!newValue) return;
Expand Down Expand Up @@ -203,5 +198,13 @@ const stepConfigs: Record<number, StepConfig> = {
const currentStepConfig = computed(() => stepConfigs[currentStep.value]);
const handleConfirm = async () => { await currentStepConfig.value.action(); };

onMounted(() => {
hasDevices.value = (
statsStore.stats.registered_devices > 0
|| statsStore.stats.pending_devices > 0
|| statsStore.stats.rejected_devices > 0
);
});

defineExpose({ currentStep, hasDeviceDetected, showDialog });
</script>
48 changes: 21 additions & 27 deletions ui/tests/components/Welcome/Welcome.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createPinia, setActivePinia } from "pinia";
import { DOMWrapper, flushPromises, mount } from "@vue/test-utils";
import { DOMWrapper, flushPromises, mount, VueWrapper } from "@vue/test-utils";
import { createVuetify } from "vuetify";
import { expect, describe, it, beforeEach, vi } from "vitest";
import { expect, describe, it, beforeEach, vi, afterEach } from "vitest";
import Welcome from "@/components/Welcome/Welcome.vue";
import { SnackbarPlugin } from "@/plugins/snackbar";
import useNamespacesStore from "@/store/modules/namespaces";
Expand All @@ -25,6 +25,7 @@ const mockNamespace = {
};

describe("Welcome", () => {
let wrapper: VueWrapper<InstanceType<typeof Welcome>>;
const vuetify = createVuetify();
setActivePinia(createPinia());
const namespacesStore = useNamespacesStore();
Expand All @@ -34,33 +35,37 @@ describe("Welcome", () => {
vi.spyOn(Storage.prototype, "getItem").mockReturnValue("{}");
vi.spyOn(Storage.prototype, "setItem");
namespacesStore.currentNamespace = mockNamespace;

namespacesStore.namespaceList = [mockNamespace];
statsStore.stats = {
registered_devices: 0,
pending_devices: 0,
rejected_devices: 0,
online_devices: 0,
active_sessions: 0,
};

wrapper = mount(Welcome, { global: { plugins: [vuetify, SnackbarPlugin] } });
});

const mountWrapper = (hasNamespaces: boolean) => {
return mount(Welcome, {
global: { plugins: [vuetify, SnackbarPlugin] },
props: { hasNamespaces },
});
};
afterEach(() => { wrapper.unmount(); });

it("Does not render when hasNamespaces is false", async () => {
mountWrapper(false);
it("Enables 'Next' (confirm) button when the user sets up a device on step 2", async () => {
await flushPromises();

wrapper.vm.currentStep = 2;
wrapper.vm.hasDeviceDetected = true;
wrapper.vm.showDialog = true;

await flushPromises();

const dialog = new DOMWrapper(document.body);
expect(dialog.find('[data-test="welcome-window"]').exists()).toBe(false);
const confirmButton = dialog.find('[data-test="confirm-btn"]');
expect(confirmButton.exists()).toBe(true);
expect((confirmButton.element as HTMLButtonElement).disabled).toBe(false);
});

it("Does not render when namespace has already been shown", async () => {
vi.spyOn(Storage.prototype, "getItem").mockReturnValue('{"test-tenant":true}');
mountWrapper(true);

await flushPromises();

Expand All @@ -71,27 +76,16 @@ describe("Welcome", () => {
it("Does not render when namespace has devices", async () => {
statsStore.stats.registered_devices = 1;

mountWrapper(true);

await flushPromises();

const dialog = new DOMWrapper(document.body);
expect(dialog.find('[data-test="welcome-window"]').exists()).toBe(false);
});

it("Enables 'Next' (confirm) button when the user sets up a device on step 2", async () => {
const wrapper = mountWrapper(true);
await flushPromises();

wrapper.vm.currentStep = 2;
wrapper.vm.hasDeviceDetected = true;
wrapper.vm.showDialog = true;

it("Does not render when hasNamespaces is false", async () => {
namespacesStore.namespaceList = [];
await flushPromises();

const dialog = new DOMWrapper(document.body);
const confirmButton = dialog.find('[data-test="confirm-btn"]');
expect(confirmButton.exists()).toBe(true);
expect((confirmButton.element as HTMLButtonElement).disabled).toBe(false);
expect(dialog.find('[data-test="welcome-window"]').exists()).toBe(false);
});
});