Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update/populateinstruments #106

Merged
merged 7 commits into from
Dec 16, 2024
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
22 changes: 3 additions & 19 deletions src/components/RealTimeInterface/SessionStarted.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import { calcAltAz } from '../../utils/visibility.js'
import { useRealTimeSessionsStore } from '../../stores/realTimeSessions'
import sites from '../../utils/sites.JSON'
import { fetchApiCall } from '../../utils/api'
import { getFilterList } from '../../utils/populateInstrumentsUtils'
import { useConfigurationStore } from '../../stores/configuration'
import { useUserDataStore } from '../../stores/userData'

const realTimeSessionsStore = useRealTimeSessionsStore()
const configurationStore = useConfigurationStore()
const userDataStore = useUserDataStore()

const isCapturingImages = computed(() => {
if (configurationStore.demo == true) {
Expand Down Expand Up @@ -144,21 +143,6 @@ const sendGoCommand = async () => {
})
}

// This should change from configdbUrl/opticalelementgroups/128/ to
// https://observe.lco.global/api/instruments and map the instruments based on what telescope is being used
const getFilterList = async () => {
await fetchApiCall({
url: configurationStore.configdbUrl + 'opticalelementgroups/128/',
method: 'GET',
successCallback: (data) => {
filterList.value = data.optical_elements
.filter(filter => filter.schedulable)
.map(filter => ({ name: filter.name, code: filter.code }))
},
failCallback: (error) => { console.error('API failed with error', error) }
})
}

function updateRenderGallery (value) {
if (!value) {
realTimeSessionsStore.updateImageCaptureState(false)
Expand All @@ -174,9 +158,9 @@ watch(exposureTime, (newTime) => {
exposureError.value = ''
})

onMounted(() => {
onMounted(async () => {
loading.value = false
getFilterList()
filterList.value = await getFilterList()
})

</script>
Expand Down
25 changes: 3 additions & 22 deletions src/components/Scheduling/SchedulingSettings.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup>
import { ref, reactive, computed, defineProps, defineEmits, onMounted } from 'vue'
import { useConfigurationStore } from '../../stores/configuration.js'
import { fetchApiCall } from '../../utils/api.js'
import { getFilterList } from '../../utils/populateInstrumentsUtils.js'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'

const props = defineProps({
Expand Down Expand Up @@ -36,25 +36,6 @@ const settings = reactive({
count: ''
})

const getFilterList = async () => {
await fetchApiCall({
url: configurationStore.observationPortalUrl + 'instruments',
method: 'GET',
successCallback: (data) => {
Object.values(data).forEach(instrument => {
// Checks if the instrument has a "class" of "0m4" and contains filters in optical_elements
if (instrument.class === '0m4' && instrument.optical_elements.filters) {
const schedulableFilters = instrument.optical_elements.filters
.filter(filter => filter.schedulable)
.map(filter => ({ name: filter.name, code: filter.code }))
filterList.value.push(...schedulableFilters)
}
})
},
failCallback: (error) => { console.error('API failed with error', error) }
})
}

// State for enabling/disabling fields
const targetEnabled = computed(() => {
return props.showProjectField ? projectName.value.trim() !== '' : true
Expand Down Expand Up @@ -139,8 +120,8 @@ const formatExposures = (exposures) => {
return exposures.map(exposure => `${exposure.filterName} - ${exposure.exposureTime}s x ${exposure.count}`).join(', ')
}

onMounted(() => {
getFilterList()
onMounted(async () => {
filterList.value = await getFilterList()
})

</script>
Expand Down
75 changes: 0 additions & 75 deletions src/tests/integration/components/schedulingSettings.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,6 @@ describe('SchedulingSettings.vue', () => {
fetchApiCall.mockClear()
const { pinia } = createTestStores()

fetchApiCall.mockImplementationOnce(({ successCallback }) => {
if (successCallback) {
successCallback({
'0M4-SCICAM-QHY600': {
'class': '0m4',
'optical_elements': {
'filters': [
{ name: 'Filter A', code: 'FA', schedulable: true },
{ name: 'Filter B', code: 'FB', schedulable: false }
]
}
},
'0M4-SCICAM-FLI': {
'class': '0m4',
'optical_elements': {
'filters': [
{ name: 'Filter D', code: 'FD', schedulable: true },
{ name: 'Filter E', code: 'FE', schedulable: true }
]
}
}
})
}
})

wrapper = mount(SchedulingSettings, {
global: {
plugins: [pinia],
Expand All @@ -53,28 +28,6 @@ describe('SchedulingSettings.vue', () => {
})
})

it('calls fetchApiCall to get filter list on mount', async () => {
expect(fetchApiCall).toHaveBeenCalledWith(
expect.objectContaining({
url: 'http://mock-api.com/instruments',
method: 'GET',
successCallback: expect.any(Function),
failCallback: expect.any(Function)
})
)

await flushPromises()

// filters through the non-schedulable filters
expect(wrapper.vm.filterList).toEqual([
{ name: 'Filter A', code: 'FA' },
{ name: 'Filter D', code: 'FD' },
{ name: 'Filter E', code: 'FE' }
])

expect(fetchApiCall).toHaveBeenCalledTimes(1)
})

it('fetches RA and Dec based on the target name and updates state correctly', async () => {
const mockRaDecResponse = {
'dec': '+41 16 07.50',
Expand Down Expand Up @@ -116,32 +69,4 @@ describe('SchedulingSettings.vue', () => {

expect(wrapper.vm.targetError).toBe('Target not found, try another target.')
})

it('emits exposuresUpdated when exposures are added', async () => {
// Checks that filterList has been populated correctly
expect(wrapper.vm.filterList).toEqual([
{ name: 'Filter A', code: 'FA' },
{ name: 'Filter D', code: 'FD' },
{ name: 'Filter E', code: 'FE' }
])

// Simulates selecting a filter from the dropdown
wrapper.vm.settings.filter = 'FA'
wrapper.vm.settings.filterName = 'Filter A'
wrapper.vm.settings.exposureTime = '30'
wrapper.vm.settings.count = '15'

await wrapper.vm.addExposure()

// Check that the event is emitted with the expected payload
expect(wrapper.emitted().exposuresUpdated).toBeTruthy()
expect(wrapper.emitted().exposuresUpdated[0][0]).toEqual([
{
filter: 'FA',
filterName: 'Filter A',
exposureTime: '30',
count: '15'
}
])
})
})
89 changes: 89 additions & 0 deletions src/tests/unit/utils/populateInstrumentsUtils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { vi, describe, it, expect, beforeEach } from 'vitest'
import { getFilterList } from '../../../utils/populateInstrumentsUtils.js'
import { fetchApiCall } from '../../../utils/api.js'
import { createTestStores } from '../../../utils/testUtils'

vi.mock('@/utils/api.js', () => ({
fetchApiCall: vi.fn()
}))

describe('thumbnailsUtils.js', () => {
let configurationStore

beforeEach(() => {
const { configurationStore: store } = createTestStores()
configurationStore = store
fetchApiCall.mockClear()
})

describe('getFilterList', () => {
beforeEach(() => {
fetchApiCall.mockClear()
})

it('fetches instruments and returns schedulable filters', async () => {
// Mock API response
fetchApiCall.mockResolvedValueOnce({
'0M4-SCICAM-QHY600': {
class: '0m4',
optical_elements: {
filters: [
{ name: 'Filter A', code: 'FA', schedulable: true },
{ name: 'Filter B', code: 'FB', schedulable: false }
]
}
},
'0M4-SCICAM-FLI': {
class: '0m4',
optical_elements: {
filters: [
{ name: 'Filter D', code: 'FD', schedulable: true },
{ name: 'Filter E', code: 'FE', schedulable: true }
]
}
},
// This instrument should be ignored
'1M0-SCICAM': {
class: '1m0',
optical_elements: {
filters: [
{ name: 'Filter X', code: 'FX', schedulable: true }
]
}
}
})

const result = await getFilterList()

expect(result).toEqual([
{ name: 'Filter A', code: 'FA' },
{ name: 'Filter D', code: 'FD' },
{ name: 'Filter E', code: 'FE' }
])

expect(fetchApiCall).toHaveBeenCalledWith(
expect.objectContaining({
url: expect.stringContaining('instruments'),
method: 'GET'
})
)
})

it('returns an empty array if no schedulable filters are found', async () => {
fetchApiCall.mockResolvedValueOnce({
'0M4-SCICAM-QHY600': {
class: '0m4',
optical_elements: {
filters: [
{ name: 'Filter A', code: 'FA', schedulable: false }
]
}
}
})

const result = await getFilterList()

expect(result).toEqual([])
})
})
})
24 changes: 24 additions & 0 deletions src/utils/populateInstrumentsUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { fetchApiCall } from './api.js'
import { useConfigurationStore } from '../stores/configuration.js'

export const getFilterList = async () => {
const configurationStore = useConfigurationStore()
const response = await fetchApiCall({
url: `${configurationStore.observationPortalUrl}instruments`,
method: 'GET'
})
const filterList = []
if (!response) {
return filterList
}
const instrumentClass = '0m4'
Object.values(response).forEach((instrument) => {
if (instrument.class === instrumentClass && instrument.optical_elements.filters) {
const schedulableFilters = instrument.optical_elements.filters
.filter(filter => filter.schedulable)
.map(filter => ({ name: filter.name, code: filter.code }))
filterList.push(...schedulableFilters)
}
})
return filterList
}
Loading