diff --git a/bin/server b/bin/server
index 435c020..dfcd1bf 100755
Binary files a/bin/server and b/bin/server differ
diff --git a/internal/repository/status/status.go b/internal/repository/status/status.go
index a18630c..226d27c 100644
--- a/internal/repository/status/status.go
+++ b/internal/repository/status/status.go
@@ -28,7 +28,7 @@ func NewRepository(client database.Client) Repository {
}
func (r *repository) Find(ctx context.Context) ([]*status.Status, error) {
- query := "select id, name, description, position from statuses order by id asc"
+ query := "select id, name, description, position from statuses order by position asc"
rows, err := r.client.Query(ctx, query)
if err != nil {
diff --git a/web/bun.lock b/web/bun.lock
index 97d6c40..6a80736 100644
--- a/web/bun.lock
+++ b/web/bun.lock
@@ -11,7 +11,7 @@
"vue": "^3.5.13",
"vue-draggable-next": "^2.2.1",
"vue-router": "^4.5.0",
- "vuetify": "^3.7.16",
+ "vuetify": "^3.8.2",
},
"devDependencies": {
"@mdi/font": "^7.4.47",
@@ -803,7 +803,7 @@
"vue-tsc": ["vue-tsc@2.2.8", "", { "dependencies": { "@volar/typescript": "~2.4.11", "@vue/language-core": "2.2.8" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "./bin/vue-tsc.js" } }, "sha512-jBYKBNFADTN+L+MdesNX/TB3XuDSyaWynKMDgR+yCSln0GQ9Tfb7JS2lr46s2LiFUT1WsmfWsSvIElyxzOPqcQ=="],
- "vuetify": ["vuetify@3.7.16", "", { "peerDependencies": { "typescript": ">=4.7", "vite-plugin-vuetify": ">=1.0.0", "vue": "^3.3.0", "webpack-plugin-vuetify": ">=2.0.0" }, "optionalPeers": ["typescript", "vite-plugin-vuetify", "webpack-plugin-vuetify"] }, "sha512-Few/cBtgJYgdkzi0LWmVy67G5uc2+q7oWcadbcTUPAtEtGYNh2AM28h01Fk+ScJgfxkA077//ZDff1rh3jYG/w=="],
+ "vuetify": ["vuetify@3.8.2", "", { "peerDependencies": { "typescript": ">=4.7", "vite-plugin-vuetify": ">=2.1.0", "vue": "^3.5.0", "webpack-plugin-vuetify": ">=3.1.0" }, "optionalPeers": ["typescript", "vite-plugin-vuetify", "webpack-plugin-vuetify"] }, "sha512-UJNFP4egmKJTQ3V3MKOq+7vIUKO7/Fko5G6yUsOW2Rm0VNBvAjgO6VY6EnK3DTqEKN6ugVXDEPw37NQSTGLZvw=="],
"which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="],
diff --git a/web/index.html b/web/index.html
index 9e5fc8f..46b049d 100644
--- a/web/index.html
+++ b/web/index.html
@@ -4,6 +4,7 @@
+
Vite App
diff --git a/web/package.json b/web/package.json
index 0539233..dfdbaec 100644
--- a/web/package.json
+++ b/web/package.json
@@ -20,7 +20,7 @@
"vue": "^3.5.13",
"vue-draggable-next": "^2.2.1",
"vue-router": "^4.5.0",
- "vuetify": "^3.7.16"
+ "vuetify": "^3.8.2"
},
"devDependencies": {
"@mdi/font": "^7.4.47",
diff --git a/web/src/components/DynamicMenu.vue b/web/src/components/DynamicMenu.vue
new file mode 100644
index 0000000..836abc1
--- /dev/null
+++ b/web/src/components/DynamicMenu.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ el.title }}
+
+
+
+
+
+
+
+
diff --git a/web/src/components/FormInput.vue b/web/src/components/FormInput.vue
new file mode 100644
index 0000000..a78767b
--- /dev/null
+++ b/web/src/components/FormInput.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+ {{ props.label }}
+ *
+
+
{{ props.description }}
+
+
+
+
+
+
diff --git a/web/src/components/FormTextarea.vue b/web/src/components/FormTextarea.vue
new file mode 100644
index 0000000..676cca0
--- /dev/null
+++ b/web/src/components/FormTextarea.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+ {{ props.label }}
+ *
+
+
{{ props.description }}
+
+
+
+
+
+
diff --git a/web/src/components/IssueCreateForm.vue b/web/src/components/IssueCreateForm.vue
index 636c3eb..76ef00c 100644
--- a/web/src/components/IssueCreateForm.vue
+++ b/web/src/components/IssueCreateForm.vue
@@ -25,6 +25,13 @@ const disabled = computed(() => !issue.value.name)
const addIssue = async () => {
const result = await issuesStore.create(issue.value)
showForm.value = !result
+ issue.value = {
+ name: undefined,
+ description: undefined,
+ status_id: props.status.id,
+ project_id: 1,
+ position: 0,
+ }
}
function onClickOutside() {
@@ -35,15 +42,26 @@ function onClickOutside() {
-
+
- ok
- cancel
+
+
+
+
+
+
diff --git a/web/src/components/IssueItemDetails.vue b/web/src/components/IssueItemDetails.vue
new file mode 100644
index 0000000..c2e6fc4
--- /dev/null
+++ b/web/src/components/IssueItemDetails.vue
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+ {{ issueId }}
+
+
+
+
+ {{ props.selectedIssue.name }}
+
+
description
+
{{ props.selectedIssue.description ?? 'add description' }}
+
+
+
+ save
+ cancel
+
+
+
+
+
+
+
+ assignee:
+
+
+
+ created: {{ created }}
+
+
+
+
+
+
+
+
diff --git a/web/src/components/IssueListItem.vue b/web/src/components/IssueListItem.vue
index f4410a9..d2ff99c 100644
--- a/web/src/components/IssueListItem.vue
+++ b/web/src/components/IssueListItem.vue
@@ -1,36 +1,41 @@
-
+
-
+
- {{ props.issue.description }}
+ {{ props.issue.description }}
-
-
{{ props.issue.name }}
+
+
{{ props.issue.name }}
@@ -39,18 +44,34 @@ async function onDelete() {
-
+
+ mdi-menu
+
-
+
-
- {{ item.title }}
+
Change status
+
+
+
+
+
+
+
+
+
@@ -58,8 +79,4 @@ async function onDelete() {
-
+
diff --git a/web/src/components/IssuesByStatusList.vue b/web/src/components/IssuesByStatusList.vue
index f55e866..b0715e7 100644
--- a/web/src/components/IssuesByStatusList.vue
+++ b/web/src/components/IssuesByStatusList.vue
@@ -12,7 +12,7 @@ const issuesStore = useIssuesStore()
const selectedId = ref()
-const height = 400
+const height = 600
async function onChange(val: {
added: { element: Issue; newIndex: number }
@@ -37,20 +37,20 @@ function onChoose() {
-
+
{{ props.status.name }}
-
+
-
+
-
+
@@ -89,12 +89,4 @@ function onChoose() {
.sortable-drag {
background-color: rgb(var(--v-theme-background));
}
-.animation {
- animation: wave 0.5s linear;
-}
-@keyframes wave {
- 50% {
- background-color: rgba(var(--v-theme-primary), 0.2);
- }
-}
diff --git a/web/src/components/ProjectCreateFlow.vue b/web/src/components/ProjectCreateFlow.vue
new file mode 100644
index 0000000..b24acef
--- /dev/null
+++ b/web/src/components/ProjectCreateFlow.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
Project type
+
+
+
+
+
+ mdi-paper-roll-outline
+
+
+
+
Kanban
+
+ Kanban is all about helping teams visualize their work, limit work currently in progress, and maximize
+ efficiency.
+
+
+
+
+
+
+
+
Project details
+
+ Required fields are marked with an asterisk *
+
+
+
+
+
+
+ create
+
+
+
+
+
diff --git a/web/src/components/StatusMenu.vue b/web/src/components/StatusMenu.vue
new file mode 100644
index 0000000..60e19b9
--- /dev/null
+++ b/web/src/components/StatusMenu.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+ {{ selected?.name }}
+
+
+
+
+
+
+ {{ el.name }}
+
+
+
+
+
+
+
+
diff --git a/web/src/layouts/DefaultLayout.vue b/web/src/layouts/DefaultLayout.vue
index 73c5c1d..7897e06 100644
--- a/web/src/layouts/DefaultLayout.vue
+++ b/web/src/layouts/DefaultLayout.vue
@@ -1,24 +1,39 @@
-
- Application - component: {{ component }}
- {{ el }}
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+
+
+
+
+ Application
-
+
diff --git a/web/src/main.ts b/web/src/main.ts
index 8c2a17a..ea45818 100644
--- a/web/src/main.ts
+++ b/web/src/main.ts
@@ -32,7 +32,7 @@ const vuetify = createVuetify({
VRow: { dense: true },
VSheet: { border: true, rounded: true },
VList: { density: 'compact' },
- VCard: { variant: 'outlined' },
+ // VCard: { variant: 'outlined' },
VChip: { density: 'compact', variant: 'outlined', label: true },
VNumberInput: { hideDetails: true, variant: 'outlined', density: 'compact' },
VBtn: { variant: 'tonal', density: 'compact' },
diff --git a/web/src/router/index.ts b/web/src/router/index.ts
index b5d582b..bf758f4 100644
--- a/web/src/router/index.ts
+++ b/web/src/router/index.ts
@@ -1,6 +1,5 @@
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
-import TestRootView from '@/views/TestRootView.vue'
declare module 'vue-router' {
interface RouteMeta {
@@ -12,17 +11,25 @@ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
- path: '/',
+ path: '',
+ redirect: '/projects',
+ },
+ {
+ path: '/projects',
component: HomeView,
children: [
+ { path: '', component: () => import('@/views/ProjectRootView.vue') },
{
- path: '/',
- name: 'items',
- component: TestRootView,
+ path: ':key/issues',
+ name: 'issues',
+ component: () => import('@/views/IssuesRootView.vue'),
+ props: (route) => ({ selectedIssue: route.query.selectedIssue }),
},
],
},
],
})
+router.beforeResolve((to, from) => {})
+
export default router
diff --git a/web/src/stores/components.ts b/web/src/stores/components.ts
deleted file mode 100644
index beb3cb6..0000000
--- a/web/src/stores/components.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { defineStore } from 'pinia'
-import { computed, ref } from 'vue'
-
-export const useComponentsStore = defineStore('components', () => {
- const count = ref(0)
- const doubleCount = computed(() => count.value * 2)
- function increment() {
- count.value++
- }
-
- return { count, doubleCount, increment }
-})
diff --git a/web/src/stores/issues.ts b/web/src/stores/issues.ts
index 52beede..562b5eb 100644
--- a/web/src/stores/issues.ts
+++ b/web/src/stores/issues.ts
@@ -25,6 +25,7 @@ export interface PositionsDto {
export const useIssuesStore = defineStore('issues', () => {
const issues = ref([])
+ const selectedIssue = ref()
const issuesObj = ref