feat: Gitea — register, settings connect, tabs org, search
1. Pas de Gitea sans config: _require_gitea() → 401 si pas de token OAuth 2. Register Gitea: boutons "Login/Register with Gitea" dynamiques selon l'onglet 3. Settings → Integrations: ✅ Active / 🔗 Connect / Disconnect + API status/disconnect 4. Workspaces: tabs par org (All | org1 | org2) + barre recherche 🔍 filtrage live 5. API: GET /api/gitea/status, DELETE /api/gitea/disconnect
This commit is contained in:
@@ -63,6 +63,12 @@
|
||||
.btn-new:hover{background:var(--bg-tertiary);color:var(--text);}
|
||||
.btn-sm{padding:4px 8px;font-size:11px;border-radius:6px;border:1px solid var(--border);background:transparent;color:var(--text-dim);cursor:pointer;}
|
||||
.btn-sm:hover{background:var(--bg-tertiary);color:var(--text);}
|
||||
/* Org tabs */
|
||||
.org-tab{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:6px;font-size:13px;color:var(--text-dim);background:transparent;border:1px solid var(--border);cursor:pointer;white-space:nowrap;transition:all 100ms;}
|
||||
.org-tab:hover{background:var(--bg-tertiary);color:var(--text);}
|
||||
.org-tab.active{background:var(--accent);color:#fff;border-color:var(--accent);}
|
||||
.org-tab-badge{font-size:10px;padding:0 5px;border-radius:8px;background:rgba(255,255,255,.15);}
|
||||
.search-input:focus{border-color:var(--accent);}
|
||||
</style>
|
||||
|
||||
<div class="ws-page" x-data="workspacesPage()">
|
||||
@@ -98,7 +104,9 @@
|
||||
<!-- Not linked -->
|
||||
<div class="gitea-empty" x-show="giteaStatus==='not_linked'">
|
||||
<div>Connect your Gitea account to see your projects.</div>
|
||||
<a class="gitea-connect" href="/auth/login?provider=gitea">🔗 Login with Gitea</a>
|
||||
<a class="gitea-connect" href="/auth/login?provider=gitea">🔗 Connect Gitea</a>
|
||||
<span style="margin:0 8px;color:var(--text-dim);">or</span>
|
||||
<a class="gitea-connect" href="/auth/login?provider=gitea">📝 Register with Gitea</a>
|
||||
</div>
|
||||
|
||||
<!-- Loading -->
|
||||
@@ -110,35 +118,57 @@
|
||||
<button class="gitea-connect" @click="loadGitea()">Retry</button>
|
||||
</div>
|
||||
|
||||
<!-- Projects (grouped by org) -->
|
||||
<template x-for="group in giteaGroups" :key="group.org">
|
||||
<div class="gitea-org">
|
||||
<div class="gitea-org-header">
|
||||
<img x-show="group.avatar" :src="group.avatar" class="gitea-org-avatar" alt="">
|
||||
<span class="gitea-org-avatar" x-show="!group.avatar" x-text="group.org.charAt(0).toUpperCase()"></span>
|
||||
<span x-text="group.org"></span>
|
||||
</div>
|
||||
<div class="ws-grid">
|
||||
<template x-for="proj in group.projects" :key="proj.id">
|
||||
<div class="ws-card" @click="openGitea(proj)">
|
||||
<div class="ws-card-name" x-text="proj.name"></div>
|
||||
<div class="ws-card-sub">
|
||||
<span x-text="proj.owner?.login || group.org"></span>
|
||||
<span style="margin:0 4px">/</span>
|
||||
<span x-text="proj.name"></span>
|
||||
</div>
|
||||
<div class="ws-card-count">
|
||||
<span x-show="proj.private" style="margin-right:6px">🔒</span>
|
||||
<span x-text="proj.description || ''" style="display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;"></span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Projects (tabs by org + search) -->
|
||||
<div x-show="giteaStatus==='ok' && giteaGroups.length > 0">
|
||||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;flex-wrap:wrap;">
|
||||
<!-- Org tabs -->
|
||||
<div style="display:flex;gap:4px;overflow-x:auto;flex:1;min-width:0;">
|
||||
<button class="org-tab" :class="{active:activeOrg==='all'}" @click="activeOrg='all'">
|
||||
All <span class="org-tab-badge" x-text="giteaTotal"></span>
|
||||
</button>
|
||||
<template x-for="g in giteaGroups" :key="g.org">
|
||||
<button class="org-tab" :class="{active:activeOrg===g.org}" @click="activeOrg=g.org">
|
||||
<span x-text="g.org"></span>
|
||||
<span class="org-tab-badge" x-text="g.projects.length"></span>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
<!-- Search -->
|
||||
<input type="text" class="search-input" x-model="giteaSearch" placeholder="🔍 Filter projects…" style="width:200px;padding:6px 10px;background:var(--bg-tertiary);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px;outline:none;">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- No projects in orgs -->
|
||||
<div class="gitea-empty" x-show="giteaStatus==='ok' && giteaTotal==0">
|
||||
<!-- Project cards (filtered) -->
|
||||
<template x-for="group in filteredGroups" :key="group.org">
|
||||
<div class="gitea-org">
|
||||
<div class="gitea-org-header">
|
||||
<span class="gitea-org-avatar" x-text="group.org.charAt(0).toUpperCase()"></span>
|
||||
<span x-text="group.org"></span>
|
||||
</div>
|
||||
<div class="ws-grid">
|
||||
<template x-for="proj in group.projects" :key="proj.id">
|
||||
<div class="ws-card" @click="openGitea(proj)">
|
||||
<div class="ws-card-name" x-text="proj.name"></div>
|
||||
<div class="ws-card-sub">
|
||||
<span x-text="group.org"></span>
|
||||
<span style="margin:0 4px">/</span>
|
||||
<span x-text="proj.name"></span>
|
||||
</div>
|
||||
<div class="ws-card-count">
|
||||
<span x-show="proj.private" style="margin-right:6px">🔒</span>
|
||||
<span x-text="proj.description || proj.language || ''" style="display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:220px;"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="gitea-empty" x-show="filteredGroups.length===0" style="margin-top:12px;">
|
||||
No projects match your search.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- No projects at all -->
|
||||
<div class="gitea-empty" x-show="giteaStatus==='ok' && giteaTotal==0 && giteaGroups.length===0">
|
||||
No Gitea projects found.
|
||||
</div>
|
||||
</div>
|
||||
@@ -171,6 +201,20 @@ function workspacesPage() {
|
||||
giteaStatus: 'loading', // loading|ok|not_linked|error
|
||||
giteaGroups: [],
|
||||
giteaTotal: 0,
|
||||
activeOrg: 'all',
|
||||
giteaSearch: '',
|
||||
|
||||
get filteredGroups() {
|
||||
var self = this;
|
||||
var q = (this.giteaSearch || '').toLowerCase();
|
||||
var groups = this.activeOrg === 'all' ? this.giteaGroups : this.giteaGroups.filter(function(g) { return g.org === self.activeOrg; });
|
||||
if (!q) return groups;
|
||||
return groups.map(function(g) {
|
||||
return {org: g.org, avatar: g.avatar, projects: g.projects.filter(function(p) {
|
||||
return p.name.toLowerCase().includes(q) || (p.description||'').toLowerCase().includes(q);
|
||||
})};
|
||||
}).filter(function(g) { return g.projects.length > 0; });
|
||||
},
|
||||
|
||||
async init() {
|
||||
await this.load();
|
||||
|
||||
Reference in New Issue
Block a user