Skip to content

Commit

Permalink
Merge branch 'main' into station-editor
Browse files Browse the repository at this point in the history
  • Loading branch information
maaikelimper authored Sep 15, 2023
2 parents c945e49 + 5d525e2 commit d231207
Show file tree
Hide file tree
Showing 16 changed files with 766 additions and 450 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/basic_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
run: docker-compose -f test/docker-compose.yml up -d

- name: Wait for service to start
run: sleep 20
run: sleep 30

- name: Check status code
run: |
Expand All @@ -27,4 +27,10 @@ jobs:
echo "Request failed with status code:"
echo ${status_code}
exit 1
fi
fi
- name: failed tests 🚩
if: ${{ failure() }}
run: |
echo "check docker logs"
docker-compose -f test/docker-compose.yml logs
62 changes: 62 additions & 0 deletions .github/workflows/ghcr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# GitHub recommends pinning actions to a commit SHA.
# To get a newer version, you will need to update the SHA.
# You can also reference a tag or branch, but the action may change without warning.

#
name: Create and publish a Docker image on gchr.io

#push on main and on published
on:
push:
branches:
- main
release:
types: [published]

# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
permissions:
contents: read
packages: write
#
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
- name: Build and push Docker image
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: webapp
push: true
tags: |
${{ steps.meta.outputs.tags }}
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
labels: ${{ steps.meta.outputs.labels }}
3 changes: 3 additions & 0 deletions webapp/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
FROM node:lts-alpine

# current version
LABEL version="1.0b5"

# Set the working directory inside the container
WORKDIR /wis2box-webapp

Expand Down
4 changes: 4 additions & 0 deletions webapp/config/HomeContent.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<!DOCTYPE html>
<html lang="en">

