@intranefr/superbackend 1.6.7 → 1.7.8
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/.beads/.br_history/issues.20260314_212352_900045509.jsonl +0 -0
- package/.beads/.br_history/issues.20260314_212352_900045509.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_087140743.jsonl +1 -0
- package/.beads/.br_history/issues.20260314_212353_087140743.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_285881504.jsonl +2 -0
- package/.beads/.br_history/issues.20260314_212353_285881504.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_473915419.jsonl +3 -0
- package/.beads/.br_history/issues.20260314_212353_473915419.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_659476307.jsonl +4 -0
- package/.beads/.br_history/issues.20260314_212353_659476307.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212353_869998925.jsonl +5 -0
- package/.beads/.br_history/issues.20260314_212353_869998925.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_212354_054785029.jsonl +6 -0
- package/.beads/.br_history/issues.20260314_212354_054785029.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_175893691.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_175893691.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_338509797.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_338509797.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_515443192.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_515443192.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_676417592.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_676417592.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213336_839182422.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213336_839182422.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213337_004349113.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213337_004349113.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213337_179824080.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213337_179824080.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213701_705075332.jsonl +7 -0
- package/.beads/.br_history/issues.20260314_213701_705075332.jsonl.meta.json +1 -0
- package/.beads/.br_history/issues.20260314_213706_783128702.jsonl +8 -0
- package/.beads/.br_history/issues.20260314_213706_783128702.jsonl.meta.json +1 -0
- package/.beads/config.yaml +4 -0
- package/.beads/issues.jsonl +8 -0
- package/.beads/metadata.json +4 -0
- package/.env.example +8 -0
- package/autochangelog/.env.example +36 -0
- package/autochangelog/README.md +412 -0
- package/autochangelog/config/database.js +27 -0
- package/autochangelog/package.json +47 -0
- package/autochangelog/public/landing.html +581 -0
- package/autochangelog/server.js +104 -0
- package/autochangelog/src/app.js +181 -0
- package/autochangelog/src/config/database.js +26 -0
- package/autochangelog/src/controllers/auth.js +488 -0
- package/autochangelog/src/controllers/changelog.js +682 -0
- package/autochangelog/src/controllers/project.js +580 -0
- package/autochangelog/src/controllers/repository.js +780 -0
- package/autochangelog/src/middleware/auth.js +386 -0
- package/autochangelog/src/models/Changelog.js +443 -0
- package/autochangelog/src/models/Project.js +226 -0
- package/autochangelog/src/models/Repository.js +366 -0
- package/autochangelog/src/models/User.js +223 -0
- package/autochangelog/src/routes/auth.routes.js +32 -0
- package/autochangelog/src/routes/changelog.routes.js +42 -0
- package/autochangelog/src/routes/github-auth.routes.js +102 -0
- package/autochangelog/src/routes/project.routes.js +50 -0
- package/autochangelog/src/routes/repository.routes.js +54 -0
- package/autochangelog/src/services/changelog.js +722 -0
- package/autochangelog/src/services/github.js +243 -0
- package/autochangelog/utils/logger.js +77 -0
- package/autochangelog/views/404.ejs +18 -0
- package/autochangelog/views/dashboard.ejs +596 -0
- package/autochangelog/views/index.ejs +231 -0
- package/autochangelog/views/layouts/main.ejs +44 -0
- package/autochangelog/views/login.ejs +104 -0
- package/autochangelog/views/partials/footer.ejs +20 -0
- package/autochangelog/views/partials/navbar.ejs +51 -0
- package/autochangelog/views/register.ejs +109 -0
- package/autochangelog-cli/README.md +266 -0
- package/autochangelog-cli/bin/autochangelog +120 -0
- package/autochangelog-cli/package.json +46 -0
- package/autochangelog-cli/src/cli/commands/auth.js +291 -0
- package/autochangelog-cli/src/cli/commands/changelog.js +619 -0
- package/autochangelog-cli/src/cli/commands/project.js +427 -0
- package/autochangelog-cli/src/cli/commands/repo.js +557 -0
- package/autochangelog-cli/src/cli/commands/stats.js +706 -0
- package/autochangelog-cli/src/cli/utils/config.js +277 -0
- package/autochangelog-cli/src/cli/utils/errors.js +307 -0
- package/autochangelog-cli/src/cli/utils/logger.js +75 -0
- package/autochangelog-cli/src/cli/utils/output.js +357 -0
- package/package.json +9 -3
- package/plugins/supercli/README.md +108 -0
- package/plugins/supercli/plugin.json +123 -0
- package/server.js +1 -1
- package/src/cli/api.js +380 -0
- package/src/cli/direct/agent-utils.js +61 -0
- package/src/cli/direct/cli-utils.js +112 -0
- package/src/cli/direct/data-seeding.js +307 -0
- package/src/cli/direct/db-admin.js +84 -0
- package/src/cli/direct/db-advanced.js +372 -0
- package/src/cli/direct/db-utils.js +558 -0
- package/src/cli/direct/help.js +195 -0
- package/src/cli/direct/migration.js +107 -0
- package/src/cli/direct/rbac-advanced.js +132 -0
- package/src/cli/direct/resources-additional.js +400 -0
- package/src/cli/direct/resources-cms-advanced.js +173 -0
- package/src/cli/direct/resources-cms.js +247 -0
- package/src/cli/direct/resources-core.js +253 -0
- package/src/cli/direct/resources-execution.js +367 -0
- package/src/cli/direct/resources-health.js +152 -0
- package/src/cli/direct/resources-integrations.js +182 -0
- package/src/cli/direct/resources-logs.js +204 -0
- package/src/cli/direct/resources-org-rbac.js +187 -0
- package/src/cli/direct/resources-system.js +236 -0
- package/src/cli/direct.js +556 -0
- package/src/controllers/admin.controller.js +4 -0
- package/src/controllers/auth.controller.js +148 -1
- package/src/controllers/waitingList.controller.js +130 -1
- package/src/models/RbacRole.js +1 -1
- package/src/models/User.js +39 -5
- package/src/routes/auth.routes.js +6 -0
- package/src/routes/waitingList.routes.js +12 -2
- package/src/routes/waitingListAdmin.routes.js +3 -0
- package/src/services/email.service.js +1 -0
- package/src/services/github.service.js +255 -0
- package/src/services/rateLimiter.service.js +29 -1
- package/src/services/waitingListJson.service.js +32 -3
- package/views/admin-waiting-list.ejs +386 -3
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" data-theme="light">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title><%= title %></title>
|
|
7
|
+
|
|
8
|
+
<!-- Tailwind CSS CDN -->
|
|
9
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
10
|
+
|
|
11
|
+
<!-- DaisyUI CDN -->
|
|
12
|
+
<link href="https://cdn.jsdelivr.net/npm/daisyui@4.4.19/dist/full.min.css" rel="stylesheet" type="text/css" />
|
|
13
|
+
|
|
14
|
+
<!-- Vue 3 CDN -->
|
|
15
|
+
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
|
16
|
+
|
|
17
|
+
<style>
|
|
18
|
+
[v-cloak] { display: none; }
|
|
19
|
+
.fade-enter-active, .fade-leave-active { transition: opacity 0.3s; }
|
|
20
|
+
.fade-enter, .fade-leave-to { opacity: 0; }
|
|
21
|
+
</style>
|
|
22
|
+
|
|
23
|
+
<script>
|
|
24
|
+
tailwind.config = {
|
|
25
|
+
theme: {
|
|
26
|
+
extend: {
|
|
27
|
+
colors: {
|
|
28
|
+
primary: '#3b82f6',
|
|
29
|
+
secondary: '#8b5cf6',
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
35
|
+
</head>
|
|
36
|
+
<body class="min-h-screen bg-base-100">
|
|
37
|
+
<div id="app" v-cloak>
|
|
38
|
+
<!-- Dashboard Layout -->
|
|
39
|
+
<div class="drawer lg:drawer-open">
|
|
40
|
+
<input id="drawer-toggle" type="checkbox" class="drawer-toggle" />
|
|
41
|
+
|
|
42
|
+
<div class="drawer-content flex flex-col">
|
|
43
|
+
<!-- Top Navbar -->
|
|
44
|
+
<div class="navbar bg-base-100 shadow-sm lg:hidden">
|
|
45
|
+
<div class="flex-none">
|
|
46
|
+
<label for="drawer-toggle" class="btn btn-square btn-ghost">
|
|
47
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
48
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
|
49
|
+
</svg>
|
|
50
|
+
</label>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="flex-1">
|
|
53
|
+
<span class="text-xl font-bold">AutoChangelog</span>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<!-- Main Content -->
|
|
58
|
+
<main class="flex-1 p-4 lg:p-8">
|
|
59
|
+
<!-- Header -->
|
|
60
|
+
<div class="flex justify-between items-center mb-8">
|
|
61
|
+
<div>
|
|
62
|
+
<h1 class="text-3xl font-bold">{{ currentViewTitle }}</h1>
|
|
63
|
+
<p class="text-gray-500 mt-1">{{ currentViewDescription }}</p>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="flex gap-2">
|
|
66
|
+
<button v-if="currentView === 'projects'" @click="showNewProjectModal = true" class="btn btn-primary">
|
|
67
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
68
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
|
69
|
+
</svg>
|
|
70
|
+
New Project
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<!-- Stats Cards -->
|
|
76
|
+
<div v-if="currentView === 'dashboard'" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
|
77
|
+
<div class="stat bg-base-200 rounded-box">
|
|
78
|
+
<div class="stat-title">Projects</div>
|
|
79
|
+
<div class="stat-value text-primary">{{ stats.projects }}</div>
|
|
80
|
+
<div class="stat-desc">Active projects</div>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="stat bg-base-200 rounded-box">
|
|
83
|
+
<div class="stat-title">Repositories</div>
|
|
84
|
+
<div class="stat-value text-secondary">{{ stats.repositories }}</div>
|
|
85
|
+
<div class="stat-desc">Connected repos</div>
|
|
86
|
+
</div>
|
|
87
|
+
<div class="stat bg-base-200 rounded-box">
|
|
88
|
+
<div class="stat-title">Changelogs</div>
|
|
89
|
+
<div class="stat-value">{{ stats.changelogs }}</div>
|
|
90
|
+
<div class="stat-desc">Generated this month</div>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="stat bg-base-200 rounded-box">
|
|
93
|
+
<div class="stat-title">Plan</div>
|
|
94
|
+
<div class="stat-value text-success">{{ stats.plan }}</div>
|
|
95
|
+
<div class="stat-desc">
|
|
96
|
+
<a href="/pricing" class="link link-primary">Upgrade</a>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<!-- Projects List -->
|
|
102
|
+
<div v-if="currentView === 'projects'" class="space-y-4">
|
|
103
|
+
<div v-if="projects.length === 0" class="text-center py-12">
|
|
104
|
+
<div class="text-6xl mb-4">📁</div>
|
|
105
|
+
<h3 class="text-xl font-bold mb-2">No projects yet</h3>
|
|
106
|
+
<p class="text-gray-500 mb-4">Create your first project to start generating changelogs</p>
|
|
107
|
+
<button @click="showNewProjectModal = true" class="btn btn-primary">Create Project</button>
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div v-else class="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
111
|
+
<div v-for="project in projects" :key="project._id" class="card bg-base-100 shadow-xl hover:shadow-2xl transition-shadow cursor-pointer" @click="selectProject(project)">
|
|
112
|
+
<div class="card-body">
|
|
113
|
+
<h3 class="card-title">{{ project.name }}</h3>
|
|
114
|
+
<p class="text-gray-500 text-sm">{{ project.description || 'No description' }}</p>
|
|
115
|
+
<div class="flex gap-2 mt-4">
|
|
116
|
+
<div class="badge badge-outline">{{ project.metadata?.totalRepositories || 0 }} repos</div>
|
|
117
|
+
<div class="badge badge-outline">{{ project.metadata?.totalChangelogs || 0 }} changelogs</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<!-- Repositories List -->
|
|
125
|
+
<div v-if="currentView === 'repositories'" class="space-y-4">
|
|
126
|
+
<div v-if="!selectedProject" class="text-center py-12">
|
|
127
|
+
<div class="text-6xl mb-4">📁</div>
|
|
128
|
+
<h3 class="text-xl font-bold mb-2">Select a project first</h3>
|
|
129
|
+
<p class="text-gray-500 mb-4">Choose a project from the Projects tab to manage its repositories</p>
|
|
130
|
+
<button @click="currentView = 'projects'" class="btn btn-primary">Go to Projects</button>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div v-else-if="repositories.length === 0" class="text-center py-12">
|
|
134
|
+
<div class="text-6xl mb-4">🔗</div>
|
|
135
|
+
<h3 class="text-xl font-bold mb-2">No repositories connected</h3>
|
|
136
|
+
<p class="text-gray-500 mb-4">Connect a GitHub repository to start generating changelogs</p>
|
|
137
|
+
<button @click="connectRepository" class="btn btn-primary">Connect Repository</button>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<div v-else class="space-y-4">
|
|
141
|
+
<div class="flex justify-between items-center mb-4">
|
|
142
|
+
<h2 class="text-xl font-bold">Repositories for {{ selectedProject.name }}</h2>
|
|
143
|
+
<button @click="connectRepository" class="btn btn-primary btn-sm">
|
|
144
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
145
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
|
146
|
+
</svg>
|
|
147
|
+
Connect Repository
|
|
148
|
+
</button>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div v-for="repo in repositories" :key="repo._id" class="card bg-base-100 shadow-lg">
|
|
152
|
+
<div class="card-body flex flex-row items-center justify-between">
|
|
153
|
+
<div>
|
|
154
|
+
<h3 class="card-title">
|
|
155
|
+
<a :href="repo.githubRepoUrl" target="_blank" class="hover:underline">
|
|
156
|
+
{{ repo.githubRepoFullName }}
|
|
157
|
+
</a>
|
|
158
|
+
</h3>
|
|
159
|
+
<p class="text-gray-500 text-sm">{{ repo.description || 'No description' }}</p>
|
|
160
|
+
<div class="flex gap-2 mt-2">
|
|
161
|
+
<div class="badge" :class="repo.status === 'active' ? 'badge-success' : 'badge-error'">{{ repo.status }}</div>
|
|
162
|
+
<div class="badge badge-outline">{{ repo.defaultBranch }}</div>
|
|
163
|
+
<div class="badge badge-ghost" v-if="repo.isPrivate">Private</div>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
<div class="flex gap-2">
|
|
167
|
+
<button @click="generateChangelog(repo)" class="btn btn-primary btn-sm">Generate Changelog</button>
|
|
168
|
+
<button @click="viewChangelogs(repo)" class="btn btn-ghost btn-sm">View History</button>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
<!-- Changelogs List -->
|
|
176
|
+
<div v-if="currentView === 'changelogs'" class="space-y-4">
|
|
177
|
+
<div v-if="changelogs.length === 0" class="text-center py-12">
|
|
178
|
+
<div class="text-6xl mb-4">📝</div>
|
|
179
|
+
<h3 class="text-xl font-bold mb-2">No changelogs yet</h3>
|
|
180
|
+
<p class="text-gray-500 mb-4">Generate your first changelog from a repository</p>
|
|
181
|
+
<button @click="currentView = 'repositories'" class="btn btn-primary">Go to Repositories</button>
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
<div v-else class="space-y-4">
|
|
185
|
+
<div v-for="changelog in changelogs" :key="changelog._id" class="card bg-base-100 shadow-lg">
|
|
186
|
+
<div class="card-body">
|
|
187
|
+
<div class="flex justify-between items-start">
|
|
188
|
+
<div>
|
|
189
|
+
<h3 class="card-title">{{ changelog.title }}</h3>
|
|
190
|
+
<p class="text-gray-500 text-sm">{{ changelog.month }}/{{ changelog.year }}</p>
|
|
191
|
+
</div>
|
|
192
|
+
<div class="badge" :class="{
|
|
193
|
+
'badge-success': changelog.status === 'completed',
|
|
194
|
+
'badge-warning': changelog.status === 'generating',
|
|
195
|
+
'badge-error': changelog.status === 'failed'
|
|
196
|
+
}">{{ changelog.status }}</div>
|
|
197
|
+
</div>
|
|
198
|
+
<div class="flex gap-2 mt-4">
|
|
199
|
+
<button @click="downloadChangelog(changelog)" class="btn btn-outline btn-sm">Download</button>
|
|
200
|
+
<button @click="viewChangelog(changelog)" class="btn btn-ghost btn-sm">View</button>
|
|
201
|
+
</div>
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</main>
|
|
207
|
+
</div>
|
|
208
|
+
|
|
209
|
+
<!-- Sidebar -->
|
|
210
|
+
<div class="drawer-side">
|
|
211
|
+
<label for="drawer-toggle" class="drawer-overlay"></label>
|
|
212
|
+
<aside class="bg-base-200 w-80 min-h-full">
|
|
213
|
+
<div class="p-4">
|
|
214
|
+
<a href="/" class="btn btn-ghost normal-case text-xl mb-4">
|
|
215
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 mr-2 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
216
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
217
|
+
</svg>
|
|
218
|
+
AutoChangelog
|
|
219
|
+
</a>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
<ul class="menu p-4 w-full">
|
|
223
|
+
<li>
|
|
224
|
+
<a @click.prevent="currentView = 'dashboard'" :class="{ 'active': currentView === 'dashboard' }" href="#">
|
|
225
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
226
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z" />
|
|
227
|
+
</svg>
|
|
228
|
+
Dashboard
|
|
229
|
+
</a>
|
|
230
|
+
</li>
|
|
231
|
+
<li>
|
|
232
|
+
<a @click.prevent="currentView = 'projects'" :class="{ 'active': currentView === 'projects' }" href="#">
|
|
233
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
234
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" />
|
|
235
|
+
</svg>
|
|
236
|
+
Projects
|
|
237
|
+
</a>
|
|
238
|
+
</li>
|
|
239
|
+
<li>
|
|
240
|
+
<a @click.prevent="currentView = 'repositories'" :class="{ 'active': currentView === 'repositories' }" href="#">
|
|
241
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
242
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
|
|
243
|
+
</svg>
|
|
244
|
+
Repositories
|
|
245
|
+
</a>
|
|
246
|
+
</li>
|
|
247
|
+
<li>
|
|
248
|
+
<a @click.prevent="currentView = 'changelogs'" :class="{ 'active': currentView === 'changelogs' }" href="#">
|
|
249
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
250
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
251
|
+
</svg>
|
|
252
|
+
Changelogs
|
|
253
|
+
</a>
|
|
254
|
+
</li>
|
|
255
|
+
</ul>
|
|
256
|
+
|
|
257
|
+
<div class="divider"></div>
|
|
258
|
+
|
|
259
|
+
<ul class="menu p-4 w-full">
|
|
260
|
+
<li>
|
|
261
|
+
<a href="/settings">
|
|
262
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
263
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
|
264
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
265
|
+
</svg>
|
|
266
|
+
Settings
|
|
267
|
+
</a>
|
|
268
|
+
</li>
|
|
269
|
+
<li>
|
|
270
|
+
<a href="/auth/logout">
|
|
271
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
272
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
|
273
|
+
</svg>
|
|
274
|
+
Logout
|
|
275
|
+
</a>
|
|
276
|
+
</li>
|
|
277
|
+
</ul>
|
|
278
|
+
</aside>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<!-- New Project Modal -->
|
|
283
|
+
<dialog :open="showNewProjectModal" class="modal" :class="{ 'modal-open': showNewProjectModal }">
|
|
284
|
+
<div class="modal-box">
|
|
285
|
+
<h3 class="font-bold text-lg">Create New Project</h3>
|
|
286
|
+
<form @submit.prevent="createProject" class="py-4">
|
|
287
|
+
<div class="form-control">
|
|
288
|
+
<label class="label">
|
|
289
|
+
<span class="label-text">Project Name</span>
|
|
290
|
+
</label>
|
|
291
|
+
<input v-model="newProject.name" type="text" placeholder="My Awesome Project" class="input input-bordered" required />
|
|
292
|
+
</div>
|
|
293
|
+
<div class="form-control mt-4">
|
|
294
|
+
<label class="label">
|
|
295
|
+
<span class="label-text">Description (optional)</span>
|
|
296
|
+
</label>
|
|
297
|
+
<textarea v-model="newProject.description" class="textarea textarea-bordered" placeholder="Brief description of your project"></textarea>
|
|
298
|
+
</div>
|
|
299
|
+
<div class="modal-action">
|
|
300
|
+
<button type="button" @click="showNewProjectModal = false" class="btn">Cancel</button>
|
|
301
|
+
<button type="submit" class="btn btn-primary" :disabled="creatingProject">
|
|
302
|
+
<span v-if="creatingProject" class="loading loading-spinner loading-sm mr-2"></span>
|
|
303
|
+
Create Project
|
|
304
|
+
</button>
|
|
305
|
+
</div>
|
|
306
|
+
</form>
|
|
307
|
+
</div>
|
|
308
|
+
<form method="dialog" class="modal-backdrop">
|
|
309
|
+
<button @click="showNewProjectModal = false">close</button>
|
|
310
|
+
</form>
|
|
311
|
+
</dialog>
|
|
312
|
+
|
|
313
|
+
<!-- GitHub Repository Selection Modal -->
|
|
314
|
+
<dialog :open="showRepoModal" class="modal" :class="{ 'modal-open': showRepoModal }">
|
|
315
|
+
<div class="modal-box w-11/12 max-w-5xl">
|
|
316
|
+
<h3 class="font-bold text-lg mb-4">Connect GitHub Repository</h3>
|
|
317
|
+
<div v-if="loadingRepos" class="flex justify-center py-8">
|
|
318
|
+
<span class="loading loading-spinner loading-lg"></span>
|
|
319
|
+
</div>
|
|
320
|
+
<div v-else-if="githubRepos.length === 0" class="text-center py-8">
|
|
321
|
+
<p class="text-gray-500">No repositories found or all repos are already connected</p>
|
|
322
|
+
</div>
|
|
323
|
+
<div v-else class="space-y-2 max-h-96 overflow-y-auto">
|
|
324
|
+
<div
|
|
325
|
+
v-for="repo in githubRepos"
|
|
326
|
+
:key="repo.id"
|
|
327
|
+
class="card bg-base-200 hover:bg-base-300 cursor-pointer transition-colors"
|
|
328
|
+
@click="selectGithubRepo(repo)"
|
|
329
|
+
>
|
|
330
|
+
<div class="card-body p-4">
|
|
331
|
+
<div class="flex justify-between items-center">
|
|
332
|
+
<div>
|
|
333
|
+
<h4 class="font-bold">{{ repo.full_name }}</h4>
|
|
334
|
+
<p class="text-sm text-gray-500">{{ repo.description || 'No description' }}</p>
|
|
335
|
+
<div class="flex gap-2 mt-2 text-xs">
|
|
336
|
+
<span class="badge badge-ghost">{{ repo.visibility || 'public' }}</span>
|
|
337
|
+
<span class="badge badge-ghost">{{ repo.language || 'Code' }}</span>
|
|
338
|
+
<span class="badge badge-ghost">{{ repo.stargazers_count }} ⭐</span>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
<div class="text-right">
|
|
342
|
+
<div class="text-xs text-gray-500">Updated</div>
|
|
343
|
+
<div class="text-sm">{{ new Date(repo.updated_at).toLocaleDateString() }}</div>
|
|
344
|
+
</div>
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
</div>
|
|
349
|
+
<div class="modal-action">
|
|
350
|
+
<button type="button" @click="showRepoModal = false" class="btn">Cancel</button>
|
|
351
|
+
</div>
|
|
352
|
+
</div>
|
|
353
|
+
<form method="dialog" class="modal-backdrop">
|
|
354
|
+
<button @click="showRepoModal = false">close</button>
|
|
355
|
+
</form>
|
|
356
|
+
</dialog>
|
|
357
|
+
</div>
|
|
358
|
+
|
|
359
|
+
<script>
|
|
360
|
+
const { createApp } = Vue;
|
|
361
|
+
|
|
362
|
+
// Extract token from URL hash if present (from GitHub OAuth)
|
|
363
|
+
const urlHash = window.location.hash;
|
|
364
|
+
if (urlHash.startsWith('#token=')) {
|
|
365
|
+
const token = urlHash.substring(7); // Remove '#token=' prefix
|
|
366
|
+
localStorage.setItem('token', token);
|
|
367
|
+
// Clear the hash from URL
|
|
368
|
+
history.replaceState(null, null, ' ');
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
createApp({
|
|
372
|
+
data() {
|
|
373
|
+
return {
|
|
374
|
+
currentView: 'dashboard',
|
|
375
|
+
selectedProject: null,
|
|
376
|
+
projects: [],
|
|
377
|
+
repositories: [],
|
|
378
|
+
changelogs: [],
|
|
379
|
+
stats: {
|
|
380
|
+
projects: 0,
|
|
381
|
+
repositories: 0,
|
|
382
|
+
changelogs: 0,
|
|
383
|
+
plan: 'Free'
|
|
384
|
+
},
|
|
385
|
+
showNewProjectModal: false,
|
|
386
|
+
showRepoModal: false,
|
|
387
|
+
creatingProject: false,
|
|
388
|
+
loadingRepos: false,
|
|
389
|
+
githubRepos: [],
|
|
390
|
+
newProject: {
|
|
391
|
+
name: '',
|
|
392
|
+
description: ''
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
computed: {
|
|
397
|
+
currentViewTitle() {
|
|
398
|
+
const titles = {
|
|
399
|
+
dashboard: 'Dashboard',
|
|
400
|
+
projects: 'Projects',
|
|
401
|
+
repositories: 'Repositories',
|
|
402
|
+
changelogs: 'Changelogs'
|
|
403
|
+
};
|
|
404
|
+
return titles[this.currentView] || 'Dashboard';
|
|
405
|
+
},
|
|
406
|
+
currentViewDescription() {
|
|
407
|
+
const descriptions = {
|
|
408
|
+
dashboard: 'Overview of your activity',
|
|
409
|
+
projects: 'Manage your projects',
|
|
410
|
+
repositories: 'Connected GitHub repositories',
|
|
411
|
+
changelogs: 'Generated changelogs'
|
|
412
|
+
};
|
|
413
|
+
return descriptions[this.currentView] || '';
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
async mounted() {
|
|
417
|
+
await this.loadDashboard();
|
|
418
|
+
},
|
|
419
|
+
methods: {
|
|
420
|
+
async loadDashboard() {
|
|
421
|
+
try {
|
|
422
|
+
const token = localStorage.getItem('token');
|
|
423
|
+
if (!token) {
|
|
424
|
+
// No token - redirect to login
|
|
425
|
+
window.location.href = '/auth/login';
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Load stats
|
|
430
|
+
const statsRes = await fetch('/api/projects/stats', {
|
|
431
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
432
|
+
});
|
|
433
|
+
if (statsRes.ok) {
|
|
434
|
+
const statsData = await statsRes.json();
|
|
435
|
+
if (statsData.success) {
|
|
436
|
+
this.stats = { ...this.stats, ...statsData.data };
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Load projects
|
|
441
|
+
await this.loadProjects();
|
|
442
|
+
} catch (error) {
|
|
443
|
+
console.error('Error loading dashboard:', error);
|
|
444
|
+
}
|
|
445
|
+
},
|
|
446
|
+
async loadProjects() {
|
|
447
|
+
try {
|
|
448
|
+
const res = await fetch('/api/projects', {
|
|
449
|
+
headers: { 'Authorization': `Bearer ${localStorage.getItem("token")}` }
|
|
450
|
+
});
|
|
451
|
+
if (res.ok) {
|
|
452
|
+
const data = await res.json();
|
|
453
|
+
if (data.success) {
|
|
454
|
+
this.projects = data.data || [];
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
} catch (error) {
|
|
458
|
+
console.error('Error loading projects:', error);
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
async createProject() {
|
|
462
|
+
this.creatingProject = true;
|
|
463
|
+
try {
|
|
464
|
+
const res = await fetch('/api/projects', {
|
|
465
|
+
method: 'POST',
|
|
466
|
+
headers: {
|
|
467
|
+
'Content-Type': 'application/json',
|
|
468
|
+
'Authorization': `Bearer ${localStorage.getItem("token")}`
|
|
469
|
+
},
|
|
470
|
+
body: JSON.stringify(this.newProject)
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
if (res.ok) {
|
|
474
|
+
const data = await res.json();
|
|
475
|
+
if (data.success) {
|
|
476
|
+
this.projects.push(data.data);
|
|
477
|
+
this.showNewProjectModal = false;
|
|
478
|
+
this.newProject = { name: '', description: '' };
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
} catch (error) {
|
|
482
|
+
console.error('Error creating project:', error);
|
|
483
|
+
} finally {
|
|
484
|
+
this.creatingProject = false;
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
async selectProject(project) {
|
|
488
|
+
this.selectedProject = project;
|
|
489
|
+
this.currentView = 'repositories';
|
|
490
|
+
await this.loadRepositories(project._id);
|
|
491
|
+
},
|
|
492
|
+
async loadRepositories(projectId) {
|
|
493
|
+
if (!projectId) return;
|
|
494
|
+
|
|
495
|
+
try {
|
|
496
|
+
const token = localStorage.getItem('token');
|
|
497
|
+
const res = await fetch(`/api/repositories/${projectId}`, {
|
|
498
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
499
|
+
});
|
|
500
|
+
if (res.ok) {
|
|
501
|
+
const data = await res.json();
|
|
502
|
+
if (data.success) {
|
|
503
|
+
this.repositories = data.data.repositories || [];
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
} catch (error) {
|
|
507
|
+
console.error('Error loading repositories:', error);
|
|
508
|
+
}
|
|
509
|
+
},
|
|
510
|
+
async connectRepository() {
|
|
511
|
+
if (!this.selectedProject) {
|
|
512
|
+
alert('Please select a project first');
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Open modal to select from GitHub repos
|
|
517
|
+
this.showRepoModal = true;
|
|
518
|
+
this.loadingRepos = true;
|
|
519
|
+
|
|
520
|
+
try {
|
|
521
|
+
const token = localStorage.getItem('token');
|
|
522
|
+
const res = await fetch('/api/repositories/github/repos', {
|
|
523
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
if (res.ok) {
|
|
527
|
+
const data = await res.json();
|
|
528
|
+
if (data.success) {
|
|
529
|
+
this.githubRepos = data.data.repositories || [];
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
} catch (error) {
|
|
533
|
+
console.error('Error loading GitHub repos:', error);
|
|
534
|
+
} finally {
|
|
535
|
+
this.loadingRepos = false;
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
async selectGithubRepo(repo) {
|
|
539
|
+
if (!this.selectedProject) return;
|
|
540
|
+
|
|
541
|
+
try {
|
|
542
|
+
const token = localStorage.getItem('token');
|
|
543
|
+
const res = await fetch('/api/repositories/github/connect', {
|
|
544
|
+
method: 'POST',
|
|
545
|
+
headers: {
|
|
546
|
+
'Content-Type': 'application/json',
|
|
547
|
+
'Authorization': `Bearer ${token}`
|
|
548
|
+
},
|
|
549
|
+
body: JSON.stringify({
|
|
550
|
+
projectId: this.selectedProject._id,
|
|
551
|
+
repoFullName: repo.full_name
|
|
552
|
+
})
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
if (res.ok) {
|
|
556
|
+
const data = await res.json();
|
|
557
|
+
if (data.success) {
|
|
558
|
+
this.repositories.push(data.data.repository);
|
|
559
|
+
this.showRepoModal = false;
|
|
560
|
+
// Update project stats
|
|
561
|
+
this.selectedProject.metadata.totalRepositories = this.repositories.length;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
} catch (error) {
|
|
565
|
+
console.error('Error connecting repository:', error);
|
|
566
|
+
}
|
|
567
|
+
},
|
|
568
|
+
generateChangelog(repo) {
|
|
569
|
+
// TODO: Implement changelog generation
|
|
570
|
+
alert('Changelog generation coming soon!');
|
|
571
|
+
},
|
|
572
|
+
viewChangelogs(repo) {
|
|
573
|
+
this.currentView = 'changelogs';
|
|
574
|
+
// TODO: Load changelogs for this repo
|
|
575
|
+
},
|
|
576
|
+
downloadChangelog(changelog) {
|
|
577
|
+
// TODO: Implement download
|
|
578
|
+
alert('Download coming soon!');
|
|
579
|
+
},
|
|
580
|
+
viewChangelog(changelog) {
|
|
581
|
+
// TODO: Implement view
|
|
582
|
+
alert('View changelog coming soon!');
|
|
583
|
+
},
|
|
584
|
+
getToken() {
|
|
585
|
+
// Get JWT token from localStorage
|
|
586
|
+
return localStorage.getItem('token') || '';
|
|
587
|
+
},
|
|
588
|
+
logout() {
|
|
589
|
+
localStorage.removeItem('token');
|
|
590
|
+
window.location.href = '/auth/login';
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}).mount('#app');
|
|
594
|
+
</script>
|
|
595
|
+
</body>
|
|
596
|
+
</html>
|