Compare commits

..

4 Commits

Author SHA1 Message Date
gitea-actions d48ee8eae5 chore: bump version to v0.4.23
Auto Tag Develop / tag (push) Successful in 6s
Build & Push Docker Image / build (push) Successful in 49s
2026-06-01 21:26:44 +00:00
Matthieu 1dadc31884 style(kanban) : largeur fixe des colonnes de statut + scroll horizontal conditionnel
Auto Tag Develop / tag (push) Successful in 7s
Remplace flex-1/min-w par une largeur fixe (w-72) avec shrink-0 sur les
colonnes du board projet et de Mes Taches. Les colonnes ne sont plus
ecrasees quand un workflow compte beaucoup de statuts ; le scroll
horizontal n'apparait que si elles depassent la largeur du conteneur.
2026-06-01 23:26:35 +02:00
gitea-actions cdd7ca7626 chore: bump version to v0.4.22
Auto Tag Develop / tag (push) Successful in 7s
Build & Push Docker Image / build (push) Successful in 49s
2026-06-01 20:52:47 +00:00
Matthieu e1bf9ecb22 fix(frontend) : copie presse-papiers fonctionnelle en HTTP via fallback execCommand
Auto Tag Develop / tag (push) Successful in 7s
navigator.clipboard n'est disponible qu'en secure context (HTTPS/localhost),
ce qui cassait la copie en prod HTTP. Ajout d'un utilitaire copyToClipboard
avec fallback textarea + execCommand, appliqué au viewer Markdown, au token
API du profil et au nom de branche Git.
2026-06-01 22:52:32 +02:00
7 changed files with 50 additions and 11 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
parameters:
app.version: '0.4.21'
app.version: '0.4.23'
@@ -124,6 +124,7 @@
import type { TaskDocument } from '~/services/dto/task-document'
import { useTaskDocumentService } from '~/services/task-documents'
import { formatFileSize } from '~/utils/format'
import { copyToClipboard } from '~/utils/clipboard'
const props = defineProps<{
document: TaskDocument | null
@@ -159,13 +160,10 @@ const isPdf = computed(() => props.document?.mimeType === 'application/pdf')
const isText = computed(() => isTextDocument(props.document))
async function copyContent() {
try {
await navigator.clipboard.writeText(textContent.value)
if (await copyToClipboard(textContent.value)) {
copied.value = true
useToast().success(t('taskDocuments.copied'))
setTimeout(() => { copied.value = false }, 2000)
} catch {
// Clipboard unavailable
}
}
+2 -1
View File
@@ -229,6 +229,7 @@
import type { Task } from '~/services/dto/task'
import type { GiteaBranch, GiteaPullRequest } from '~/services/dto/gitea'
import { useGiteaService } from '~/services/gitea'
import { copyToClipboard } from '~/utils/clipboard'
const { t } = useI18n()
const props = defineProps<{
@@ -374,7 +375,7 @@ async function handleCreate() {
async function handleCopy() {
try {
const result = await getBranchName(props.task.id, branchForm.type)
await navigator.clipboard.writeText(result.name)
await copyToClipboard(result.name)
const { success } = useToast()
success(t('gitea.branch.copied'))
} catch {
+1 -1
View File
@@ -439,7 +439,7 @@ onMounted(async () => {
<div
v-for="cat in CATEGORIES"
:key="cat"
class="flex min-w-40 flex-1 flex-col rounded-lg bg-neutral-50 transition"
class="flex w-72 shrink-0 flex-col rounded-lg bg-neutral-50 transition"
:class="dragOverCategory === cat ? 'ring-2 ring-primary-400' : ''"
@dragover.prevent="dragOverCategory = cat"
@dragleave="dragOverCategory = null"
+3 -3
View File
@@ -129,6 +129,7 @@
<script setup lang="ts">
import { useAvatarService } from '~/composables/useAvatarService'
import { useApiTokenService } from '~/services/api-token'
import { copyToClipboard } from '~/utils/clipboard'
const auth = useAuthStore()
const toast = useToast()
@@ -181,10 +182,9 @@ async function onRemove() {
async function onCopy() {
if (!auth.user?.apiToken) return
try {
await navigator.clipboard.writeText(auth.user.apiToken)
if (await copyToClipboard(auth.user.apiToken)) {
toast.success({ message: t('profile.apiToken.copied') })
} catch {
} else {
toast.error({ message: t('profile.apiToken.copyFailed') })
}
}
+1 -1
View File
@@ -96,7 +96,7 @@
<div
v-for="status in statuses"
:key="status.id"
class="flex min-w-36 flex-1 flex-col rounded-lg transition-colors"
class="flex w-72 shrink-0 flex-col rounded-lg transition-colors"
:class="dragOverStatusId === status.id ? 'bg-neutral-200' : 'bg-neutral-50'"
@dragover.prevent
@dragenter.prevent="onDragEnter(status.id)"
+40
View File
@@ -0,0 +1,40 @@
/**
* Copy text to the clipboard with a fallback for non-secure contexts.
*
* `navigator.clipboard` is only available in secure contexts (HTTPS or
* localhost). On a plain HTTP origin (e.g. an internal/prod server without
* TLS) the API is missing, so we fall back to the legacy
* `document.execCommand('copy')` using a temporary off-screen textarea.
*
* @returns `true` if the copy succeeded, `false` otherwise.
*/
export async function copyToClipboard(text: string): Promise<boolean> {
// Preferred path: available in secure contexts (HTTPS / localhost).
if (navigator.clipboard && window.isSecureContext) {
try {
await navigator.clipboard.writeText(text)
return true
} catch {
// Fall through to the legacy fallback below.
}
}
// Legacy fallback: works on plain HTTP origins.
try {
const textarea = document.createElement('textarea')
textarea.value = text
// Keep it out of view and prevent layout shift / scrolling.
textarea.style.position = 'fixed'
textarea.style.top = '-9999px'
textarea.style.left = '-9999px'
textarea.setAttribute('readonly', '')
document.body.appendChild(textarea)
textarea.select()
textarea.setSelectionRange(0, text.length)
const ok = document.execCommand('copy')
document.body.removeChild(textarea)
return ok
} catch {
return false
}
}