feat(nextcloud-status): Kundenname voll ausgeschrieben, Kachel-Knoepfe in die Fusszeile
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -15,7 +15,7 @@ Diese Liste beschreibt in einfachen Worten, was sich von Version zu Version an T
|
|||||||
### Geändert
|
### Geändert
|
||||||
|
|
||||||
- DKV-Rechnung: Die Modulbeschreibung im Marktplatz weist jetzt darauf hin, dass das Modul die Freigabestufe „Verwalten“ benötigt. Mit „Benutzen“ erscheint es zwar in der Seitenleiste, öffnet aber nur die Seite „Kein Zugriff“. Modulversion 1.1.0.
|
- DKV-Rechnung: Die Modulbeschreibung im Marktplatz weist jetzt darauf hin, dass das Modul die Freigabestufe „Verwalten“ benötigt. Mit „Benutzen“ erscheint es zwar in der Seitenleiste, öffnet aber nur die Seite „Kein Zugriff“. Modulversion 1.1.0.
|
||||||
- Nextcloud-Status: Über der Kachelliste gibt es jetzt ein Suchfeld. Es zeigt nur die Clouds, deren Kundenname den eingegebenen Text enthält; Groß- und Kleinschreibung spielen keine Rolle, die gewählte Sortierung bleibt erhalten. Die Kacheln sind kompakter, und die Adresse der Cloud steht in voller Länge in einer eigenen Zeile, statt abgeschnitten zu werden.
|
- Nextcloud-Status: Über der Kachelliste gibt es jetzt ein Suchfeld. Es zeigt nur die Clouds, deren Kundenname den eingegebenen Text enthält; Groß- und Kleinschreibung spielen keine Rolle, die gewählte Sortierung bleibt erhalten. Die Kacheln sind kompakter, der Kundenname und die Adresse der Cloud stehen in voller Länge da, statt abgeschnitten zu werden. Die Knöpfe Benachrichtigen, Prüfen und Bearbeiten sitzen jetzt unten rechts neben „Zuletzt geprüft“.
|
||||||
- Nextcloud-Status: Als Logo können Sie jetzt auch eine Bildadresse eingeben, die mit http:// beginnt. Tessera holt das Bild beim Speichern einmalig ab und behält es wie ein hochgeladenes Bild (höchstens 1 MB; PNG, JPEG, GIF oder WebP). Adressen, die nur intern erreichbar sind, holt Tessera nicht ab – solche Bilder laden Sie über „Bild hochladen“ hoch. Adressen mit https:// lädt weiterhin direkt Ihr Browser. Das Feld heißt jetzt „Bildadresse“.
|
- Nextcloud-Status: Als Logo können Sie jetzt auch eine Bildadresse eingeben, die mit http:// beginnt. Tessera holt das Bild beim Speichern einmalig ab und behält es wie ein hochgeladenes Bild (höchstens 1 MB; PNG, JPEG, GIF oder WebP). Adressen, die nur intern erreichbar sind, holt Tessera nicht ab – solche Bilder laden Sie über „Bild hochladen“ hoch. Adressen mit https:// lädt weiterhin direkt Ihr Browser. Das Feld heißt jetzt „Bildadresse“.
|
||||||
|
|
||||||
### Behoben
|
### Behoben
|
||||||
|
|||||||
@@ -98,9 +98,69 @@ export function CloudTile({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<div className="truncate font-semibold leading-tight" title={instance.customerName}>
|
<div className="break-words font-semibold leading-tight">{instance.customerName}</div>
|
||||||
{instance.customerName}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Adresse in voller Laenge auf eigener Zeile — bricht notfalls um statt abgeschnitten zu werden. */}
|
||||||
|
<a
|
||||||
|
href={instance.baseUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="block break-all text-xs text-muted-foreground underline-offset-2 hover:underline"
|
||||||
|
title={t('card.openCloud')}
|
||||||
|
>
|
||||||
|
{instance.baseUrl}
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div className="flex flex-wrap items-center justify-between gap-x-2 gap-y-1">
|
||||||
|
<span
|
||||||
|
data-testid="rating-pill"
|
||||||
|
className={`inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium ${style.pill}`}
|
||||||
|
>
|
||||||
|
<span aria-hidden="true" className={`h-1.5 w-1.5 rounded-full ${style.fill}`} />
|
||||||
|
{reason}
|
||||||
|
</span>
|
||||||
|
<span className="text-xs text-muted-foreground">
|
||||||
|
{t('card.version')}:{' '}
|
||||||
|
<span className="font-medium tabular-nums text-foreground">
|
||||||
|
{instance.status.versionString ?? t('card.versionUnknown')}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{hintText && (
|
||||||
|
<p
|
||||||
|
data-testid="error-hint"
|
||||||
|
className="break-words text-xs text-muted-foreground"
|
||||||
|
title={hintRaw}
|
||||||
|
>
|
||||||
|
{hintText}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{instance.status.pendingRetry === true && (
|
||||||
|
<p
|
||||||
|
data-testid="pending-retry"
|
||||||
|
className="flex items-center gap-1.5 text-xs text-muted-foreground"
|
||||||
|
>
|
||||||
|
<span aria-hidden="true" className="h-1.5 w-1.5 shrink-0 rounded-full bg-status-warn" />
|
||||||
|
{t('card.pendingRetry')}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Fusszeile: Pruefzeitpunkt links, Knoepfe rechts — der Kopf bleibt dem vollen Kundennamen. */}
|
||||||
|
<div className="mt-auto flex items-center justify-between gap-2">
|
||||||
|
<div
|
||||||
|
data-testid="last-check"
|
||||||
|
className="min-w-0 text-xs text-muted-foreground"
|
||||||
|
title={
|
||||||
|
instance.status.checkedAt
|
||||||
|
? new Date(instance.status.checkedAt).toLocaleString(locale)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{checkedAge ? t('card.lastCheck', { age: checkedAge }) : t('card.neverChecked')}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex shrink-0 items-center gap-1">
|
<div className="flex shrink-0 items-center gap-1">
|
||||||
<button
|
<button
|
||||||
@@ -183,65 +243,6 @@ export function CloudTile({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Adresse in voller Laenge auf eigener Zeile — bricht notfalls um statt abgeschnitten zu werden. */}
|
|
||||||
<a
|
|
||||||
href={instance.baseUrl}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
className="block break-all text-xs text-muted-foreground underline-offset-2 hover:underline"
|
|
||||||
title={t('card.openCloud')}
|
|
||||||
>
|
|
||||||
{instance.baseUrl}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<div className="flex flex-wrap items-center justify-between gap-x-2 gap-y-1">
|
|
||||||
<span
|
|
||||||
data-testid="rating-pill"
|
|
||||||
className={`inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium ${style.pill}`}
|
|
||||||
>
|
|
||||||
<span aria-hidden="true" className={`h-1.5 w-1.5 rounded-full ${style.fill}`} />
|
|
||||||
{reason}
|
|
||||||
</span>
|
|
||||||
<span className="text-xs text-muted-foreground">
|
|
||||||
{t('card.version')}:{' '}
|
|
||||||
<span className="font-medium tabular-nums text-foreground">
|
|
||||||
{instance.status.versionString ?? t('card.versionUnknown')}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{hintText && (
|
|
||||||
<p
|
|
||||||
data-testid="error-hint"
|
|
||||||
className="break-words text-xs text-muted-foreground"
|
|
||||||
title={hintRaw}
|
|
||||||
>
|
|
||||||
{hintText}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{instance.status.pendingRetry === true && (
|
|
||||||
<p
|
|
||||||
data-testid="pending-retry"
|
|
||||||
className="flex items-center gap-1.5 text-xs text-muted-foreground"
|
|
||||||
>
|
|
||||||
<span aria-hidden="true" className="h-1.5 w-1.5 shrink-0 rounded-full bg-status-warn" />
|
|
||||||
{t('card.pendingRetry')}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
|
||||||
data-testid="last-check"
|
|
||||||
className="mt-auto text-xs text-muted-foreground"
|
|
||||||
title={
|
|
||||||
instance.status.checkedAt
|
|
||||||
? new Date(instance.status.checkedAt).toLocaleString(locale)
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{checkedAge ? t('card.lastCheck', { age: checkedAge }) : t('card.neverChecked')}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user