diff --git a/frontend/src/lib/i18n/locales/en/datasets.json b/frontend/src/lib/i18n/locales/en/datasets.json index 4f5c85a4..972e4b6b 100644 --- a/frontend/src/lib/i18n/locales/en/datasets.json +++ b/frontend/src/lib/i18n/locales/en/datasets.json @@ -56,5 +56,29 @@ "save_description": "Save description", "add_description": "Add description", "columns": "Columns", - "detail_empty": "No data" + "detail_empty": "No data", + "filter_all_tip": "Show all datasets in the environment", + "filter_unmapped_tip": "Datasets without mapped columns", + "filter_mapped_tip": "Datasets with mapped columns", + "filter_linked_tip": "Datasets linked to Superset dashboards", + "refresh_tip": "Refresh the dataset list", + "select_all_tip": "Select all datasets on this page", + "deselect_all_tip": "Deselect all datasets", + "map_columns_tip": "Run column mapping for this dataset", + "generate_docs_tip": "Generate column descriptions via LLM", + "pagination_first_tip": "First page", + "pagination_prev_tip": "Previous page", + "pagination_next_tip": "Next page", + "pagination_last_tip": "Last page", + "bulk_map_tip": "Bulk column mapping for selected datasets", + "bulk_docs_tip": "Bulk documentation generation for selected datasets", + "clear_selection_tip": "Deselect all datasets", + "source_type_tip": "Select data source: SQL Lab (Superset DB) or XLSX file", + "database_tip": "Superset database to look up column mappings", + "sql_query_tip": "Custom SQL query for mapping. Leave empty for automatic information_schema lookup", + "file_input_tip": "XLSX file with column mapping data", + "start_mapping_tip": "Start mapping task for selected datasets", + "cancel_tip": "Cancel and close", + "llm_provider_tip": "Select LLM provider for documentation generation", + "start_docs_tip": "Start documentation generation for selected datasets" } diff --git a/frontend/src/lib/i18n/locales/ru/datasets.json b/frontend/src/lib/i18n/locales/ru/datasets.json index 5f7af23e..96640082 100644 --- a/frontend/src/lib/i18n/locales/ru/datasets.json +++ b/frontend/src/lib/i18n/locales/ru/datasets.json @@ -56,5 +56,29 @@ "save_description": "Сохранить описание", "add_description": "Добавить описание", "columns": "Колонки", - "detail_empty": "Нет данных" + "detail_empty": "Нет данных", + "filter_all_tip": "Показать все датасеты в окружении", + "filter_unmapped_tip": "Датасеты без размеченных колонок", + "filter_mapped_tip": "Датасеты с размеченными колонками", + "filter_linked_tip": "Датасеты, связанные с дашбордами Superset", + "refresh_tip": "Обновить список датасетов", + "select_all_tip": "Выбрать все датасеты на странице", + "deselect_all_tip": "Снять выбор со всех датасетов", + "map_columns_tip": "Запустить маппинг колонок для этого датасета", + "generate_docs_tip": "Сгенерировать описание колонок через LLM", + "pagination_first_tip": "Первая страница", + "pagination_prev_tip": "Предыдущая страница", + "pagination_next_tip": "Следующая страница", + "pagination_last_tip": "Последняя страница", + "bulk_map_tip": "Массовый маппинг колонок для выбранных датасетов", + "bulk_docs_tip": "Массовая генерация документации для выбранных датасетов", + "clear_selection_tip": "Снять выбор со всех датасетов", + "source_type_tip": "Выберите источник данных: SQL Lab (база Superset) или XLSX-файл", + "database_tip": "База данных Superset для поиска соответствий колонок", + "sql_query_tip": "Произвольный SQL-запрос для маппинга. Оставьте пустым для автоматического поиска по information_schema", + "file_input_tip": "XLSX-файл с данными маппинга колонок", + "start_mapping_tip": "Запустить задачу маппинга для выбранных датасетов", + "cancel_tip": "Отменить и закрыть", + "llm_provider_tip": "Выберите LLM-провайдера для генерации документации", + "start_docs_tip": "Запустить генерацию документации для выбранных датасетов" } diff --git a/frontend/src/routes/datasets/+page.svelte b/frontend/src/routes/datasets/+page.svelte index f3067eb9..401a340d 100644 --- a/frontend/src/routes/datasets/+page.svelte +++ b/frontend/src/routes/datasets/+page.svelte @@ -259,7 +259,7 @@ {$t.datasets?.all}: {stats?.total ?? 0} - loadDatasets()}> + loadDatasets()}> {$t.common?.refresh ?? '⟳'} @@ -331,13 +331,13 @@ ✓ {selectedIds.size} {$t.datasets?.selected} - { showMapColumnsModal = true; mapSourceType = "sqllab"; mapDatabaseId = null; mapSqlQuery = ""; mapFileData = null; if (selectedEnv) api.getEnvironmentDatabases(selectedEnv).then(dbs => mapDatabases = dbs ?? []).catch(() => {}); }}> + { showMapColumnsModal = true; mapSourceType = "sqllab"; mapDatabaseId = null; mapSqlQuery = ""; mapFileData = null; if (selectedEnv) api.getEnvironmentDatabases(selectedEnv).then(dbs => mapDatabases = dbs ?? []).catch(() => {}); }}> 🗺 {$t.datasets?.action_map_columns} - { showGenerateDocsModal = true; }}> + { showGenerateDocsModal = true; }}> 📄 {$t.datasets?.generate_docs} - selectedIds = new SvelteSet()}> + selectedIds = new SvelteSet()}> ✕ {$t.common?.cancel ?? 'Clear'} @@ -351,34 +351,54 @@ e.stopPropagation()}> {$t.datasets?.bulk_map_columns} {$t.datasets?.selected_count?.replace('{count}', String(selectedIds.size))} - { if (mapSourceType === 'sqllab' && mapDatabases.length === 0 && selectedEnv) { api.getEnvironmentDatabases(selectedEnv).then(dbs => mapDatabases = dbs ?? []).catch(() => {}); } }}> + { if (mapSourceType === 'sqllab' && mapDatabases.length === 0 && selectedEnv) { api.getEnvironmentDatabases(selectedEnv).then(dbs => mapDatabases = dbs ?? []).catch(() => {}); } }} + > {$t.datasets?.source_sqllab ?? 'Superset SQL Lab'} {$t.datasets?.source_xlsx} {#if mapSourceType === "sqllab"} - {$t.datasets?.source_database ?? 'База данных'} - + {$t.datasets?.source_database ?? 'База данных'} + -- {$t.datasets?.select_database ?? 'выберите базу данных'} -- - {#each mapDatabases as db} + {#each mapDatabases as db (db.id)} {db.database_name || db.name} {/each} - + {$t.datasets?.sql_query ?? 'SQL-запрос'} ({$t.datasets?.sql_query_hint ?? 'оставьте пустым для information_schema'}) {:else} - mapFileData = e.target.files} /> + {$t.datasets?.xlsx_file ?? 'XLSX-файл'} + mapFileData = e.target.files} + /> {/if} - showMapColumnsModal = false}>{$t.common?.cancel} - {$t.datasets?.start_mapping} + showMapColumnsModal = false}>{$t.common?.cancel} + {$t.datasets?.start_mapping} @@ -390,15 +410,15 @@ e.stopPropagation()}> {$t.datasets?.bulk_docs_generation} {$t.datasets?.selected_count?.replace('{count}', String(selectedIds.size))} - + {$t.datasets?.select_llm_provider_option} OpenAI Anthropic Local LLM - showGenerateDocsModal = false}>{$t.common?.cancel} - {$t.datasets?.generate_docs} + showGenerateDocsModal = false}>{$t.common?.cancel} + {$t.datasets?.generate_docs} diff --git a/frontend/src/routes/datasets/DatasetList.svelte b/frontend/src/routes/datasets/DatasetList.svelte index f590ae04..76eebfaf 100644 --- a/frontend/src/routes/datasets/DatasetList.svelte +++ b/frontend/src/routes/datasets/DatasetList.svelte @@ -65,10 +65,12 @@ { selectedIds = new Set(datasets.map(d => d.id)); oncheckbox?.({}, 'all'); }} >{$t.datasets?.select_all} { selectedIds = new Set(); oncheckbox?.({}, 'clear-all'); }} >{$t.datasets?.deselect_all} @@ -134,16 +136,35 @@ {/if} - + { e.stopPropagation(); onaction?.(dataset, 'map_columns'); }} - >{$t.datasets?.action_map_columns} + > + + + + + + + + { e.stopPropagation(); onaction?.(dataset, 'generate_docs'); }} - >{$t.datasets?.generate_docs} + > + + + + + + + + + @@ -157,11 +178,11 @@ {($t.datasets?.showing ?? 'Showing {start}-{end} of {total}').replace('{start}', String((page - 1) * pageSize + 1)).replace('{end}', String(Math.min(page * pageSize, total))).replace('{total}', String(total))} - onpagechange?.(1)} disabled={page <= 1}>« - onpagechange?.(page - 1)} disabled={page <= 1}>‹ + onpagechange?.(1)} disabled={page <= 1}>« + onpagechange?.(page - 1)} disabled={page <= 1}>‹ {page} / {totalPages} - onpagechange?.(page + 1)} disabled={page >= totalPages}>› - onpagechange?.(totalPages)} disabled={page >= totalPages}>» + onpagechange?.(page + 1)} disabled={page >= totalPages}>› + onpagechange?.(totalPages)} disabled={page >= totalPages}>» {/if} diff --git a/frontend/src/routes/datasets/StatsBar.svelte b/frontend/src/routes/datasets/StatsBar.svelte index c988e0f8..4a74492d 100644 --- a/frontend/src/routes/datasets/StatsBar.svelte +++ b/frontend/src/routes/datasets/StatsBar.svelte @@ -38,6 +38,7 @@ class="inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm transition-all {activeFilter === tile.key ? 'bg-primary text-white shadow-sm' : 'bg-white border border-gray-300 text-gray-600 hover:border-gray-400 hover:text-gray-800'}" onclick={() => handleTileClick(tile.key)} aria-pressed={activeFilter === tile.key} + title={$t.datasets?.[tile.key === 'all' ? 'filter_all_tip' : tile.key === 'unmapped' ? 'filter_unmapped_tip' : tile.key === 'mapped' ? 'filter_mapped_tip' : 'filter_linked_tip']} > {$t.datasets?.[tile.label] ?? tile.label} {tile.getCount(stats)} diff --git a/frontend/src/routes/datasets/__tests__/DatasetList.test.js b/frontend/src/routes/datasets/__tests__/DatasetList.test.js index a06626fa..c337582d 100644 --- a/frontend/src/routes/datasets/__tests__/DatasetList.test.js +++ b/frontend/src/routes/datasets/__tests__/DatasetList.test.js @@ -50,10 +50,11 @@ describe('DatasetList Component', () => { expect(src).toContain('selectedIds'); }); - it('has quick-action buttons (map, docs)', () => { + it('has quick-action icon buttons (map, docs)', () => { const src = fs.readFileSync(COMPONENT_PATH, 'utf-8'); - expect(src).toContain('action_map_columns'); - expect(src).toContain('generate_docs'); + expect(src).toContain('map_columns_tip'); + expect(src).toContain('generate_docs_tip'); + expect(src).toContain(' {
{$t.datasets?.selected_count?.replace('{count}', String(selectedIds.size))}