mirror of
https://github.com/lukaszraczylo/claude-mnemonic.git
synced 2026-06-14 02:11:34 +00:00
Additional abstractions for both sqlite and chroma.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { FilterType, ObservationType, ConceptType } from '@/types'
|
||||
import { OBSERVATION_TYPES, CONCEPT_TYPES } from '@/types/observation'
|
||||
import { useTypes } from '@/composables/useTypes'
|
||||
|
||||
defineProps<{
|
||||
currentFilter: FilterType
|
||||
@@ -16,6 +16,9 @@ const emit = defineEmits<{
|
||||
'update:conceptFilter': [concept: ConceptType | null]
|
||||
}>()
|
||||
|
||||
// Fetch types from API (cached)
|
||||
const { observationTypes, conceptTypes } = useTypes()
|
||||
|
||||
const tabs: { key: FilterType; label: string; icon: string }[] = [
|
||||
{ key: 'all', label: 'All', icon: 'fa-layer-group' },
|
||||
{ key: 'observations', label: 'Observations', icon: 'fa-brain' },
|
||||
@@ -63,7 +66,7 @@ const tabs: { key: FilterType; label: string; icon: string }[] = [
|
||||
@change="emit('update:typeFilter', ($event.target as HTMLSelectElement).value as ObservationType || null)"
|
||||
>
|
||||
<option value="">All Types</option>
|
||||
<option v-for="type in OBSERVATION_TYPES" :key="type" :value="type">
|
||||
<option v-for="type in observationTypes" :key="type" :value="type">
|
||||
{{ type }}
|
||||
</option>
|
||||
</select>
|
||||
@@ -78,7 +81,7 @@ const tabs: { key: FilterType; label: string; icon: string }[] = [
|
||||
@change="emit('update:conceptFilter', ($event.target as HTMLSelectElement).value as ConceptType || null)"
|
||||
>
|
||||
<option value="">All Concepts</option>
|
||||
<option v-for="concept in CONCEPT_TYPES" :key="concept" :value="concept">
|
||||
<option v-for="concept in conceptTypes" :key="concept" :value="concept">
|
||||
{{ concept }}
|
||||
</option>
|
||||
</select>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
|
||||
export interface TypesResponse {
|
||||
observation_types: string[]
|
||||
concept_types: string[]
|
||||
}
|
||||
|
||||
// Default fallback types
|
||||
const DEFAULT_OBSERVATION_TYPES = ['bugfix', 'feature', 'refactor', 'discovery', 'decision', 'change']
|
||||
const DEFAULT_CONCEPT_TYPES = [
|
||||
'gotcha', 'pattern', 'problem-solution', 'trade-off',
|
||||
'how-it-works', 'why-it-exists', 'what-changed',
|
||||
'best-practice', 'anti-pattern', 'architecture',
|
||||
'security', 'performance', 'testing', 'debugging', 'workflow', 'tooling',
|
||||
'refactoring', 'api', 'database', 'configuration', 'error-handling',
|
||||
'caching', 'logging', 'auth', 'validation'
|
||||
]
|
||||
|
||||
// Cached types data (shared across components)
|
||||
const observationTypes = ref<string[]>(DEFAULT_OBSERVATION_TYPES)
|
||||
const conceptTypes = ref<string[]>(DEFAULT_CONCEPT_TYPES)
|
||||
const loaded = ref(false)
|
||||
const loading = ref(false)
|
||||
|
||||
export function useTypes() {
|
||||
const fetchTypes = async () => {
|
||||
if (loaded.value || loading.value) return
|
||||
|
||||
loading.value = true
|
||||
try {
|
||||
const response = await fetch('/api/types')
|
||||
if (!response.ok) throw new Error('Failed to fetch types')
|
||||
const data: TypesResponse = await response.json()
|
||||
observationTypes.value = data.observation_types
|
||||
conceptTypes.value = data.concept_types
|
||||
loaded.value = true
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch types:', error)
|
||||
// Keep defaults
|
||||
loaded.value = true
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch on first use
|
||||
onMounted(fetchTypes)
|
||||
|
||||
return {
|
||||
observationTypes,
|
||||
conceptTypes,
|
||||
loaded,
|
||||
loading,
|
||||
fetchTypes
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,15 @@
|
||||
export type ObservationType = 'bugfix' | 'feature' | 'refactor' | 'discovery' | 'decision' | 'change'
|
||||
export type ObservationScope = 'project' | 'global'
|
||||
export type ConceptType = 'gotcha' | 'pattern' | 'problem-solution' | 'trade-off' | 'how-it-works' | 'why-it-exists' | 'what-changed'
|
||||
export type ConceptType =
|
||||
// Semantic concepts
|
||||
| 'gotcha' | 'pattern' | 'problem-solution' | 'trade-off'
|
||||
| 'how-it-works' | 'why-it-exists' | 'what-changed'
|
||||
// Globalizable concepts
|
||||
| 'best-practice' | 'anti-pattern' | 'architecture'
|
||||
| 'security' | 'performance' | 'testing' | 'debugging' | 'workflow' | 'tooling'
|
||||
// Additional useful concepts
|
||||
| 'refactoring' | 'api' | 'database' | 'configuration' | 'error-handling'
|
||||
| 'caching' | 'logging' | 'auth' | 'validation'
|
||||
|
||||
export interface Observation {
|
||||
id: number
|
||||
@@ -26,13 +35,34 @@ export interface Observation {
|
||||
export const OBSERVATION_TYPES: ObservationType[] = ['bugfix', 'feature', 'refactor', 'discovery', 'decision', 'change']
|
||||
|
||||
export const CONCEPT_TYPES: ConceptType[] = [
|
||||
// Semantic concepts
|
||||
'gotcha',
|
||||
'pattern',
|
||||
'problem-solution',
|
||||
'trade-off',
|
||||
'how-it-works',
|
||||
'why-it-exists',
|
||||
'what-changed'
|
||||
'what-changed',
|
||||
// Globalizable concepts
|
||||
'best-practice',
|
||||
'anti-pattern',
|
||||
'architecture',
|
||||
'security',
|
||||
'performance',
|
||||
'testing',
|
||||
'debugging',
|
||||
'workflow',
|
||||
'tooling',
|
||||
// Additional useful concepts
|
||||
'refactoring',
|
||||
'api',
|
||||
'database',
|
||||
'configuration',
|
||||
'error-handling',
|
||||
'caching',
|
||||
'logging',
|
||||
'auth',
|
||||
'validation'
|
||||
]
|
||||
|
||||
export const TYPE_CONFIG: Record<ObservationType, { icon: string; colorClass: string; bgClass: string; borderClass: string; gradient: string }> = {
|
||||
@@ -44,7 +74,11 @@ export const TYPE_CONFIG: Record<ObservationType, { icon: string; colorClass: st
|
||||
decision: { icon: 'fa-scale-balanced', colorClass: 'text-yellow-300', bgClass: 'bg-yellow-500/20', borderClass: 'border-yellow-500/30', gradient: 'from-yellow-500 to-yellow-700' },
|
||||
}
|
||||
|
||||
// Default config for unknown concepts
|
||||
const DEFAULT_CONCEPT_CONFIG = { icon: 'fa-tag', colorClass: 'text-slate-300', bgClass: 'bg-slate-500/20', borderClass: 'border-slate-500/40' }
|
||||
|
||||
export const CONCEPT_CONFIG: Record<ConceptType, { icon: string; colorClass: string; bgClass: string; borderClass: string }> = {
|
||||
// Semantic concepts
|
||||
gotcha: { icon: 'fa-triangle-exclamation', colorClass: 'text-red-300', bgClass: 'bg-red-500/20', borderClass: 'border-red-500/40' },
|
||||
pattern: { icon: 'fa-puzzle-piece', colorClass: 'text-purple-300', bgClass: 'bg-purple-500/20', borderClass: 'border-purple-500/40' },
|
||||
'problem-solution': { icon: 'fa-lightbulb', colorClass: 'text-blue-300', bgClass: 'bg-blue-500/20', borderClass: 'border-blue-500/40' },
|
||||
@@ -52,4 +86,29 @@ export const CONCEPT_CONFIG: Record<ConceptType, { icon: string; colorClass: str
|
||||
'how-it-works': { icon: 'fa-gear', colorClass: 'text-cyan-300', bgClass: 'bg-cyan-500/20', borderClass: 'border-cyan-500/40' },
|
||||
'why-it-exists': { icon: 'fa-circle-question', colorClass: 'text-green-300', bgClass: 'bg-green-500/20', borderClass: 'border-green-500/40' },
|
||||
'what-changed': { icon: 'fa-clipboard-list', colorClass: 'text-slate-300', bgClass: 'bg-slate-500/20', borderClass: 'border-slate-500/40' },
|
||||
// Globalizable concepts
|
||||
'best-practice': { icon: 'fa-check-circle', colorClass: 'text-emerald-300', bgClass: 'bg-emerald-500/20', borderClass: 'border-emerald-500/40' },
|
||||
'anti-pattern': { icon: 'fa-ban', colorClass: 'text-red-300', bgClass: 'bg-red-500/20', borderClass: 'border-red-500/40' },
|
||||
architecture: { icon: 'fa-sitemap', colorClass: 'text-indigo-300', bgClass: 'bg-indigo-500/20', borderClass: 'border-indigo-500/40' },
|
||||
security: { icon: 'fa-shield-halved', colorClass: 'text-rose-300', bgClass: 'bg-rose-500/20', borderClass: 'border-rose-500/40' },
|
||||
performance: { icon: 'fa-gauge-high', colorClass: 'text-orange-300', bgClass: 'bg-orange-500/20', borderClass: 'border-orange-500/40' },
|
||||
testing: { icon: 'fa-vial', colorClass: 'text-teal-300', bgClass: 'bg-teal-500/20', borderClass: 'border-teal-500/40' },
|
||||
debugging: { icon: 'fa-bug', colorClass: 'text-amber-300', bgClass: 'bg-amber-500/20', borderClass: 'border-amber-500/40' },
|
||||
workflow: { icon: 'fa-diagram-project', colorClass: 'text-violet-300', bgClass: 'bg-violet-500/20', borderClass: 'border-violet-500/40' },
|
||||
tooling: { icon: 'fa-wrench', colorClass: 'text-zinc-300', bgClass: 'bg-zinc-500/20', borderClass: 'border-zinc-500/40' },
|
||||
// Additional useful concepts
|
||||
refactoring: { icon: 'fa-rotate', colorClass: 'text-blue-300', bgClass: 'bg-blue-500/20', borderClass: 'border-blue-500/40' },
|
||||
api: { icon: 'fa-plug', colorClass: 'text-lime-300', bgClass: 'bg-lime-500/20', borderClass: 'border-lime-500/40' },
|
||||
database: { icon: 'fa-database', colorClass: 'text-sky-300', bgClass: 'bg-sky-500/20', borderClass: 'border-sky-500/40' },
|
||||
configuration: { icon: 'fa-sliders', colorClass: 'text-fuchsia-300', bgClass: 'bg-fuchsia-500/20', borderClass: 'border-fuchsia-500/40' },
|
||||
'error-handling': { icon: 'fa-circle-exclamation', colorClass: 'text-red-300', bgClass: 'bg-red-500/20', borderClass: 'border-red-500/40' },
|
||||
caching: { icon: 'fa-bolt', colorClass: 'text-yellow-300', bgClass: 'bg-yellow-500/20', borderClass: 'border-yellow-500/40' },
|
||||
logging: { icon: 'fa-file-lines', colorClass: 'text-gray-300', bgClass: 'bg-gray-500/20', borderClass: 'border-gray-500/40' },
|
||||
auth: { icon: 'fa-key', colorClass: 'text-amber-300', bgClass: 'bg-amber-500/20', borderClass: 'border-amber-500/40' },
|
||||
validation: { icon: 'fa-check', colorClass: 'text-green-300', bgClass: 'bg-green-500/20', borderClass: 'border-green-500/40' },
|
||||
}
|
||||
|
||||
// Helper to get config with fallback for unknown concepts
|
||||
export function getConceptConfig(concept: string) {
|
||||
return CONCEPT_CONFIG[concept as ConceptType] || DEFAULT_CONCEPT_CONFIG
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user