From 58b42d956b83f03c1e3db85a9173425277466a46 Mon Sep 17 00:00:00 2001 From: monomono Date: Sat, 15 Aug 2026 18:33:30 -0500 Subject: [PATCH] =?UTF-8?q?#49=20fix:=20labels=20en=20nodos=20de=20gr?= =?UTF-8?q?=C3=A1ficos=20y=20municipio=20con=20departamento=20en=20proveed?= =?UTF-8?q?ores?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProductSupplierOrganizationChart.vue | 3 ++- .../provenance/ProductTerritoryChart.vue | 3 ++- .../provenance/admin/SuppliersManagement.vue | 15 ++++++++++--- .../ProductSupplierOrganizationChart.spec.js | 8 +++++++ .../provenance/ProductTerritoryChart.spec.js | 8 +++++++ .../admin/SuppliersManagement.spec.js | 22 +++++++++++++++++-- 6 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/components/provenance/ProductSupplierOrganizationChart.vue b/src/components/provenance/ProductSupplierOrganizationChart.vue index 5e2d6a4..58f32da 100644 --- a/src/components/provenance/ProductSupplierOrganizationChart.vue +++ b/src/components/provenance/ProductSupplierOrganizationChart.vue @@ -60,6 +60,7 @@ color: '#263238', 'font-size': 12, 'font-family': 'sans-serif', + content: 'data(label)', 'text-valign': 'bottom', 'text-halign': 'center', 'text-wrap': 'wrap', @@ -73,7 +74,7 @@ { selector: 'node.product', style: { 'background-color': '#26a69a', 'border-color': '#00796b' } }, { selector: 'node.supplier', style: { 'background-color': '#42a5f5', 'border-color': '#1565c0' } }, { selector: 'node.organization', style: { 'background-color': '#ffb74d', 'border-color': '#e65100' } }, - { selector: 'node.has-image', style: { 'background-image': 'data(image)', 'background-fit': 'cover', 'background-clip': 'none' } }, + { selector: 'node.has-image', style: { 'background-image': 'data(image)', 'background-fit': 'cover', 'background-clip': 'none', 'text-background-color': '#ffffff', 'text-background-opacity': 0.85, 'text-background-padding': 2 } }, { selector: 'edge', style: { diff --git a/src/components/provenance/ProductTerritoryChart.vue b/src/components/provenance/ProductTerritoryChart.vue index d77cb48..a30ea35 100644 --- a/src/components/provenance/ProductTerritoryChart.vue +++ b/src/components/provenance/ProductTerritoryChart.vue @@ -60,6 +60,7 @@ color: '#263238', 'font-size': 12, 'font-family': 'sans-serif', + content: 'data(label)', 'text-valign': 'bottom', 'text-halign': 'center', 'text-wrap': 'wrap', @@ -75,7 +76,7 @@ { selector: 'node.municipality', style: { 'background-color': '#66bb6a', 'border-color': '#2e7d32' } }, { selector: 'node.department', style: { 'background-color': '#5c6bc0', 'border-color': '#283593' } }, { selector: 'node.country', style: { 'background-color': '#ab47bc', 'border-color': '#6a1b9a' } }, - { selector: 'node.has-image', style: { 'background-image': 'data(image)', 'background-fit': 'cover', 'background-clip': 'none' } }, + { selector: 'node.has-image', style: { 'background-image': 'data(image)', 'background-fit': 'cover', 'background-clip': 'none', 'text-background-color': '#ffffff', 'text-background-opacity': 0.85, 'text-background-padding': 2 } }, { selector: 'edge', style: { diff --git a/src/components/provenance/admin/SuppliersManagement.vue b/src/components/provenance/admin/SuppliersManagement.vue index e16a475..cbb8cfd 100644 --- a/src/components/provenance/admin/SuppliersManagement.vue +++ b/src/components/provenance/admin/SuppliersManagement.vue @@ -111,7 +111,7 @@ v-model="formData.municipality" clearable data-testid="supplier-form-municipality" - item-title="name" + :item-title="municipalityItemTitle" item-value="id" :items="municipalityItems" label="Municipio" @@ -189,6 +189,7 @@ const suppliers = ref([]) const organizations = ref([]) const municipalities = ref([]) + const departments = ref([]) const loading = ref(false) const saving = ref(false) const searchQuery = ref('') @@ -226,12 +227,18 @@ }) }) + function municipalityItemTitle (item) { + const department = departments.value.find(department => department.id === item.department) + if (!department) return item.name || '' + return `${item.name} (${department.name})` + } + const municipalityItems = computed(() => { const query = municipalitySearch.value.trim().toLowerCase() let filtered = municipalities.value if (query) { filtered = municipalities.value.filter(municipality => { - return (municipality.name || '').toLowerCase().includes(query) + return municipalityItemTitle(municipality).toLowerCase().includes(query) }) } const selectedId = Number(formData.value.municipality) @@ -246,14 +253,16 @@ async function load () { loading.value = true try { - const [suppliersData, organizationsData, municipalitiesData] = await Promise.all([ + const [suppliersData, organizationsData, municipalitiesData, departmentsData] = await Promise.all([ api.getSuppliers(), api.getOrganizations(), api.getMunicipalities(), + api.getDepartments(), ]) suppliers.value = suppliersData organizations.value = organizationsData municipalities.value = municipalitiesData + departments.value = departmentsData } catch (error) { console.error('Error al cargar proveedores:', error) showSnackbar('Error al cargar proveedores', 'error') diff --git a/tests/unit/components/provenance/ProductSupplierOrganizationChart.spec.js b/tests/unit/components/provenance/ProductSupplierOrganizationChart.spec.js index ab71d38..b9d7a3c 100644 --- a/tests/unit/components/provenance/ProductSupplierOrganizationChart.spec.js +++ b/tests/unit/components/provenance/ProductSupplierOrganizationChart.spec.js @@ -60,6 +60,14 @@ describe('ProductSupplierOrganizationChart', () => { expect(nodeIds).toContain('organization:3') }) + it('muestra el nombre de los nodos a través del label', () => { + const wrapper = mountChart() + + const styles = wrapper.findComponent(CytoscapeChart).props('styles') + const nodeStyle = styles.find(style => style.selector === 'node').style + expect(nodeStyle.content).toBe('data(label)') + }) + it('no muestra mensaje de próximamente cuando existen relaciones', () => { const wrapper = mountChart() diff --git a/tests/unit/components/provenance/ProductTerritoryChart.spec.js b/tests/unit/components/provenance/ProductTerritoryChart.spec.js index 528df3b..49a3ff8 100644 --- a/tests/unit/components/provenance/ProductTerritoryChart.spec.js +++ b/tests/unit/components/provenance/ProductTerritoryChart.spec.js @@ -58,6 +58,14 @@ describe('ProductTerritoryChart', () => { expect(nodeIds).toContain('country:1') }) + it('muestra el nombre de los nodos a través del label', () => { + const wrapper = mountChart() + + const styles = wrapper.findComponent(CytoscapeChart).props('styles') + const nodeStyle = styles.find(style => style.selector === 'node').style + expect(nodeStyle.content).toBe('data(label)') + }) + it('muestra mensaje de próximamente cuando ningún proveedor tiene territorio', () => { const wrapper = mountChart({ provenance: [ diff --git a/tests/unit/components/provenance/admin/SuppliersManagement.spec.js b/tests/unit/components/provenance/admin/SuppliersManagement.spec.js index 310bca6..d2315e5 100644 --- a/tests/unit/components/provenance/admin/SuppliersManagement.spec.js +++ b/tests/unit/components/provenance/admin/SuppliersManagement.spec.js @@ -10,8 +10,13 @@ const organizations = [ ] const municipalities = [ - { id: 7, name: 'La Mesa' }, - { id: 8, name: 'San Antonio' }, + { id: 7, name: 'La Mesa', department: 2 }, + { id: 8, name: 'San Antonio', department: 3 }, +] + +const departments = [ + { id: 2, name: 'Cundinamarca' }, + { id: 3, name: 'Antioquia' }, ] const suppliers = [ @@ -44,6 +49,7 @@ function mockApi () { getSuppliers: vi.fn().mockResolvedValue(suppliers), getOrganizations: vi.fn().mockResolvedValue(organizations), getMunicipalities: vi.fn().mockResolvedValue(municipalities), + getDepartments: vi.fn().mockResolvedValue(departments), createSupplier: vi.fn().mockResolvedValue({}), updateSupplier: vi.fn().mockResolvedValue({}), deleteSupplier: vi.fn().mockResolvedValue({}), @@ -68,6 +74,18 @@ describe('SuppliersManagement', () => { expect(wrapper.text()).toContain('La Mesa') }) + it('muestra el departamento en el título del municipio', async () => { + const api = mockApi() + const wrapper = mountComponent(api) + await flushPromises() + + await wrapper.find('[data-testid="supplier-create"]').trigger('click') + const autocomplete = wrapper.findAllComponents({ name: 'VAutocomplete' })[0] + const itemTitle = autocomplete.props('itemTitle') + + expect(itemTitle({ id: 7, name: 'La Mesa', department: 2 })).toBe('La Mesa (Cundinamarca)') + }) + it('crea un proveedor con organización y municipio', async () => { const api = mockApi() const wrapper = mountComponent(api)