Skip to content
Open
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
33 changes: 33 additions & 0 deletions apps/data-management/e2e/specs/sites.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,39 @@ test.describe('sites and workspaces', () => {
await expect(mutableThingRow).toBeVisible()
})

test('modifier-clicking a site opens its details in a new tab', async ({
page,
}) => {
await authenticateSession(page, users.owner.email, users.owner.password)
await page.goto('/sites')
await selectWorkspace(page, fixtures.workspaces.public.name)

const siteRow = page.locator('tr').filter({
hasText: fixtures.things.public.name,
})
await expect(siteRow).toBeVisible()

const siteLink = siteRow.getByRole('link', {
name: fixtures.things.public.name,
})
const newPagePromise = page.context().waitForEvent('page')
await siteLink.click({
modifiers: [process.platform === 'darwin' ? 'Meta' : 'Control'],
})
const newPage = await newPagePromise

await expect(page).toHaveURL(/\/sites$/)
await expect(newPage).toHaveURL(
new RegExp(`/sites/${fixtures.things.public.id}$`)
)
await newPage.close()

await siteLink.click()
await expect(page).toHaveURL(
new RegExp(`/sites/${fixtures.things.public.id}$`)
)
})

test('owner can register a site with metadata and see the saved values on site details', async ({
page,
}) => {
Expand Down
66 changes: 52 additions & 14 deletions apps/data-management/src/pages/Sites.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
multi-sort
item-value="id"
class="elevation-3 owned-sites-table"
@click:row="onRowClick"
color="primary"
:hover="coloredThings?.length > 0 && isPageLoaded"
:style="{ 'max-height': `200vh` }"
Expand Down Expand Up @@ -106,15 +105,45 @@
</p>
</div>
</template>
<template v-slot:item.samplingFeatureCode="{ item }">
<RouterLink
:to="siteDetailsRoute(item.id)"
class="site-details-link"
>
{{ item.samplingFeatureCode }}
</RouterLink>
</template>
<template v-slot:item.name="{ item }">
<RouterLink
:to="siteDetailsRoute(item.id)"
class="site-details-link"
>
{{ item.name }}
</RouterLink>
</template>
<template v-slot:item.siteType="{ item }">
<RouterLink
:to="siteDetailsRoute(item.id)"
class="site-details-link"
>
{{ item.siteType }}
</RouterLink>
</template>
<template v-slot:item.tagValue="{ item }">
<template v-for="(tag, index) in item.tags">
<v-chip
:color="item.color?.background"
v-if="tag.key === filterCriteria.key"
>
{{ item.tagValue }}
</v-chip>
</template>
<RouterLink
:to="siteDetailsRoute(item.id)"
class="site-details-link"
>
<template v-for="tag in item.tags">
<v-chip
:color="item.color?.background"
v-if="tag.key === filterCriteria.key"
:key="`${tag.key}:${tag.value}`"
>
{{ item.tagValue }}
</v-chip>
</template>
</RouterLink>
</template>
</v-data-table-virtual>
</v-card>
Expand All @@ -132,7 +161,6 @@
</template>

<script setup lang="ts">
import { useRouter } from 'vue-router'
import { ref, onMounted, computed, watch } from 'vue'
import OpenLayersMap from '@/components/Maps/OpenLayersMap.vue'
import SiteForm from '@/components/Site/SiteForm.vue'
Expand Down Expand Up @@ -225,7 +253,6 @@ const coloredThings = computed<ThingSiteSummaryWithColor[]>(() =>

const showSiteForm = ref(false)
const showFilter = ref(false)
const router = useRouter()

const headers = computed(() => {
const baseHeaders = [
Expand All @@ -249,9 +276,10 @@ const handleFilter = (criteria: { key: string; values: string[] }) => {
filterCriteria.value = criteria
}

const onRowClick = (event: Event, item: any) => {
router.push({ name: 'SiteDetails', params: { id: item.item.id } })
}
const siteDetailsRoute = (id: string) => ({
name: 'SiteDetails',
params: { id },
})

const loadThings = async () => {
const res = await hs.things.listSiteSummaries(selectedWorkspace.value!.id)
Expand Down Expand Up @@ -282,4 +310,14 @@ onMounted(async () => {
position: relative;
height: 33rem;
}

.site-details-link {
align-items: center;
color: inherit;
display: flex;
margin: 0 -16px;
min-height: var(--v-table-row-height);
padding: 0 16px;
text-decoration: none;
}
</style>
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { flushPromises, mount, shallowMount } from '@vue/test-utils'
import {
enableAutoUnmount,
flushPromises,
mount,
shallowMount,
} from '@vue/test-utils'
import { createPinia, setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import RatingCurveTaskDetails from '@/components/Orchestration/data-products/RatingCurveTaskDetails.vue'
import SimpleProductTaskDetails from '@/components/Orchestration/data-products/SimpleProductTaskDetails.vue'
import IngestionTaskDetails from '@/components/Orchestration/ingestion/IngestionTaskDetails.vue'
import QualityTaskDetails from '@/components/Orchestration/monitoring/QualityTaskDetails.vue'

enableAutoUnmount(afterEach)

const {
dataProductGetMock,
Expand Down Expand Up @@ -169,6 +180,18 @@ const globalStubs = {
emits: ['close', 'updated', 'deleted'],
template: '<div class="quality-form-stub" />',
},
DeleteTaskCard: {
name: 'DeleteTaskCard',
emits: ['close', 'delete'],
template: '<div />',
},
AggregationForm: { template: '<div />' },
DerivationForm: { template: '<div />' },
ExpressionForm: { template: '<div />' },
RatingCurveForm: { template: '<div />' },
NoScheduleIcon: { template: '<span />' },
ProductTaskSwimlanes: { template: '<div />' },
RatingCurveSwimlanes: { template: '<div />' },
}

const seedWorkspace = async () => {
Expand Down Expand Up @@ -208,9 +231,6 @@ describe('Task detail components', () => {
})

it('fetches rating-curve task details from the data-product task endpoint', async () => {
const { default: RatingCurveTaskDetails } = await import(
'@/components/Orchestration/data-products/RatingCurveTaskDetails.vue'
)
await seedWorkspace()

mount(RatingCurveTaskDetails as any, {
Expand Down Expand Up @@ -261,9 +281,6 @@ describe('Task detail components', () => {
// })

it('loads ingestion details in the ingestion component', async () => {
const { default: IngestionTaskDetails } = await import(
'@/components/Orchestration/ingestion/IngestionTaskDetails.vue'
)
await seedWorkspace()

const wrapper = shallowMount(IngestionTaskDetails as any, {
Expand All @@ -284,9 +301,6 @@ describe('Task detail components', () => {
})

it('closes the ingestion delete dialog when deletion is cancelled', async () => {
const { default: IngestionTaskDetails } = await import(
'@/components/Orchestration/ingestion/IngestionTaskDetails.vue'
)
await seedWorkspace()

const wrapper = shallowMount(IngestionTaskDetails as any, {
Expand All @@ -309,9 +323,6 @@ describe('Task detail components', () => {
})

it('closes the data-product delete dialog when deletion is cancelled', async () => {
const { default: SimpleProductTaskDetails } = await import(
'@/components/Orchestration/data-products/SimpleProductTaskDetails.vue'
)
await seedWorkspace()

const wrapper = shallowMount(SimpleProductTaskDetails as any, {
Expand All @@ -335,9 +346,6 @@ describe('Task detail components', () => {
})

it('closes the quality edit dialog after a successful update', async () => {
const { default: QualityTaskDetails } = await import(
'@/components/Orchestration/monitoring/QualityTaskDetails.vue'
)
await seedWorkspace()

const wrapper = shallowMount(QualityTaskDetails as any, {
Expand All @@ -359,9 +367,6 @@ describe('Task detail components', () => {
})

it('closes the quality delete dialog when deletion is cancelled', async () => {
const { default: QualityTaskDetails } = await import(
'@/components/Orchestration/monitoring/QualityTaskDetails.vue'
)
await seedWorkspace()

const wrapper = shallowMount(QualityTaskDetails as any, {
Expand Down
Loading