diff --git a/frontend/src/pages/StoreDetailPage.vue b/frontend/src/pages/StoreDetailPage.vue
index 5024395..9ce0b08 100644
--- a/frontend/src/pages/StoreDetailPage.vue
+++ b/frontend/src/pages/StoreDetailPage.vue
@@ -5,9 +5,22 @@
← {{ t('storeDetail.back') }}
@@ -96,6 +109,7 @@ import { computed, onMounted, ref } from 'vue'
import { RouterLink, useRouter } from 'vue-router'
import {
+ deleteStore,
fetchStoreDocuments,
removeDocumentFromStore,
type StoreDocEntry,
@@ -148,6 +162,17 @@ async function removeDoc(doc: StoreDocEntry): Promise
{
selectedIds.value = next
}
+async function onDeleteStore(): Promise {
+ const message = t('stores.deleteConfirm').replace('{name}', props.store)
+ if (!window.confirm(message)) return
+ try {
+ await deleteStore(props.store)
+ router.push({ name: ROUTES.STORES_LIST })
+ } catch (e) {
+ error.value = e instanceof Error ? e.message : String(e)
+ }
+}
+
const allSelected = computed(
() => docs.value.length > 0 && docs.value.every((d) => selectedIds.value.has(d.docId)),
)
@@ -434,6 +459,25 @@ onMounted(load)
color: var(--text);
}
+.header-actions {
+ display: flex;
+ gap: 8px;
+}
+
+.btn-danger {
+ color: #b91c1c;
+ border-color: rgba(220, 38, 38, 0.4);
+}
+
+.btn-danger:hover:not(:disabled) {
+ background: rgba(220, 38, 38, 0.08);
+}
+
+.btn-danger:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
.btn-sm {
padding: 5px 10px;
font-size: 12px;
diff --git a/frontend/src/pages/StoresListPage.vue b/frontend/src/pages/StoresListPage.vue
index 259c4a1..ab473f1 100644
--- a/frontend/src/pages/StoresListPage.vue
+++ b/frontend/src/pages/StoresListPage.vue
@@ -2,6 +2,7 @@
@@ -20,16 +21,18 @@
{{ t('stores.colName') }} |
{{ t('stores.colType') }} |
{{ t('stores.colStatus') }} |
+
{{ t('stores.colDefault') }} |
{{ t('stores.colDocs') }} |
{{ t('stores.colChunks') }} |
+
|
|
|
+
+ {{ store.isDefault ? t('stores.default.yes') : t('stores.default.no') }}
+ |
{{ store.documentCount }} |
{{ store.chunkCount }} |
+
+
+
+ |
@@ -77,6 +96,7 @@
{{ t('stores.empty') }}
+
@@ -85,7 +105,7 @@
import { onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
-import { fetchStores, type StoreInfo } from '../features/store/api'
+import { deleteStore, fetchStores, type StoreInfo } from '../features/store/api'
import { useI18n } from '../shared/i18n'
import { ROUTES } from '../shared/routing/names'
@@ -108,8 +128,27 @@ async function load(): Promise {
}
}
-function openStore(name: string): void {
- router.push({ name: ROUTES.STORE_DETAIL, params: { store: name } })
+function openStore(slug: string): void {
+ router.push({ name: ROUTES.STORE_DETAIL, params: { store: slug } })
+}
+
+function goCreate(): void {
+ router.push({ name: ROUTES.STORE_CREATE })
+}
+
+function goEdit(slug: string): void {
+ router.push({ name: ROUTES.STORE_EDIT, params: { store: slug } })
+}
+
+async function onDelete(store: StoreInfo): Promise {
+ const message = t('stores.deleteConfirm').replace('{name}', store.name)
+ if (!window.confirm(message)) return
+ try {
+ await deleteStore(store.slug)
+ await load()
+ } catch (e) {
+ error.value = e instanceof Error ? e.message : String(e)
+ }
}
onMounted(load)
@@ -126,6 +165,7 @@ onMounted(load)
.stores-header {
display: flex;
align-items: center;
+ justify-content: space-between;
padding: 20px 24px 16px;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
@@ -137,6 +177,22 @@ onMounted(load)
color: var(--text);
}
+.btn-primary {
+ padding: 7px 14px;
+ font-size: 13px;
+ font-weight: 500;
+ color: white;
+ background: var(--accent);
+ border: 1px solid var(--accent);
+ border-radius: var(--radius-sm);
+ cursor: pointer;
+ transition: all var(--transition);
+}
+
+.btn-primary:hover {
+ filter: brightness(1.05);
+}
+
.loading-state {
display: flex;
justify-content: center;
@@ -206,6 +262,11 @@ onMounted(load)
text-align: right;
}
+.col-actions {
+ width: 160px;
+ text-align: right;
+}
+
.stores-table td.col-num {
text-align: right;
}
@@ -323,4 +384,32 @@ onMounted(load)
background: var(--bg-hover);
color: var(--text);
}
+
+.row-action {
+ font-size: 12px;
+ font-weight: 500;
+ padding: 4px 10px;
+ margin-left: 6px;
+ border-radius: var(--radius-sm);
+ border: 1px solid var(--border);
+ background: var(--bg-elevated);
+ color: var(--text-secondary);
+ cursor: pointer;
+ transition: all var(--transition);
+}
+.row-action:hover:not(:disabled) {
+ background: var(--bg-hover);
+ color: var(--text);
+}
+.row-action:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+.row-action--danger {
+ color: #b91c1c;
+ border-color: rgba(220, 38, 38, 0.4);
+}
+.row-action--danger:hover:not(:disabled) {
+ background: rgba(220, 38, 38, 0.08);
+}