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
16 changes: 8 additions & 8 deletions app/components/ComboSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ import {
} from '@headlessui/vue'
import { CheckIcon, ChevronUpDownIcon } from '@heroicons/vue/20/solid'

const { options, multiple = false, optionsDisplay = (option: any) => option } = defineProps<{
modelValue: any
options: ComputedRef<Array<any>>
/** Whether multiple options can be selected */
multiple?: boolean
/** Function called for getting the display string for a given option */
optionsDisplay?: (option: any) => string
}>()
const { options, multiple, optionsDisplay = (option: any) => option} = defineProps<{
modelValue: any
options: ComputedRef<Array<any>>
/** Whether multiple options can be selected */
multiple?: boolean
/** Function called for getting the display string for a given option */
optionsDisplay?: (option: any) => string
}>()

const query = ref('')
const filteredOptions = computed(() =>
Expand Down
1 change: 0 additions & 1 deletion app/components/app_footer/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
<script setup lang="ts">
const links = [
{ text: 'Home', route: '/', target: '_self' },
{ text: 'Release Notes', route: 'https://www.release-notes.bcregistry.gov.bc.ca' },
{ text: 'Disclaimer', route: 'https://www2.gov.bc.ca/gov/content/home/disclaimer' },
{ text: 'Privacy', route: 'https://www2.gov.bc.ca/gov/content/home/privacy' },
{ text: 'Accessibility', route: 'https://www2.gov.bc.ca/gov/content/home/accessibility' },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,16 @@ function setDefaultInputValues() {
examine.addEditAction({
validate() {
let isValid = true
if (examine.expiryDate && !expiry.value) {
expiryDateErrorText.value = 'Expiry date is required'
isValid = false
if (examine.expiryDate) {
if (expiry.value) {
isValid = DateTime.fromISO(expiry.value).startOf('day') >= DateTime.now().startOf('day')
expiryDateErrorText.value = isValid ? '' : 'Expiry date must be today or later';
} else {
expiryDateErrorText.value = 'Expiry date is required'
isValid = false
}
}

if (consentFlag.value === ConsentFlag.Received && !consentDate.value) {
consentDateErrorText.value = 'Consent date is required'
isValid = false
Expand Down
7 changes: 6 additions & 1 deletion app/components/search/ResultsBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@
<LoadingSpinner v-if="search.isLoading" />
</div>

<div v-if="search.isLoading"
class="absolute bottom-1/2 right-1/2 translate-x-1/2 translate-y-1/2 transform">
<LoadingSpinner />
</div>

<PopupDialog :show="showDateDialog">
<template #title>Choose a Date Range</template>
<SearchDateForm
Expand Down Expand Up @@ -190,7 +195,7 @@ const layout: ILayout = {
dropdown: Object.values(Submitted),
clickable: {
icon: computed(() =>
search.submittedDateOrder === 'asc' ? ArrowDownIcon : ArrowUpIcon
search.submittedDateOrder === 'asc' ? ArrowUpIcon : ArrowDownIcon
),
onClick: search.toggleSubmittedDateOrder,
},
Expand Down
113 changes: 90 additions & 23 deletions app/devops/cloudbuild-pr.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
steps:
# install / setup ci
# Install / setup CI
- name: node:20.5.1
entrypoint: npm
args: ['install']
dir: app # <-- ADD THIS

# setup .env
# Setup .env
- name: 'bash'
script: |
#!/usr/bin/env bash
cp .env.example .env
dir: app # <-- ADD THIS

#
# Generate the static site
#
- name: node:20.5.1
entrypoint: npm
env:
Expand All @@ -21,38 +21,105 @@ steps:
- 'NUXT_PROJECT_ID=$_NUXT_PROJECT_ID'
- 'NUXT_APP_ID=$_NUXT_APP_ID'
args: ['run', 'build']
dir: app # <-- ADD THIS

#
# Deploy to firebase channel, using the PR #
# store log to /workspace to get the channel URL
#
# Deploy to Firebase channel using the PR #
- name: gcr.io/yfthig-dev/firebase
entrypoint: bash
args: ['-c', 'firebase hosting:channel:deploy --project=yfthig-dev PR-$_PR_NUMBER > /workspace/firebase-deploy.txt']
dir: app # <-- ADD THIS

# Generate GitHub App installation token
- id: "Generate GitHub App token"
name: python:3.11
entrypoint: bash
args:
- -c
- |
pip install pyjwt cryptography requests
python <<EOF
import os, time, jwt, requests
from cryptography.hazmat.primitives import serialization

# Load GitHub App info from env
app_id = os.environ["GITHUB_APP_ID"]
installation_id = os.environ["GITHUB_INSTALLATION_ID"]
private_key = os.environ["GITHUB_APP_PRIVATE_KEY"]

# Build JWT
now = int(time.time())
payload = {
"iat": now,
"exp": now + 540, # 9 minutes
"iss": app_id,
}
key = serialization.load_pem_private_key(private_key.encode(), password=None)
jwt_token = jwt.encode(payload, key, algorithm="RS256")

# Exchange for installation token
headers = {"Authorization": f"Bearer {jwt_token}", "Accept": "application/vnd.github.v3+json"}
url = f"https://api.github.com/app/installations/{installation_id}/access_tokens"
r = requests.post(url, headers=headers)
r.raise_for_status()
token = r.json()["token"]

# Write token for next steps
with open("/workspace/github_token.txt", "w") as f:
f.write(token)
EOF
secretEnv:
- GITHUB_APP_PRIVATE_KEY
- GITHUB_APP_ID
- GITHUB_INSTALLATION_ID

#
# Update the PR with the temporary URL
#
- id: "Update the PR"
name: gcr.io/cloud-builders/curl
entrypoint: bash
args:
- -c
- |
# Read from "/workspace"
cat /workspace/firebase-deploy.txt
url=`cat /workspace/firebase-deploy.txt| grep 'Channel URL' | grep -Eo "https://[a-zA-Z0-9./?=_%:-]*"`
echo "this is the body:"
echo '{"body": "Temporary Url for review:'"$url"'"}'
# Read Firebase URL
url=$(grep 'Channel URL' /workspace/firebase-deploy.txt | grep -Eo "https://[a-zA-Z0-9./?=_%:-]*")
echo "Posting PR comment with URL: $url"

# Read GitHub App installation token
GITHUB_TOKEN=$(cat /workspace/github_token.txt)

curl -X POST \
https://api.github.com/repos/bcgov/name-examination/issues/$_PR_NUMBER/comments \
--header "Authorization: token $$GITHUB_TOKEN" \
--header "Accept: application/vnd.github.v3+json" \
--data-binary '{"body": "Temporary Url for review: '"$url"'"}'

# Run smoke test workflow
- id: "Run Smoke Test"
name: gcr.io/cloud-builders/curl
entrypoint: bash
args:
- -c
- |
# Read Firebase URL
url=$(grep 'Channel URL' /workspace/firebase-deploy.txt | grep -Eo "https://[a-zA-Z0-9./?=_%:-]*")
echo "Triggering smoke test workflow with URL: $url"

# Read GitHub App installation token
GITHUB_TOKEN=$(cat /workspace/github_token.txt)

curl -X POST \
https://api.github.com/repos/bcgov/name-examination/issues/$_PR_NUMBER/comments \
--header "Authorization: Token $$TOKEN" \
--header "Accept: application/vnd.github.v3+json" \
--data-binary '{"body": "Temporary Url for review: '"$url"'"}'
secretEnv: ['TOKEN']
-H "Accept: application/vnd.github+json" \
-H "Authorization: token $$GITHUB_TOKEN" \
https://api.github.com/repos/bcgov/name-examination/actions/workflows/e2e.yml/dispatches \
-d '{"ref":"main","inputs":{"url_parameter":"'"$url"'"}}'

availableSecrets:
secretManager:
- versionName: projects/$PROJECT_ID/secrets/token-pr-review/versions/latest
env: 'TOKEN'
- versionName: projects/$PROJECT_ID/secrets/private-key-pr-review/versions/latest
env: 'GITHUB_APP_PRIVATE_KEY'
- versionName: projects/$PROJECT_ID/secrets/app-id-pr-review/versions/latest
env: 'GITHUB_APP_ID'
- versionName: projects/$PROJECT_ID/secrets/installation-id-pr-review/versions/latest
env: 'GITHUB_INSTALLATION_ID'

options:
dynamic_substitutions: true
dynamicSubstitutions: false
5 changes: 3 additions & 2 deletions app/package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
{
"name": "name-examination",
"version": "1.2.44",
"version": "1.2.47",
"private": true,
"scripts": {
"build": "nuxt generate",
"build-check": "nuxt generate",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
Expand Down Expand Up @@ -78,4 +79,4 @@
"engines": {
"node": "=20.5.1"
}
}
}
27 changes: 14 additions & 13 deletions app/pages/Stats.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@
<div class="font-semibold text-center">Total Examined Names: {{ numRecords }}</div>
<div class="flex items-center space-x-2">
<div class="flex items-center space-x-1">
<input
id="stats-checkbox"
class="h-4 w-4"
v-model="myStats"
<input
id="stats-checkbox"
class="h-4 w-4"
v-model="myStats"
type="checkbox"
data-testid="statsCheckbox"
>
<label for="stats-checkbox" class="font-bold">My Stats</label>
</div>
<div class="timespan-input align-baseline space-x-1">
<label for="timespan" class="font-bold align-baseline">Hours:&nbsp;</label>
<TextInput
id="timespan"
ref="numberinput"
v-model="timespan"
type="number"
class="!w-24"
<TextInput
id="timespan"
ref="numberinput"
v-model="timespan"
type="number"
class="!w-24"
data-testid="statsHoursInput"
/>
<IconButton @click="fetchStats" data-testid="getStatsBtn">
Expand Down Expand Up @@ -99,8 +99,9 @@
</tr>
</tbody>
</table>
<div class="absolute bottom-1/2 right-1/2 translate-x-1/2 translate-y-1/2 transform">
<LoadingSpinner v-if="isLoading" />
<div v-if="isLoading"
class="absolute bottom-1/2 right-1/2 translate-x-1/2 translate-y-1/2 transform">
<LoadingSpinner />
</div>

</div>
Expand Down Expand Up @@ -171,7 +172,7 @@ export default {
/**
* Determines the CSS class based on the provided state.
* @param {string} state - The state value used to determine the CSS class.
* @return {string | undefined} Returns the CSS class corresponding to the provided state.
* @return {string | undefined} Returns the CSS class corresponding to the provided state.
* If the state does not match any condition, returns undefined.
*/
function getClass(state) {
Expand Down
4 changes: 2 additions & 2 deletions app/store/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ export const useSearchStore = defineStore('search', () => {
const isLoading = ref(true)

const formattedSearchParams = computed(() => {
const params = {
order: `priorityCd:desc,submittedDate:${submittedDateOrder.value}`,
const params = {
order: `submittedDate:${submittedDateOrder.value}`,
queue:
filters[SearchColumns.Status] === StatusSearchFilter.All
? ''
Expand Down
4 changes: 3 additions & 1 deletion app/tests/store/search.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ describe('Search store tests', () => {
search.filters[SearchColumns.ApplicantFirstName] = testName

let expectedParams = new URLSearchParams({
order: 'priorityCd:desc,submittedDate:asc',
// this is to match current code, verify with business if this is correct
// order: 'priorityCd:desc,submittedDate:asc',
order: 'submittedDate:asc',
queue: Status.Hold,
consentOption: ConsentRequired.All,
ranking: Priority.All,
Expand Down
Loading