Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
05dbdb8
feat(address-service): use FIAS ID for address key generation in FIAS…
AleX83Xpert Oct 13, 2025
82d8dc4
feat(address-service): DOMA-12746 move address key generation to prov…
AleX83Xpert Dec 18, 2025
1a9dc70
feat(address-service): DOMA-12746 implement heuristics-based address …
AleX83Xpert Feb 12, 2026
9518b0f
test(address-service): DOMA-12746 add extractHeuristics mock calls to…
AleX83Xpert Feb 12, 2026
96fe3f3
fix(address-service): DOMA-12746 add onKeyDown handler to ResolveAddr…
AleX83Xpert Feb 12, 2026
5db825e
feat(address-service): DOMA-12746 refactor merge-duplicate-addresses …
AleX83Xpert Feb 13, 2026
c1c87de
fix(address-service): DOMA-12746 add safety check and error handling …
AleX83Xpert Feb 13, 2026
05fec90
refactor(address-service): DOMA-12746 use heuristic type constants in…
AleX83Xpert Feb 13, 2026
ae04293
docs(address-service): DOMA-12746 update migration guide and remove d…
AleX83Xpert Feb 13, 2026
b4fe60d
docs(address-service): DOMA-12746 remove unnecessary makemigrations s…
AleX83Xpert Feb 13, 2026
5da36fd
refactor(address-service): DOMA-12746 simplify mergeAddresses heurist…
AleX83Xpert Feb 13, 2026
fea8a75
refactor(address-service): DOMA-12746 improve findRootAddress to hand…
AleX83Xpert Feb 13, 2026
bacf9fd
refactor(address-service): DOMA-12746 add enabled filter to heuristic…
AleX83Xpert Feb 13, 2026
836dfec
refactor(address-service): DOMA-12746 return null instead of empty st…
AleX83Xpert Feb 13, 2026
311c356
refactor(address-service): DOMA-12746 migrate admin-ui buttons to @op…
AleX83Xpert Feb 13, 2026
598db05
refactor(address-service): DOMA-12746 add confirmation dialog to actu…
AleX83Xpert Feb 13, 2026
b7c4d96
refactor(address-service): DOMA-12746 add error handling and validati…
AleX83Xpert Feb 13, 2026
2087957
refactor(address-service): DOMA-12746 skip addresses with null possib…
AleX83Xpert Feb 13, 2026
4fa2cbb
refactor(address-service): DOMA-12746 fix pagination in merge-duplica…
AleX83Xpert Feb 13, 2026
c6789d4
refactor(address-service): DOMA-12746 add @open-condo/apollo-server-c…
AleX83Xpert Feb 13, 2026
9cedd30
refactor(address-service): DOMA-12746 update generateAddressKey retur…
AleX83Xpert Feb 13, 2026
45f5e1f
refactor(address-service): DOMA-12746 optimize upsertHeuristics to se…
AleX83Xpert Feb 13, 2026
ad6524b
refactor(address-service): DOMA-12746 migrate merge-duplicate-address…
AleX83Xpert Feb 13, 2026
a9d16b9
refactor(address-service): DOMA-12746 optimize migrate-address-keys-t…
AleX83Xpert Feb 18, 2026
87794e9
refactor(address-service): DOMA-12746 optimize create-address-heurist…
AleX83Xpert Feb 19, 2026
c3e3903
refactor(address-service): DOMA-12746 add possibleDuplicateOf field …
AleX83Xpert Feb 19, 2026
8759fd2
refactor(address-service): DOMA-12746 filter coordinate heuristics to…
AleX83Xpert Feb 19, 2026
e57c46e
refactor(address-service): DOMA-12746 add unit tests for heuristic-ba…
AleX83Xpert Feb 19, 2026
f7da2b9
test(address-service): DOMA-12746 add unit tests for ResolveAddressDu…
AleX83Xpert Feb 19, 2026
644a351
refactor(address-service): DOMA-12746 add race condition handling for…
AleX83Xpert Feb 19, 2026
27d2ed0
test(address-service): DOMA-12746 add unit tests for SuggestionKeysto…
AleX83Xpert Feb 20, 2026
491bf79
test(address-service): DOMA-12746 add unit tests for SearchKeystoneApp
AleX83Xpert Feb 20, 2026
3d7b46b
docs(address-service): DOMA-12746 update heuristics migration guide w…
AleX83Xpert Feb 24, 2026
d4d9230
refactor(address-service): DOMA-12746 remove fias_id key migration lo…
AleX83Xpert Feb 24, 2026
985b9fb
refactor(address-service): DOMA-12746 remove fias_id key parsing from…
AleX83Xpert Feb 24, 2026
f88f972
refactor(address-service): DOMA-12746 fix skip increment in merge-dup…
AleX83Xpert Feb 24, 2026
6ad973a
refactor(address-service): DOMA-12746 improve error handling in Resol…
AleX83Xpert Feb 24, 2026
5e48420
refactor(address-service): DOMA-12746 increase coordinate precision i…
AleX83Xpert Feb 24, 2026
12a2171
refactor(address-service): DOMA-12746 add latitude/longitude to coord…
AleX83Xpert Feb 24, 2026
41cf098
refactor(address-service): DOMA-12746 fix possibleDuplicateOf links c…
AleX83Xpert Feb 24, 2026
87e0fbe
test(condo): add createTestBillingIntegration calls to acquiring and …
AleX83Xpert Feb 24, 2026
d42b8bd
refactor(address-service): DOMA-12746 add heuristics extraction and u…
AleX83Xpert Feb 24, 2026
4844ef0
refactor(address-service): DOMA-12746 fix coordinate validation in Da…
AleX83Xpert Feb 25, 2026
0a49add
refactor(address-service): DOMA-12746 defer possibleDuplicateOf updat…
AleX83Xpert Feb 25, 2026
856c35a
refactor(address-service): DOMA-12746 add soft-delete check for addre…
AleX83Xpert Feb 25, 2026
076804d
refactor(address-service): DOMA-12746 wrap logger metadata in data ob…
AleX83Xpert Feb 25, 2026
3c78f32
refactor(address-service): DOMA-12746 add input validation and trim w…
AleX83Xpert Feb 25, 2026
6410c9b
refactor(address-service): DOMA-12746 fix coordinate validation in Go…
AleX83Xpert Feb 25, 2026
33dd637
refactor(address-service): DOMA-12746 skip merge when duplicate addre…
AleX83Xpert Feb 25, 2026
4fa49f6
refactor(address-service): DOMA-12746 add fias_id key parsing support…
AleX83Xpert Feb 25, 2026
cb35a56
refactor(address-service): DOMA-12746 fix coordinate validation in cr…
AleX83Xpert Feb 25, 2026
a37d1b1
refactor(address-service): DOMA-12746 add self-link check before upda…
AleX83Xpert Feb 25, 2026
2910d11
refactor(address-service): DOMA-12746 optimize merge-duplicate-addres…
AleX83Xpert Feb 25, 2026
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
138 changes: 123 additions & 15 deletions apps/address-service/admin-ui/index.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,72 @@
import { useMutation, gql } from '@apollo/client'
import { useMutation, useQuery, gql } from '@apollo/client'
import Logo from '@app/address-service/admin-ui/logo'
import { ItemId, AddNewItem } from '@open-keystone/app-admin-ui/components'
import React, { useCallback } from 'react'
import { useLocation } from 'react-router-dom'