</html>
50 changes: 41 additions & 9 deletions webapp/src/components/DownloadButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,61 @@ import { VBtn } from 'vuetify/lib/components/index.mjs';
export default defineComponent({
name: 'DownloadButton',
props: {
fileUrl: {
fileName: {
type: String,
required: true,
},
fileUrl: {
type: String,
required: false,
default: '',
},
data: {
type: String,
required: false,
default: '',
},
},
components: {
VBtn
},
setup(props) {
// Extract the file name from the URL
const fileName = props.fileUrl.split('/').pop();
// function to download file
const downloadFile = () => {
// Create a temporary anchor element to initiate the download
const link = document.createElement('a');
link.href = props.fileUrl;
link.target = '_blank';
// Programmatically trigger the click event on the link to start the download
link.click();
if( props.fileUrl != '' ) {
//console.log("Downloading file from URL: " + props.fileUrl)
link.href = props.fileUrl;
link.target = '_blank';
// Programmatically trigger the click event on the link to start the download
link.click();
// Clean up
URL.revokeObjectURL(link.href);
}
else if( props.data != '' ) {
//console.log("Downloading file from data: " + props.data)
// Decode the base64 encoded data
const decodedData = atob(props.data);
// Convert the decoded data to a Uint8Array
const uint8Array = new Uint8Array(decodedData.length);
for (let i = 0; i < decodedData.length; ++i) {
uint8Array[i] = decodedData.charCodeAt(i);
}
// Create a Blob with the Uint8Array data
const blob = new Blob([uint8Array], { type: 'application/octet-stream' });
link.href = URL.createObjectURL(blob);
link.download = props.fileName;
// Programmatically trigger the click event on the link to start the download
link.click();
// Clean up
URL.revokeObjectURL(link.href);
}
else {
console.log("No fileURL or data provided");
}
};
return {
fileName,
downloadFile
};
},
Expand Down
36 changes: 36 additions & 0 deletions webapp/src/components/HomePage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<template>
<v-card>
<v-card-title class="big-title">
Welcome to WIS2 in a box!
</v-card-title>
<v-card-item>
At this page you can submit FM 12 SYNOP bulletin and monitor notifications from topics found in your wis2box.
</v-card-item>
<v-card-item v-html="homeContent"></v-card-item>
</v-card>
</template>

<script setup>
import { ref, onMounted } from 'vue';
const homeContent = ref('If you encounter any issues, please contact: <a href = "mailto: abc@example.com">abc@example.com</a>')
if (import.meta.env.VITE_HOME_CONTENT_PATH != undefined) {
onMounted(async () => {
const response = await fetch(import.meta.env.VITE_HOME_CONTENT_PATH);
if (response.ok) {
homeContent.value = await response.text();
}
});
}
</script>

<style scoped>
.big-title {
font-size: 1.4rem;
font-weight: 700;
}
</style>
38 changes: 29 additions & 9 deletions webapp/src/components/InspectBufrButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
<v-card class="inspect-content">
<v-card-title>{{ fileName }}</v-card-title>
<v-card-text>
<div v-if="itemsInBufr.length === 0">
<!-- Display a message when itemsInBufr is empty -->
<p>No items found in bufr</p>
</div>
<div v-for="(item, index) in itemsInBufr" :key="index" class="item-container">
<div v-for="(value, key) in item" :key="key" class="key-value-pair">
<span class="key">{{ key }}:</span> {{ value }}
Expand All @@ -26,10 +30,20 @@ import { VCard, VCardTitle, VCardText, VCardItem, VForm, VTextarea, VBtn, VSelec
export default defineComponent({
name: 'InspectBufrButton',
props: {
fileUrl: {
fileName: {
type: String,
required: true,
},
fileUrl: {
type: String,
required: false,
default: '',
},
data: {
type: String,
required: false,
default: '',
},
},
components: {
VCard,
Expand All @@ -42,8 +56,6 @@ export default defineComponent({
VSelect,
},
setup(props) {
// Extract the file name from the URL
const fileName = props.fileUrl.split('/').pop();
const itemsInBufr = ref([]);
const dialog = ref(false);
// function to create new object and to add to store
Expand Down Expand Up @@ -91,9 +103,17 @@ export default defineComponent({
const callInspect = async () => {
// set items_from_bufr back to empty array
itemsInBufr.value = [];
var payload = {
let payload;
if (props.fileUrl !== '') {
payload = {
inputs: {
data_url: props.fileUrl
}
};
} else if (props.data !== '') {
payload = {
inputs: {
data_url: props.fileUrl
data: props.data
}
};
const inspectUrl = `${import.meta.env.VITE_API_URL}/processes/wis2box-bufr2geojson/execution`
Expand All @@ -110,23 +130,23 @@ export default defineComponent({
console.error('HTTP error', response.status);
} else {
const data = await response.json();
console.log(data);
//console.log(data);
if (data.items) {
// Use Array.map to create a new array of the items in the bufr file
itemsInBufr.value = data.items.map(item => {
if (item.properties) {
return item.properties;
}
});
console.log(itemsInBufr.value);
//console.log(itemsInBufr.value);
}
}
};
return {
fileName,
itemsInBufr,
inspectFile,
dialog
dialog,
fileName: props.fileName
};
},
});
Expand Down
62 changes: 27 additions & 35 deletions webapp/src/components/MonitoringPage.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<template>
<v-card-title class="big-title">Monitoring Dashboard</v-card-title>

<!-- Drop down selection for the dataset the user wants to monitor -->
<v-select label="Choose a dataset to monitor" v-model="selectedTitle" :items="titles" v-if="titles.length"></v-select>
<v-card-item>
<!-- Drop down selection for the topic the user wants to monitor -->
<v-select label="Choose a topic to monitor" v-model="selectedTopic" :items="topics" v-if="topics.length"></v-select>

</v-card-item>

<!-- Search bar to search for a WSI and only monitor that station -->
<v-text-field label="Search a station to monitor (optional)" clearable/>

<!-- Dashboard visualising the notifications of the dataset selected -->
<NotificationDashboard :topicHierarchy="datasets[selectedTitle]" v-if="selectedTitle"/>

<!-- Dashboard visualising the notifications of the topic selected -->
<NotificationDashboard :topicHierarchy="selectedTopic" v-if="selectedTopic" />
</template>

<script>
Expand All @@ -26,30 +26,24 @@ export default defineComponent({
data() {
return {
// Options for user to filter the dashboard (surface, upper air, etc)
datasets: {},
topics: [],
// Title selected by the user, used to get the topic hierarchy
// from the datasets dictionary
selectedTitle: null
}
},
computed: {
// Get titles (the keys) from datasets dictionary by using Object.keys,
// used for the selection at the top of the page
titles() {
return Object.keys(this.datasets);
// from the topics array
selectedTopic: null
}
},
methods: {
// Method to get topic hierarchies and corresponding titles from the
// discovery metadata, in order to allow the user to select the dataset
// discovery metadata, in order to allow the user to select the topic
// dsisplayed in the dashboard
async getDatasets() {
async getTopics() {
if (import.meta.env.VITE_TEST_MODE === "true" || import.meta.env.VITE_API_URL == undefined) {
console.log("Use test datasets");
this.datasets = {
"Synoptic weather observations from Romania": "rou/rnimh/data/core/weather/surface-based-observations/synop",
"Surface weather observations from Malawi": "mwi/mwi_met_centre/data/core/weather/surface-based-observations/synop"
};
console.log("Use test topics");
this.topics = [
"rou/rnimh/data/core/weather/surface-based-observations/synop",
"mwi/mwi_met_centre/data/core/weather/surface-based-observations/synop",
"tst/topic/with/zero/notifications"
];
}
else {
const apiUrl = `${import.meta.env.VITE_API_URL}/collections/discovery-metadata/items?f=json`;
Expand All @@ -63,15 +57,13 @@ export default defineComponent({
const data = await response.json();
// If the features object is in the data
if (data.features) {
// Populate the datasets dictionary with the titles as keys
// and corresponding topic hierarchies as items
this.datasets = data.features.reduce((acc, feature) => {
acc[feature.properties.title] = feature.properties["wmo:topicHierarchy"];
// acc: accumulator object, used to iteratively build
// this datasets dictionary
return acc;
}, {});
console.log("Datasets:", this.datasets);
// Use Array.map to create a new array of the topic hierarchies
this.topics = data.features.map(feature => {
if (feature.properties && feature.properties['wmo:topicHierarchy']) {
return feature.properties['wmo:topicHierarchy']
}
});
console.log("Topics:", this.topics);
}
else {
console.error("API response does not have features property");
Expand All @@ -85,8 +77,8 @@ export default defineComponent({
}
},
mounted() {
// Get topic hierarchies and titles for the user to select a dataset
this.getDatasets();
// Get topic hierarchies and titles for the user to select a topic
this.getTopics();
}
});
</script>
Expand Down
Loading

0 comments on commit d231207

Please sign in to comment.