diff --git a/.gitignore b/.gitignore
index 11e3992e..9a467729 100644
--- a/.gitignore
+++ b/.gitignore
@@ -147,6 +147,7 @@ dist
# IDEs
.vscode
+.idea
# Cypress related files
**/cypress.env.json
@@ -160,4 +161,4 @@ dist
**/token.json
**/local-dev/**
**/*copy.json
-testing/cypress.config copy.ts
\ No newline at end of file
+testing/cypress.config copy.ts
diff --git a/app/.env.example b/app/.env.example
index 62cffa36..c4d12ffa 100644
--- a/app/.env.example
+++ b/app/.env.example
@@ -4,7 +4,8 @@
NUXT_SITEMINDER_LOGOUT_URL="https://logontest7.gov.bc.ca/clp-cgi/logoff.cgi"
#vaults API
-NUXT_NAMEX_API_URL="https://namex-dev.apps.silver.devops.gov.bc.ca"
+NUXT_NAMEX_API_GW_URL="https://test.api.connect.gov.bc.ca/namex-dev"
+NUXT_NAMEX_API_KEY=
NUXT_NAMEX_API_VERSION="/api/v1"
NUXT_NAMEX_ADMIN_URL = "https://namex-solr-dev.apps.silver.devops.gov.bc.ca/"
diff --git a/app/devops/vaults.env b/app/devops/vaults.env
index 91fe7801..28b24e00 100644
--- a/app/devops/vaults.env
+++ b/app/devops/vaults.env
@@ -5,7 +5,8 @@ NUXT_SITEMINDER_LOGOUT_URL="op://web-url/$APP_ENV/siteminder/SITEMINDER_LOGOUT_U
NUXT_NAMEX_ADMIN_URL="op://web-url/$APP_ENV/namex-examination/NAMEX_ADMIN_URL"
#vaults API
-NUXT_NAMEX_API_URL="op://API/$APP_ENV/namex-api/NAMEX_API_URL"
+NUXT_NAMEX_API_GW_URL="op://API/$APP_ENV/namex-api/NAMEX_API_GW_URL"
+NUXT_NAMEX_API_KEY="op://API/$APP_ENV/namex-api/NAMEX_API_KEY"
NUXT_NAMEX_API_VERSION="op://API/$APP_ENV/namex-api/NAMEX_API_VERSION"
#vaults keycloak
diff --git a/app/nuxt.config.ts b/app/nuxt.config.ts
index cc911c44..c21429b9 100644
--- a/app/nuxt.config.ts
+++ b/app/nuxt.config.ts
@@ -18,7 +18,6 @@ export default defineNuxtConfig({
'@nuxt/content',
'@nuxtjs/tailwindcss',
'@pinia/nuxt',
- 'nuxt-vitest',
],
css: ['@/assets/css/main.scss'],
typescript: {
@@ -50,7 +49,8 @@ export default defineNuxtConfig({
firebaseAuthDomain: process.env.NUXT_AUTH_DOMAIN,
firebaseProjectId: process.env.NUXT_PROJECT_ID,
firebaseAppId: process.env.NUXT_APP_ID,
- namexAPIURL: process.env.NUXT_NAMEX_API_URL,
+ namexAPIURL: process.env.NUXT_NAMEX_API_GW_URL,
+ namexAPIKey: process.env.NUXT_NAMEX_API_KEY,
namexAPIVersion: process.env.NUXT_NAMEX_API_VERSION,
namexAdminURL: process.env.NUXT_NAMEX_ADMIN_URL,
keycloakAuthUrl: process.env.NUXT_KEYCLOAK_AUTH_URL,
diff --git a/app/package-lock.json b/app/package-lock.json
index 0178aa1d..c5ea8989 100644
--- a/app/package-lock.json
+++ b/app/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "name-examination",
- "version": "1.2.39",
+ "version": "1.2.48",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "name-examination",
- "version": "1.2.39",
+ "version": "1.2.48",
"hasInstallScript": true,
"dependencies": {
"@headlessui/vue": "0.0.0-insiders.01a34cb",
diff --git a/app/package.json b/app/package.json
index 4e991a38..534d1030 100644
--- a/app/package.json
+++ b/app/package.json
@@ -1,6 +1,6 @@
{
"name": "name-examination",
- "version": "1.2.47",
+ "version": "1.2.49",
"private": true,
"scripts": {
"build": "nuxt generate",
diff --git a/app/store/examine/conflicts.ts b/app/store/examine/conflicts.ts
index 4bfc5b69..d683baca 100644
--- a/app/store/examine/conflicts.ts
+++ b/app/store/examine/conflicts.ts
@@ -1,5 +1,6 @@
import type { ConflictListItem } from '~/types'
import { getConflicts } from '~/util/namex-api'
+import { highlightWord } from '~/util/html/highlight'
export const useConflicts = defineStore('conflicts', () => {
@@ -83,31 +84,44 @@ export const useConflicts = defineStore('conflicts', () => {
}
function highlightNameChoices(entry: any): string {
- let result = entry.name
- if (entry.highlighting) {
- if (entry.highlighting.stems) {
- entry.highlighting.stems.forEach((stem: string) => {
- const re = new RegExp(stem, 'gi')
- result = result.replace(re, (match: any) => `${match}`)
- })
+ const name: string = entry?.name ?? ''
+ const highlighting = entry?.highlighting
+
+ // If we have nothing to highlight, keep original text intact
+ if (!name || !highlighting) {
+ return name
+ }
+
+ // Split into word and whitespace tokens so we preserve spacing exactly
+ const tokens = name.split(/(\s+)/)
+
+ const exactList: string[] = Array.isArray(highlighting.exact) ? highlighting.exact : []
+ const synonymList: string[] = Array.isArray(highlighting.synonyms) ? highlighting.synonyms : []
+ const stemList: string[] = Array.isArray(highlighting.stems) ? highlighting.stems : []
+
+ const applyFirstMatchingCategory = (word: string): string => {
+ // exact > synonym > stem
+ for (const exact of exactList) {
+ const highlighted = highlightWord(exact, word, 'exact-highlight')
+ if (highlighted !== word) return highlighted
}
- if (entry.highlighting.synonyms) {
- entry.highlighting.synonyms.forEach((synonym: string) => {
- const re = new RegExp(synonym, 'gi')
- result = result.replace(re, (match: any) => `${match}`)
- })
+ for (const synonym of synonymList) {
+ const highlighted = highlightWord(synonym, word, 'synonym-highlight')
+ if (highlighted !== word) return highlighted
}
- if (entry.highlighting.exact) {
- entry.highlighting.exact.forEach((exact: string) => {
- const re = new RegExp(exact, 'gi')
- result = result.replace(re, (match: any) => `${match}`)
- })
+ for (const stem of stemList) {
+ const highlighted = highlightWord(stem, word, 'stem-highlight')
+ if (highlighted !== word) return highlighted
}
+
+ return word
}
- return result
+ return tokens
+ .map((token) => (token.trim().length === 0 ? token : applyFirstMatchingCategory(token)))
+ .join('')
}
async function initialize(searchQuery: string, exactPhrase: string) {
@@ -163,7 +177,7 @@ export const useConflicts = defineStore('conflicts', () => {
}
/** Reset selectedConflicts and comparedConflicts and save existing data */
- function disableAutoAdd () {
+ function disableAutoAdd() {
if (!autoAdd.value) {
const initialRun = (prevSelectedConflicts.value.length === 0 && prevComparedConflicts.value.length === 0)
for (const conflict of selectedConflicts.value) {
@@ -180,7 +194,7 @@ export const useConflicts = defineStore('conflicts', () => {
}
/** Reassign selectedConflicts and comparedConflicts */
- function enableAutoAdd () {
+ function enableAutoAdd() {
if (autoAdd.value) {
selectedConflicts.value = prevSelectedConflicts.value
comparedConflicts.value = prevComparedConflicts.value
@@ -205,6 +219,6 @@ export const useConflicts = defineStore('conflicts', () => {
enableAutoAdd,
autoAdd,
firstConflictItem,
- syncSelectedAndComparedConflicts,
+ syncSelectedAndComparedConflicts
}
})
diff --git a/app/util/html/highlight.ts b/app/util/html/highlight.ts
new file mode 100644
index 00000000..cfea1ea5
--- /dev/null
+++ b/app/util/html/highlight.ts
@@ -0,0 +1,7 @@
+const escapeRegExp = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+
+export const highlightWord = (word: string, text: string, highlightCss: string) => {
+ if (!word) return text
+ const re = new RegExp(escapeRegExp(word), 'gi')
+ return text.replace(re, (match: string) => `${match}`)
+}
diff --git a/app/util/namex-api.ts b/app/util/namex-api.ts
index ca109cd6..2e7c5048 100644
--- a/app/util/namex-api.ts
+++ b/app/util/namex-api.ts
@@ -29,6 +29,7 @@ async function callNamexApi(url: URL, options?: object, headers?: object) {
headers: {
Authorization: `Bearer ${token}`,
'App-Name': packageInfo.name,
+ 'X-Apikey': useRuntimeConfig().public.namexAPIKey || '',
...headers,
},
...(options ? options : {}),
@@ -41,9 +42,10 @@ async function callNamexApi(url: URL, options?: object, headers?: object) {
*/
export function getNamexApiUrl(endpoint: string): URL {
const config = useRuntimeConfig().public
+ const base = config.namexAPIURL
return new URL(
- config.namexAPIVersion + endpoint,
- config.namexAPIURL as string
+ config.namexAPIVersion.replace(/^\//, '') + endpoint,
+ base.endsWith('/') ? base : base + '/' as string
)
}