import { Download } from '@open-condo/icons'
import { Download, Link } from '@open-condo/icons'
import { getClientSideSenderInfo } from '@open-condo/miniapp-utils/helpers/sender'
import { Button, Space } from '@open-condo/ui'
import '@open-condo/ui/dist/styles.min.css'

const TARGET_URL_PART = 'addresses'

const ICON_STYLE = {
cursor: 'pointer',
marginLeft: '20px',
}
const GET_ADDRESS_QUERY = gql`
query getAddress ($id: ID!) {
address: Address(where: { id: $id }) { id possibleDuplicateOf { id address } }
}
`

const RESOLVE_ADDRESS_DUPLICATE_MUTATION = gql`
mutation resolveAddressDuplicate ($data: ResolveAddressDuplicateInput!) {
result: resolveAddressDuplicate(data: $data) { status }
}
`

const ACTUALIZE_ADDRESSES_MUTATION = gql`
mutation actualizeAddresses ($data: ActualizeAddressesInput!) {
result: actualizeAddresses(data: $data) { successIds failures { addressId errorMessage } }
}
`

function extractErrorMessage (error, fallbackMessage) {
return error?.graphQLErrors?.[0]?.extensions?.message ||
error?.graphQLErrors?.[0]?.message ||
error?.networkError?.message ||
error?.message ||
fallbackMessage
}

