@ninebix/nmt-system 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dashboard-lite/index.html +458 -0
- package/dist/bin/nmt.js +135 -4
- package/dist/bin/nmt.js.map +1 -1
- package/dist/src/api/cli-server.d.ts.map +1 -1
- package/dist/src/api/cli-server.js +229 -30
- package/dist/src/api/cli-server.js.map +1 -1
- package/dist/src/cli/commands/db.d.ts +33 -0
- package/dist/src/cli/commands/db.d.ts.map +1 -0
- package/dist/src/cli/commands/db.js +197 -0
- package/dist/src/cli/commands/db.js.map +1 -0
- package/dist/src/cli/commands/infer.d.ts.map +1 -1
- package/dist/src/cli/commands/infer.js +8 -2
- package/dist/src/cli/commands/infer.js.map +1 -1
- package/dist/src/cli/commands/learn.d.ts.map +1 -1
- package/dist/src/cli/commands/learn.js +25 -1
- package/dist/src/cli/commands/learn.js.map +1 -1
- package/dist/src/cli/commands/sync.d.ts +14 -0
- package/dist/src/cli/commands/sync.d.ts.map +1 -1
- package/dist/src/cli/commands/sync.js +12 -7
- package/dist/src/cli/commands/sync.js.map +1 -1
- package/dist/src/connectors/index.d.ts +11 -0
- package/dist/src/connectors/index.d.ts.map +1 -0
- package/dist/src/connectors/index.js +24 -0
- package/dist/src/connectors/index.js.map +1 -0
- package/dist/src/connectors/mongodb-connector.d.ts +29 -0
- package/dist/src/connectors/mongodb-connector.d.ts.map +1 -0
- package/dist/src/connectors/mongodb-connector.js +286 -0
- package/dist/src/connectors/mongodb-connector.js.map +1 -0
- package/dist/src/connectors/mysql-connector.d.ts +29 -0
- package/dist/src/connectors/mysql-connector.d.ts.map +1 -0
- package/dist/src/connectors/mysql-connector.js +357 -0
- package/dist/src/connectors/mysql-connector.js.map +1 -0
- package/dist/src/connectors/types.d.ts +174 -0
- package/dist/src/connectors/types.d.ts.map +1 -0
- package/dist/src/connectors/types.js +6 -0
- package/dist/src/connectors/types.js.map +1 -0
- package/dist/src/core/attractor-model.d.ts +6 -2
- package/dist/src/core/attractor-model.d.ts.map +1 -1
- package/dist/src/core/attractor-model.js +260 -16
- package/dist/src/core/attractor-model.js.map +1 -1
- package/dist/src/core/hnsw-index.d.ts.map +1 -1
- package/dist/src/core/hnsw-index.js +16 -9
- package/dist/src/core/hnsw-index.js.map +1 -1
- package/dist/src/core/neuron-graph.d.ts +10 -1
- package/dist/src/core/neuron-graph.d.ts.map +1 -1
- package/dist/src/core/neuron-graph.js +10 -1
- package/dist/src/core/neuron-graph.js.map +1 -1
- package/dist/src/core/probabilistic-neuron.d.ts.map +1 -1
- package/dist/src/core/probabilistic-neuron.js +24 -4
- package/dist/src/core/probabilistic-neuron.js.map +1 -1
- package/dist/src/core/probabilistic-orchestrator.d.ts.map +1 -1
- package/dist/src/core/probabilistic-orchestrator.js +17 -13
- package/dist/src/core/probabilistic-orchestrator.js.map +1 -1
- package/dist/src/extensions/clustering/index.d.ts +0 -7
- package/dist/src/extensions/clustering/index.d.ts.map +1 -1
- package/dist/src/extensions/clustering/index.js.map +1 -1
- package/dist/src/mcp/server.js +4 -0
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/services/db-bridge.d.ts +46 -0
- package/dist/src/services/db-bridge.d.ts.map +1 -0
- package/dist/src/services/db-bridge.js +524 -0
- package/dist/src/services/db-bridge.js.map +1 -0
- package/dist/src/services/four-stage-learning.d.ts.map +1 -1
- package/dist/src/services/four-stage-learning.js +20 -9
- package/dist/src/services/four-stage-learning.js.map +1 -1
- package/dist/src/services/ingestion.d.ts +10 -1
- package/dist/src/services/ingestion.d.ts.map +1 -1
- package/dist/src/services/ingestion.js +20 -2
- package/dist/src/services/ingestion.js.map +1 -1
- package/dist/src/services/text-embedding.d.ts +1 -1
- package/dist/src/services/text-embedding.d.ts.map +1 -1
- package/dist/src/services/text-embedding.js +62 -3
- package/dist/src/services/text-embedding.js.map +1 -1
- package/dist/src/storage/neuron-store.d.ts +10 -1
- package/dist/src/storage/neuron-store.d.ts.map +1 -1
- package/dist/src/storage/neuron-store.js +10 -1
- package/dist/src/storage/neuron-store.js.map +1 -1
- package/dist/src/sync/change-journal.d.ts.map +1 -1
- package/dist/src/sync/change-journal.js +63 -37
- package/dist/src/sync/change-journal.js.map +1 -1
- package/dist/src/sync/state-sync.d.ts +5 -0
- package/dist/src/sync/state-sync.d.ts.map +1 -1
- package/dist/src/sync/state-sync.js +9 -2
- package/dist/src/sync/state-sync.js.map +1 -1
- package/dist/src/types/index.d.ts +59 -2
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/utils/hash.d.ts.map +1 -1
- package/dist/src/utils/hash.js +3 -3
- package/dist/src/utils/hash.js.map +1 -1
- package/package.json +5 -1
|
@@ -924,6 +924,327 @@
|
|
|
924
924
|
</div>
|
|
925
925
|
</section>
|
|
926
926
|
|
|
927
|
+
<!-- DATABASE TAB -->
|
|
928
|
+
<section x-show="activeTab === 'database'" x-cloak>
|
|
929
|
+
<div class="flex items-center justify-between mb-6">
|
|
930
|
+
<div>
|
|
931
|
+
<h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark">Database Bridge</h2>
|
|
932
|
+
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Connect external databases to import/export NMT data</p>
|
|
933
|
+
</div>
|
|
934
|
+
<div class="flex items-center gap-2">
|
|
935
|
+
<span class="flex items-center gap-2 px-3 py-1.5 rounded-full text-xs font-medium"
|
|
936
|
+
:class="dbConnected ? 'bg-md-success/10 text-md-success dark:bg-md-success/20' : 'bg-gray-100 text-gray-500 dark:bg-gray-800 dark:text-gray-400'">
|
|
937
|
+
<span class="w-2 h-2 rounded-full" :class="dbConnected ? 'bg-md-success' : 'bg-gray-400'"></span>
|
|
938
|
+
<span x-text="dbConnected ? 'Connected' : 'Disconnected'"></span>
|
|
939
|
+
</span>
|
|
940
|
+
</div>
|
|
941
|
+
</div>
|
|
942
|
+
|
|
943
|
+
<!-- Connection Panel -->
|
|
944
|
+
<div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden mb-6">
|
|
945
|
+
<div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark">
|
|
946
|
+
<h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
|
|
947
|
+
<span class="material-icons-outlined text-md-primary">link</span>
|
|
948
|
+
Connection
|
|
949
|
+
</h3>
|
|
950
|
+
</div>
|
|
951
|
+
<div class="p-6">
|
|
952
|
+
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-4">
|
|
953
|
+
<div>
|
|
954
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Driver</label>
|
|
955
|
+
<select x-model="dbDriver" @change="dbPort = dbDriver === 'mongodb' ? 27017 : 3306"
|
|
956
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
957
|
+
<option value="mysql">MySQL</option>
|
|
958
|
+
<option value="mariadb">MariaDB</option>
|
|
959
|
+
<option value="mongodb">MongoDB</option>
|
|
960
|
+
</select>
|
|
961
|
+
</div>
|
|
962
|
+
<div x-show="dbDriver !== 'mongodb' || !dbUri">
|
|
963
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Host</label>
|
|
964
|
+
<input type="text" x-model="dbHost" placeholder="localhost"
|
|
965
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
966
|
+
</div>
|
|
967
|
+
<div x-show="dbDriver !== 'mongodb' || !dbUri">
|
|
968
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Port</label>
|
|
969
|
+
<input type="number" x-model.number="dbPort"
|
|
970
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
971
|
+
</div>
|
|
972
|
+
<div>
|
|
973
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Database</label>
|
|
974
|
+
<input type="text" x-model="dbDatabase" placeholder="mydb"
|
|
975
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
976
|
+
</div>
|
|
977
|
+
</div>
|
|
978
|
+
|
|
979
|
+
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-4">
|
|
980
|
+
<div x-show="dbDriver !== 'mongodb' || !dbUri">
|
|
981
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">User</label>
|
|
982
|
+
<input type="text" x-model="dbUser" placeholder="root"
|
|
983
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
984
|
+
</div>
|
|
985
|
+
<div x-show="dbDriver !== 'mongodb' || !dbUri">
|
|
986
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Password</label>
|
|
987
|
+
<input type="password" x-model="dbPassword" placeholder="••••••"
|
|
988
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
989
|
+
</div>
|
|
990
|
+
<div x-show="dbDriver === 'mongodb'" class="md:col-span-2">
|
|
991
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">URI (optional, overrides host/port/user)</label>
|
|
992
|
+
<input type="text" x-model="dbUri" placeholder="mongodb://localhost:27017"
|
|
993
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm font-mono focus:ring-2 focus:ring-md-primary outline-none">
|
|
994
|
+
</div>
|
|
995
|
+
</div>
|
|
996
|
+
|
|
997
|
+
<!-- Error Message -->
|
|
998
|
+
<div x-show="dbError" class="mb-4 p-3 bg-md-error/10 border border-md-error/30 rounded-lg text-sm text-md-error flex items-center gap-2">
|
|
999
|
+
<span class="material-icons-outlined text-lg">error</span>
|
|
1000
|
+
<span x-text="dbError"></span>
|
|
1001
|
+
<button @click="dbError = ''" class="ml-auto material-icons-outlined text-lg hover:opacity-70">close</button>
|
|
1002
|
+
</div>
|
|
1003
|
+
|
|
1004
|
+
<div class="flex gap-3">
|
|
1005
|
+
<button @click="dbConnect()" :disabled="dbLoading || !dbDatabase"
|
|
1006
|
+
class="flex items-center gap-2 px-5 py-2.5 bg-md-primary text-white rounded-lg text-sm font-medium hover:bg-md-primary-dark disabled:opacity-50 shadow-md-1 transition-all">
|
|
1007
|
+
<span x-show="dbLoading" class="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
|
|
1008
|
+
<span class="material-icons-outlined text-lg" x-show="!dbLoading">power</span>
|
|
1009
|
+
<span x-text="dbLoading ? 'Connecting...' : 'Connect & Scan'"></span>
|
|
1010
|
+
</button>
|
|
1011
|
+
<button x-show="dbConnected" @click="dbDisconnect()"
|
|
1012
|
+
class="flex items-center gap-2 px-5 py-2.5 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg text-sm font-medium hover:bg-gray-300 dark:hover:bg-gray-600 transition-all">
|
|
1013
|
+
<span class="material-icons-outlined text-lg">power_off</span>
|
|
1014
|
+
Disconnect
|
|
1015
|
+
</button>
|
|
1016
|
+
</div>
|
|
1017
|
+
</div>
|
|
1018
|
+
</div>
|
|
1019
|
+
|
|
1020
|
+
<!-- Schema Browser -->
|
|
1021
|
+
<div x-show="dbSchema" class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden mb-6">
|
|
1022
|
+
<div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark">
|
|
1023
|
+
<h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
|
|
1024
|
+
<span class="material-icons-outlined text-md-primary">table_chart</span>
|
|
1025
|
+
Schema Browser
|
|
1026
|
+
<span class="text-xs font-medium bg-md-primary/10 text-md-primary dark:bg-md-primary/20 dark:text-md-primary-light px-2 py-0.5 rounded-full" x-text="dbSchema?.name"></span>
|
|
1027
|
+
</h3>
|
|
1028
|
+
</div>
|
|
1029
|
+
<div class="flex divide-x divide-md-outline dark:divide-md-outline-dark" style="min-height: 300px;">
|
|
1030
|
+
<!-- Table List -->
|
|
1031
|
+
<div class="w-64 flex-shrink-0 overflow-y-auto" style="max-height: 400px;">
|
|
1032
|
+
<template x-for="table in (dbSchema?.tables || [])" :key="table.name">
|
|
1033
|
+
<button @click="dbSelectTable(table.name)"
|
|
1034
|
+
:class="dbSelectedTable === table.name ? 'bg-md-primary/10 dark:bg-md-primary/20 border-l-2 border-md-primary' : 'hover:bg-md-surface-variant dark:hover:bg-md-surface-dark'"
|
|
1035
|
+
class="w-full text-left px-4 py-3 border-b border-md-outline dark:border-md-outline-dark transition-colors">
|
|
1036
|
+
<div class="flex items-center justify-between">
|
|
1037
|
+
<span class="text-sm font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="table.name"></span>
|
|
1038
|
+
<span class="text-xs bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400 px-2 py-0.5 rounded-full" x-text="(table.rowCount ?? 0).toLocaleString() + ' rows'"></span>
|
|
1039
|
+
</div>
|
|
1040
|
+
</button>
|
|
1041
|
+
</template>
|
|
1042
|
+
<div x-show="!dbSchema?.tables?.length" class="p-4 text-center text-gray-400 text-sm">
|
|
1043
|
+
No tables found
|
|
1044
|
+
</div>
|
|
1045
|
+
</div>
|
|
1046
|
+
|
|
1047
|
+
<!-- Column Details -->
|
|
1048
|
+
<div class="flex-1 overflow-x-auto">
|
|
1049
|
+
<template x-if="dbSelectedTable && dbGetSelectedTableSchema()">
|
|
1050
|
+
<table class="w-full">
|
|
1051
|
+
<thead>
|
|
1052
|
+
<tr class="bg-md-surface-variant dark:bg-md-surface-dark">
|
|
1053
|
+
<th class="text-left text-xs font-medium text-gray-500 uppercase tracking-wider px-4 py-3">Column</th>
|
|
1054
|
+
<th class="text-left text-xs font-medium text-gray-500 uppercase tracking-wider px-4 py-3">Type</th>
|
|
1055
|
+
<th class="text-left text-xs font-medium text-gray-500 uppercase tracking-wider px-4 py-3">Attributes</th>
|
|
1056
|
+
</tr>
|
|
1057
|
+
</thead>
|
|
1058
|
+
<tbody class="divide-y divide-md-outline dark:divide-md-outline-dark">
|
|
1059
|
+
<template x-for="col in dbGetSelectedTableSchema().columns" :key="col.name">
|
|
1060
|
+
<tr class="hover:bg-md-surface-variant/50 dark:hover:bg-md-surface-dark/50">
|
|
1061
|
+
<td class="px-4 py-2.5">
|
|
1062
|
+
<span class="text-sm font-mono text-md-on-surface dark:text-md-on-surface-dark" x-text="col.name"></span>
|
|
1063
|
+
</td>
|
|
1064
|
+
<td class="px-4 py-2.5">
|
|
1065
|
+
<span class="text-sm text-gray-600 dark:text-gray-400" x-text="col.type"></span>
|
|
1066
|
+
</td>
|
|
1067
|
+
<td class="px-4 py-2.5">
|
|
1068
|
+
<div class="flex flex-wrap gap-1">
|
|
1069
|
+
<span x-show="col.isPrimary" class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-400">PK</span>
|
|
1070
|
+
<span x-show="col.isForeign" class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400">
|
|
1071
|
+
FK<span x-show="col.foreignTable" class="ml-0.5" x-text="'→ ' + col.foreignTable"></span>
|
|
1072
|
+
</span>
|
|
1073
|
+
<span x-show="!col.nullable" class="inline-flex items-center px-1.5 py-0.5 rounded text-xs font-medium bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400">NN</span>
|
|
1074
|
+
</div>
|
|
1075
|
+
</td>
|
|
1076
|
+
</tr>
|
|
1077
|
+
</template>
|
|
1078
|
+
</tbody>
|
|
1079
|
+
</table>
|
|
1080
|
+
</template>
|
|
1081
|
+
<div x-show="!dbSelectedTable" class="flex items-center justify-center h-full text-gray-400 dark:text-gray-500">
|
|
1082
|
+
<div class="text-center py-12">
|
|
1083
|
+
<span class="material-icons-outlined text-4xl mb-2 block">arrow_back</span>
|
|
1084
|
+
<p class="text-sm">Select a table to view columns</p>
|
|
1085
|
+
</div>
|
|
1086
|
+
</div>
|
|
1087
|
+
</div>
|
|
1088
|
+
</div>
|
|
1089
|
+
</div>
|
|
1090
|
+
|
|
1091
|
+
<!-- Import / Export -->
|
|
1092
|
+
<div x-show="dbConnected" class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
1093
|
+
<!-- Import Panel -->
|
|
1094
|
+
<div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
|
|
1095
|
+
<div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark">
|
|
1096
|
+
<h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
|
|
1097
|
+
<span class="material-icons-outlined text-md-success">download</span>
|
|
1098
|
+
Import (DB → NMT)
|
|
1099
|
+
</h3>
|
|
1100
|
+
</div>
|
|
1101
|
+
<div class="p-6 space-y-4">
|
|
1102
|
+
<div>
|
|
1103
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Table / Collection</label>
|
|
1104
|
+
<select x-model="dbImportTable"
|
|
1105
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
1106
|
+
<option value="">Select table...</option>
|
|
1107
|
+
<template x-for="t in (dbSchema?.tables || [])" :key="t.name">
|
|
1108
|
+
<option :value="t.name" x-text="t.name + ' (' + (t.rowCount ?? 0) + ' rows)'"></option>
|
|
1109
|
+
</template>
|
|
1110
|
+
</select>
|
|
1111
|
+
</div>
|
|
1112
|
+
<div class="grid grid-cols-2 gap-3">
|
|
1113
|
+
<div>
|
|
1114
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Limit (rows)</label>
|
|
1115
|
+
<input type="number" x-model="dbImportLimit" placeholder="All"
|
|
1116
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
1117
|
+
</div>
|
|
1118
|
+
<div>
|
|
1119
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Batch Size</label>
|
|
1120
|
+
<input type="number" x-model="dbImportBatch" placeholder="1000"
|
|
1121
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
1122
|
+
</div>
|
|
1123
|
+
</div>
|
|
1124
|
+
<div>
|
|
1125
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Tags (comma-separated)</label>
|
|
1126
|
+
<input type="text" x-model="dbImportTags" placeholder="import, users"
|
|
1127
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
1128
|
+
</div>
|
|
1129
|
+
<button @click="dbRunImport()" :disabled="dbImportLoading || !dbImportTable"
|
|
1130
|
+
class="w-full py-3 bg-md-success text-white rounded-lg font-medium hover:bg-green-700 disabled:opacity-50 flex items-center justify-center gap-2 shadow-md-1 transition-all">
|
|
1131
|
+
<span x-show="dbImportLoading" class="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
|
|
1132
|
+
<span class="material-icons-outlined" x-show="!dbImportLoading">download</span>
|
|
1133
|
+
<span x-text="dbImportLoading ? 'Importing...' : 'Import'"></span>
|
|
1134
|
+
</button>
|
|
1135
|
+
|
|
1136
|
+
<!-- Import Result -->
|
|
1137
|
+
<div x-show="dbImportResult" class="p-4 bg-md-success/10 dark:bg-md-success/20 border border-md-success/30 rounded-lg">
|
|
1138
|
+
<div class="flex items-center gap-2 mb-3">
|
|
1139
|
+
<span class="material-icons-outlined text-md-success">check_circle</span>
|
|
1140
|
+
<span class="text-sm font-medium text-md-success">Import Complete</span>
|
|
1141
|
+
</div>
|
|
1142
|
+
<div class="grid grid-cols-2 gap-3 text-sm">
|
|
1143
|
+
<div>
|
|
1144
|
+
<span class="text-gray-500 dark:text-gray-400">Rows Processed:</span>
|
|
1145
|
+
<span class="ml-1 font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="dbImportResult?.rowsProcessed"></span>
|
|
1146
|
+
</div>
|
|
1147
|
+
<div>
|
|
1148
|
+
<span class="text-gray-500 dark:text-gray-400">Neurons Created:</span>
|
|
1149
|
+
<span class="ml-1 font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="dbImportResult?.neuronsCreated"></span>
|
|
1150
|
+
</div>
|
|
1151
|
+
<div>
|
|
1152
|
+
<span class="text-gray-500 dark:text-gray-400">Synapses Created:</span>
|
|
1153
|
+
<span class="ml-1 font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="dbImportResult?.synapsesCreated"></span>
|
|
1154
|
+
</div>
|
|
1155
|
+
<div>
|
|
1156
|
+
<span class="text-gray-500 dark:text-gray-400">Duration:</span>
|
|
1157
|
+
<span class="ml-1 font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="((dbImportResult?.duration || 0) / 1000).toFixed(1) + 's'"></span>
|
|
1158
|
+
</div>
|
|
1159
|
+
</div>
|
|
1160
|
+
<div x-show="dbImportResult?.errors?.length > 0" class="mt-3 text-xs text-md-error">
|
|
1161
|
+
<span x-text="dbImportResult.errors.length + ' error(s)'"></span>
|
|
1162
|
+
</div>
|
|
1163
|
+
</div>
|
|
1164
|
+
</div>
|
|
1165
|
+
</div>
|
|
1166
|
+
|
|
1167
|
+
<!-- Export Panel -->
|
|
1168
|
+
<div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
|
|
1169
|
+
<div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark">
|
|
1170
|
+
<h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
|
|
1171
|
+
<span class="material-icons-outlined text-md-primary">upload</span>
|
|
1172
|
+
Export (NMT → DB)
|
|
1173
|
+
</h3>
|
|
1174
|
+
</div>
|
|
1175
|
+
<div class="p-6 space-y-4">
|
|
1176
|
+
<div>
|
|
1177
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Target Table Name</label>
|
|
1178
|
+
<input type="text" x-model="dbExportTable" placeholder="nmt_neurons"
|
|
1179
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
1180
|
+
</div>
|
|
1181
|
+
<div class="grid grid-cols-2 gap-3">
|
|
1182
|
+
<div>
|
|
1183
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Tags Filter</label>
|
|
1184
|
+
<input type="text" x-model="dbExportTags" placeholder="All neurons"
|
|
1185
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
1186
|
+
</div>
|
|
1187
|
+
<div>
|
|
1188
|
+
<label class="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Limit</label>
|
|
1189
|
+
<input type="number" x-model="dbExportLimit" placeholder="All"
|
|
1190
|
+
class="w-full px-3 py-2.5 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
|
|
1191
|
+
</div>
|
|
1192
|
+
</div>
|
|
1193
|
+
<div class="flex flex-wrap gap-x-6 gap-y-2">
|
|
1194
|
+
<label class="flex items-center gap-2 text-sm text-md-on-surface dark:text-md-on-surface-dark cursor-pointer">
|
|
1195
|
+
<input type="checkbox" x-model="dbExportEmbeddings" class="w-4 h-4 text-md-primary rounded focus:ring-md-primary">
|
|
1196
|
+
Include Embeddings
|
|
1197
|
+
</label>
|
|
1198
|
+
<label class="flex items-center gap-2 text-sm text-md-on-surface dark:text-md-on-surface-dark cursor-pointer">
|
|
1199
|
+
<input type="checkbox" x-model="dbExportSynapses" class="w-4 h-4 text-md-primary rounded focus:ring-md-primary">
|
|
1200
|
+
Include Synapses
|
|
1201
|
+
</label>
|
|
1202
|
+
<label class="flex items-center gap-2 text-sm text-md-on-surface dark:text-md-on-surface-dark cursor-pointer" title="Export original source columns instead of neuron metadata">
|
|
1203
|
+
<input type="checkbox" x-model="dbExportRestore" class="w-4 h-4 text-md-tertiary rounded focus:ring-md-tertiary">
|
|
1204
|
+
Restore Source Data
|
|
1205
|
+
</label>
|
|
1206
|
+
</div>
|
|
1207
|
+
<button @click="dbRunExport()" :disabled="dbExportLoading"
|
|
1208
|
+
class="w-full py-3 bg-md-primary text-white rounded-lg font-medium hover:bg-md-primary-dark disabled:opacity-50 flex items-center justify-center gap-2 shadow-md-1 transition-all">
|
|
1209
|
+
<span x-show="dbExportLoading" class="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
|
|
1210
|
+
<span class="material-icons-outlined" x-show="!dbExportLoading">upload</span>
|
|
1211
|
+
<span x-text="dbExportLoading ? 'Exporting...' : 'Export'"></span>
|
|
1212
|
+
</button>
|
|
1213
|
+
|
|
1214
|
+
<!-- Export Result -->
|
|
1215
|
+
<div x-show="dbExportResult" class="p-4 bg-md-primary/10 dark:bg-md-primary/20 border border-md-primary/30 rounded-lg">
|
|
1216
|
+
<div class="flex items-center gap-2 mb-3">
|
|
1217
|
+
<span class="material-icons-outlined text-md-primary">check_circle</span>
|
|
1218
|
+
<span class="text-sm font-medium text-md-primary">Export Complete</span>
|
|
1219
|
+
</div>
|
|
1220
|
+
<div class="grid grid-cols-2 gap-3 text-sm">
|
|
1221
|
+
<div>
|
|
1222
|
+
<span class="text-gray-500 dark:text-gray-400">Neurons Exported:</span>
|
|
1223
|
+
<span class="ml-1 font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="dbExportResult?.neuronsExported"></span>
|
|
1224
|
+
</div>
|
|
1225
|
+
<div>
|
|
1226
|
+
<span class="text-gray-500 dark:text-gray-400">Synapses Exported:</span>
|
|
1227
|
+
<span class="ml-1 font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="dbExportResult?.synapsesExported"></span>
|
|
1228
|
+
</div>
|
|
1229
|
+
<div>
|
|
1230
|
+
<span class="text-gray-500 dark:text-gray-400">Tables Created:</span>
|
|
1231
|
+
<span class="ml-1 font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="(dbExportResult?.tablesCreated || []).join(', ') || 'none'"></span>
|
|
1232
|
+
</div>
|
|
1233
|
+
<div>
|
|
1234
|
+
<span class="text-gray-500 dark:text-gray-400">Duration:</span>
|
|
1235
|
+
<span class="ml-1 font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="((dbExportResult?.duration || 0) / 1000).toFixed(1) + 's'"></span>
|
|
1236
|
+
</div>
|
|
1237
|
+
<div x-show="dbExportResult?.sourceDataRestored > 0">
|
|
1238
|
+
<span class="text-gray-500 dark:text-gray-400">Source Restored:</span>
|
|
1239
|
+
<span class="ml-1 font-medium text-md-tertiary" x-text="dbExportResult?.sourceDataRestored"></span>
|
|
1240
|
+
</div>
|
|
1241
|
+
</div>
|
|
1242
|
+
</div>
|
|
1243
|
+
</div>
|
|
1244
|
+
</div>
|
|
1245
|
+
</div>
|
|
1246
|
+
</section>
|
|
1247
|
+
|
|
927
1248
|
</div>
|
|
928
1249
|
</main>
|
|
929
1250
|
|
|
@@ -952,6 +1273,7 @@
|
|
|
952
1273
|
{ id: 'search', label: 'Search', icon: 'search' },
|
|
953
1274
|
{ id: 'ingest', label: 'Ingest', icon: 'upload_file' },
|
|
954
1275
|
{ id: 'verify', label: 'Verify', icon: 'verified' },
|
|
1276
|
+
{ id: 'database', label: 'Database', icon: 'storage' },
|
|
955
1277
|
],
|
|
956
1278
|
|
|
957
1279
|
// Connection
|
|
@@ -1008,6 +1330,34 @@
|
|
|
1008
1330
|
verifySingleResult: null,
|
|
1009
1331
|
verifySingleLoading: false,
|
|
1010
1332
|
|
|
1333
|
+
// Database
|
|
1334
|
+
dbDriver: 'mysql',
|
|
1335
|
+
dbHost: 'localhost',
|
|
1336
|
+
dbPort: 3306,
|
|
1337
|
+
dbUser: '',
|
|
1338
|
+
dbPassword: '',
|
|
1339
|
+
dbDatabase: '',
|
|
1340
|
+
dbUri: '',
|
|
1341
|
+
dbConnected: false,
|
|
1342
|
+
dbSchema: null,
|
|
1343
|
+
dbSelectedTable: null,
|
|
1344
|
+
dbImportTable: '',
|
|
1345
|
+
dbImportLimit: '',
|
|
1346
|
+
dbImportBatch: '1000',
|
|
1347
|
+
dbImportTags: '',
|
|
1348
|
+
dbImportResult: null,
|
|
1349
|
+
dbImportLoading: false,
|
|
1350
|
+
dbExportTable: 'nmt_neurons',
|
|
1351
|
+
dbExportTags: '',
|
|
1352
|
+
dbExportLimit: '',
|
|
1353
|
+
dbExportEmbeddings: true,
|
|
1354
|
+
dbExportSynapses: true,
|
|
1355
|
+
dbExportRestore: false,
|
|
1356
|
+
dbExportResult: null,
|
|
1357
|
+
dbExportLoading: false,
|
|
1358
|
+
dbLoading: false,
|
|
1359
|
+
dbError: '',
|
|
1360
|
+
|
|
1011
1361
|
async init() {
|
|
1012
1362
|
await this.checkHealth();
|
|
1013
1363
|
await this.loadStats();
|
|
@@ -1307,6 +1657,114 @@
|
|
|
1307
1657
|
this.verifySingleLoading = false;
|
|
1308
1658
|
},
|
|
1309
1659
|
|
|
1660
|
+
// Database methods
|
|
1661
|
+
dbGetConnection() {
|
|
1662
|
+
const conn = {
|
|
1663
|
+
driver: this.dbDriver,
|
|
1664
|
+
host: this.dbHost,
|
|
1665
|
+
port: this.dbPort,
|
|
1666
|
+
user: this.dbUser || undefined,
|
|
1667
|
+
password: this.dbPassword || undefined,
|
|
1668
|
+
database: this.dbDatabase,
|
|
1669
|
+
};
|
|
1670
|
+
if (this.dbDriver === 'mongodb' && this.dbUri) {
|
|
1671
|
+
conn.uri = this.dbUri;
|
|
1672
|
+
}
|
|
1673
|
+
return conn;
|
|
1674
|
+
},
|
|
1675
|
+
|
|
1676
|
+
async dbConnect() {
|
|
1677
|
+
this.dbLoading = true;
|
|
1678
|
+
this.dbError = '';
|
|
1679
|
+
this.dbSchema = null;
|
|
1680
|
+
this.dbSelectedTable = null;
|
|
1681
|
+
this.dbImportResult = null;
|
|
1682
|
+
this.dbExportResult = null;
|
|
1683
|
+
try {
|
|
1684
|
+
const conn = this.dbGetConnection();
|
|
1685
|
+
await this.api('POST', '/db/connect', conn);
|
|
1686
|
+
// Connection test passed; now fetch schema
|
|
1687
|
+
try {
|
|
1688
|
+
const schema = await this.api('POST', '/db/schema', conn);
|
|
1689
|
+
this.dbSchema = schema;
|
|
1690
|
+
if (schema.tables?.length > 0) {
|
|
1691
|
+
this.dbSelectedTable = schema.tables[0].name;
|
|
1692
|
+
this.dbImportTable = schema.tables[0].name;
|
|
1693
|
+
}
|
|
1694
|
+
} catch (schemaErr) {
|
|
1695
|
+
// Connection works but schema fetch failed - still mark as connected
|
|
1696
|
+
this.dbError = 'Connected, but schema fetch failed: ' + (schemaErr.message || 'Unknown error');
|
|
1697
|
+
}
|
|
1698
|
+
this.dbConnected = true;
|
|
1699
|
+
} catch (e) {
|
|
1700
|
+
this.dbConnected = false;
|
|
1701
|
+
this.dbError = e.message || 'Connection failed';
|
|
1702
|
+
}
|
|
1703
|
+
this.dbLoading = false;
|
|
1704
|
+
},
|
|
1705
|
+
|
|
1706
|
+
dbDisconnect() {
|
|
1707
|
+
this.dbConnected = false;
|
|
1708
|
+
this.dbSchema = null;
|
|
1709
|
+
this.dbSelectedTable = null;
|
|
1710
|
+
this.dbImportResult = null;
|
|
1711
|
+
this.dbExportResult = null;
|
|
1712
|
+
this.dbError = '';
|
|
1713
|
+
},
|
|
1714
|
+
|
|
1715
|
+
dbSelectTable(name) {
|
|
1716
|
+
this.dbSelectedTable = name;
|
|
1717
|
+
},
|
|
1718
|
+
|
|
1719
|
+
dbGetSelectedTableSchema() {
|
|
1720
|
+
if (!this.dbSchema || !this.dbSelectedTable) return null;
|
|
1721
|
+
return this.dbSchema.tables.find(t => t.name === this.dbSelectedTable) || null;
|
|
1722
|
+
},
|
|
1723
|
+
|
|
1724
|
+
async dbRunImport() {
|
|
1725
|
+
if (!this.dbImportTable) return;
|
|
1726
|
+
this.dbImportLoading = true;
|
|
1727
|
+
this.dbImportResult = null;
|
|
1728
|
+
this.dbError = '';
|
|
1729
|
+
try {
|
|
1730
|
+
const tags = this.dbImportTags ? this.dbImportTags.split(',').map(t => t.trim()).filter(t => t) : [];
|
|
1731
|
+
const parsedLimit = this.dbImportLimit ? parseInt(this.dbImportLimit, 10) : undefined;
|
|
1732
|
+
const parsedBatch = this.dbImportBatch ? parseInt(this.dbImportBatch, 10) : 1000;
|
|
1733
|
+
this.dbImportResult = await this.api('POST', '/db/import', {
|
|
1734
|
+
connection: this.dbGetConnection(),
|
|
1735
|
+
table: this.dbImportTable,
|
|
1736
|
+
limit: Number.isNaN(parsedLimit) ? undefined : parsedLimit,
|
|
1737
|
+
batchSize: Number.isNaN(parsedBatch) ? 1000 : parsedBatch,
|
|
1738
|
+
tags,
|
|
1739
|
+
});
|
|
1740
|
+
} catch (e) {
|
|
1741
|
+
this.dbError = e.message || 'Import failed';
|
|
1742
|
+
}
|
|
1743
|
+
this.dbImportLoading = false;
|
|
1744
|
+
},
|
|
1745
|
+
|
|
1746
|
+
async dbRunExport() {
|
|
1747
|
+
this.dbExportLoading = true;
|
|
1748
|
+
this.dbExportResult = null;
|
|
1749
|
+
this.dbError = '';
|
|
1750
|
+
try {
|
|
1751
|
+
const tags = this.dbExportTags ? this.dbExportTags.split(',').map(t => t.trim()).filter(t => t) : undefined;
|
|
1752
|
+
const parsedExportLimit = this.dbExportLimit ? parseInt(this.dbExportLimit, 10) : undefined;
|
|
1753
|
+
this.dbExportResult = await this.api('POST', '/db/export', {
|
|
1754
|
+
connection: this.dbGetConnection(),
|
|
1755
|
+
table: this.dbExportTable || 'nmt_neurons',
|
|
1756
|
+
tags,
|
|
1757
|
+
limit: Number.isNaN(parsedExportLimit) ? undefined : parsedExportLimit,
|
|
1758
|
+
includeEmbeddings: this.dbExportEmbeddings,
|
|
1759
|
+
includeSynapses: this.dbExportSynapses,
|
|
1760
|
+
restoreSourceData: this.dbExportRestore,
|
|
1761
|
+
});
|
|
1762
|
+
} catch (e) {
|
|
1763
|
+
this.dbError = e.message || 'Export failed';
|
|
1764
|
+
}
|
|
1765
|
+
this.dbExportLoading = false;
|
|
1766
|
+
},
|
|
1767
|
+
|
|
1310
1768
|
formatNumber(v) {
|
|
1311
1769
|
return v == null || v === '--' ? '0' : Number(v).toLocaleString();
|
|
1312
1770
|
},
|