const UpdateAddress = (props) => {
const location = useLocation()
const [actualizeAddress] = useMutation(ACTUALIZE_ADDRESSES_MUTATION)
const onClick = useCallback(() => {
// eslint-disable-next-line no-restricted-globals
const confirmed = confirm(
'Actualize this address?\n\n' +
'This will re-fetch the address data from the suggestion provider, ' +
'update the address key, meta, and heuristics, and reload the page.'
)
if (!confirmed) return

const sender = getClientSideSenderInfo()
const path = location.pathname.split('/').splice(2, 2)
const addressId = (path[0] === TARGET_URL_PART && path[1]) ? path[1] : null
if (!addressId) {
alert('Cannot detect address id from current URL')
return
}

const data = { dv: 1, sender, addresses: [{ id: addressId }] }
actualizeAddress({ variables: { data } })
.then(({ data }) => {
const { result: { successIds, failures } } = data
const result = data?.result
if (!result) {
alert('Actualize failed: empty response')
return
}

const { successIds, failures } = result
if (successIds.includes(addressId)) {
console.log('✅ Address actualized')
window.location.reload()
Expand All @@ -46,13 +82,80 @@
})
.catch((error) => {
console.error('Failed to actualize address', error)
alert(extractErrorMessage(error, 'Failed to actualize address'))
})
}, [location, actualizeAddress])

return location.pathname.indexOf(`${TARGET_URL_PART}/`) !== -1 && (
<span style={ICON_STYLE} onClick={onClick}>
<Download/>
</span>
<Button size='small' onClick={onClick} title='Actualize address'>
<Download size='small' />
</Button>
)
}

const ResolveAddressDuplicate = () => {
const location = useLocation()
const path = location.pathname.split('/').splice(2, 2)
const addressId = (path[0] === TARGET_URL_PART && path[1]) ? path[1] : null

const { data } = useQuery(GET_ADDRESS_QUERY, {
variables: { id: addressId },
skip: !addressId,
})

const [resolveDuplicate] = useMutation(RESOLVE_ADDRESS_DUPLICATE_MUTATION)

const possibleDuplicate = data?.address?.possibleDuplicateOf

const onClick = useCallback(() => {
if (!possibleDuplicate) return

// eslint-disable-next-line no-restricted-globals
const choice = prompt(
`This address is a possible duplicate of:\n${possibleDuplicate.address} (${possibleDuplicate.id})\n\n` +
'Type "merge" to MERGE (this address will be removed, all sources moved to the existing one)\n' +
'Type "dismiss" to DISMISS (mark as not a duplicate, possibleDuplicateOf will be cleared)\n\n' +
'Leave empty or press Cancel to abort.'
)

if (!choice) return

const action = choice.trim().toLowerCase()
if (action !== 'merge' && action !== 'dismiss') {
alert(`Unknown action: "${choice}". Please type "merge" or "dismiss".`)
return
}

const sender = getClientSideSenderInfo()
const mutationData = {
dv: 1,
sender,
addressId,
action,
...(action === 'merge' ? { winnerId: possibleDuplicate.id } : {}),
}

resolveDuplicate({ variables: { data: mutationData } })
.then(({ data: result }) => {
console.log(`Duplicate ${result.result.status}`)
if (action === 'merge') {
window.location.href = location.pathname.replace(addressId, possibleDuplicate.id)

Check warning on line 142 in apps/address-service/admin-ui/index.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `globalThis` over `window`.

See more on https://sonarcloud.io/project/issues?id=open-condo-software_condo&issues=AZxR3PLjyiTGTwyT64H6&open=AZxR3PLjyiTGTwyT64H6&pullRequest=7196
} else {
window.location.reload()

Check warning on line 144 in apps/address-service/admin-ui/index.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `globalThis` over `window`.

See more on https://sonarcloud.io/project/issues?id=open-condo-software_condo&issues=AZxR3PLjyiTGTwyT64H7&open=AZxR3PLjyiTGTwyT64H7&pullRequest=7196
}
})
.catch((error) => {
console.error('Failed to resolve duplicate', error)
alert(extractErrorMessage(error, 'Failed to resolve duplicate'))
})
}, [addressId, location.pathname, possibleDuplicate, resolveDuplicate])

if (!possibleDuplicate) return null

return (
<Button size='small' onClick={onClick} title='Resolve duplicate'>
<Link size='small' />
</Button>
)
}

Expand All @@ -64,11 +167,16 @@
},
itemHeaderActions: () => {
return (
<div>
<ItemId/>
<AddNewItem/>
<UpdateAddress/>
</div>
<Space direction='vertical' align='end'>
<Space>
<ItemId />
<AddNewItem />
</Space>
<Space>
<UpdateAddress />
<ResolveAddressDuplicate />
</Space>
</Space>
)
},
}
Loading