fix(domains): Neu-einlesen-Knopf nur fuer Verwalter sichtbar (WR-06)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-10-08 11:29:01 +02:00
parent 9eada2e082
commit e1dd996438
5 changed files with 34 additions and 21 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ Diese Liste beschreibt in einfachen Worten, was sich von Version zu Version an T
- Neues Modul „Domains“ in der Gruppe „Domains“: Domains bei AutoDNS registrieren, Kontakte und Kunden zuordnen. Ein Administrator aktiviert das Modul im Marktplatz; wer es nutzen soll, bekommt zusätzlich die Freigabe. Mit „Benutzen“ sehen Sie die Domainliste, die Kontakte, die Kunden und die Aufträge; mit „Verwalten“ (und als Administrator) registrieren Sie Domains, legen Kontakte und Kunden an und richten die Anbindung ein. - Neues Modul „Domains“ in der Gruppe „Domains“: Domains bei AutoDNS registrieren, Kontakte und Kunden zuordnen. Ein Administrator aktiviert das Modul im Marktplatz; wer es nutzen soll, bekommt zusätzlich die Freigabe. Mit „Benutzen“ sehen Sie die Domainliste, die Kontakte, die Kunden und die Aufträge; mit „Verwalten“ (und als Administrator) registrieren Sie Domains, legen Kontakte und Kunden an und richten die Anbindung ein.
- Domains, Anbindung an AutoDNS: Unter „Einstellungen“ tragen Sie Benutzername, Passwort und Kontext getrennt für das Demo-System (zum Ausprobieren) und das Live-System (echte, kostenpflichtige Registrierungen) ein. Das Passwort wird verschlüsselt gespeichert und nie wieder angezeigt. Neue Installationen starten im Demo-System; der Wechsel auf das Live-System verlangt eine ausdrückliche Bestätigung, und eine Kennzeichnung oben auf der Seite zeigt jederzeit, welches System gerade gilt. „Verbindung testen“ prüft den Zugang mit einem einzigen Aufruf. Dazu kommen die Standard-Nameserver, die bei jeder Registrierung vorausgefüllt werden. - Domains, Anbindung an AutoDNS: Unter „Einstellungen“ tragen Sie Benutzername, Passwort und Kontext getrennt für das Demo-System (zum Ausprobieren) und das Live-System (echte, kostenpflichtige Registrierungen) ein. Das Passwort wird verschlüsselt gespeichert und nie wieder angezeigt. Neue Installationen starten im Demo-System; der Wechsel auf das Live-System verlangt eine ausdrückliche Bestätigung, und eine Kennzeichnung oben auf der Seite zeigt jederzeit, welches System gerade gilt. „Verbindung testen“ prüft den Zugang mit einem einzigen Aufruf. Dazu kommen die Standard-Nameserver, die bei jeder Registrierung vorausgefüllt werden.
- Domains, Kontakte und Kunden: Alle Kontakte, die bei AutoDNS vorhanden sind, erscheinen automatisch in Tessera („Aus AutoDNS neu einlesen“ holt sie auf Wunsch sofort neu). Neue Kontakte (Person oder Organisation) legen Sie über ein Formular an. Jeden Kontakt – einzeln oder viele auf einmal – ordnen Sie einem Kunden zu; Ihre eigene Firma legen Sie ebenfalls als Kunden an und markieren sie. Die Listen lassen sich nach Kunde filtern und gruppieren. - Domains, Kontakte und Kunden: Alle Kontakte, die bei AutoDNS vorhanden sind, erscheinen automatisch in Tessera („Aus AutoDNS neu einlesen“ holt sie auf Wunsch sofort neu; das dürfen Benutzer mit der Freigabe „Verwalten“). Neue Kontakte (Person oder Organisation) legen Sie über ein Formular an. Jeden Kontakt – einzeln oder viele auf einmal – ordnen Sie einem Kunden zu; Ihre eigene Firma legen Sie ebenfalls als Kunden an und markieren sie. Die Listen lassen sich nach Kunde filtern und gruppieren.
- Domains, Domainliste: Alle Domains aus AutoDNS mit Kunde (über den Inhaber-Kontakt), Inhaber, Ablaufdatum und Status, ebenfalls filterbar und nach Kunde gruppierbar. - Domains, Domainliste: Alle Domains aus AutoDNS mit Kunde (über den Inhaber-Kontakt), Inhaber, Ablaufdatum und Status, ebenfalls filterbar und nach Kunde gruppierbar.
- Domains, Registrieren: Verfügbarkeit prüfen, Kontakte und Nameserver wählen, Zusammenfassung mit System und Preis ansehen und mit „Jetzt verbindlich registrieren“ bestätigen. Tessera schützt vor Doppelbestellungen: Jede Registrierung wird höchstens ein einziges Mal an AutoDNS geschickt, auch bei Doppelklick oder zwei geöffneten Fenstern, und nie automatisch wiederholt. Ist unklar, ob AutoDNS die Bestellung angenommen hat, steht der Auftrag auf „Ergebnis ungeklärt“, bis Tessera ihn mit AutoDNS abgeglichen hat. Den Stand jeder Registrierung sehen Sie im Reiter „Aufträge“; er wird beim Öffnen und danach alle 30 Sekunden mit AutoDNS abgeglichen. - Domains, Registrieren: Verfügbarkeit prüfen, Kontakte und Nameserver wählen, Zusammenfassung mit System und Preis ansehen und mit „Jetzt verbindlich registrieren“ bestätigen. Tessera schützt vor Doppelbestellungen: Jede Registrierung wird höchstens ein einziges Mal an AutoDNS geschickt, auch bei Doppelklick oder zwei geöffneten Fenstern, und nie automatisch wiederholt. Ist unklar, ob AutoDNS die Bestellung angenommen hat, steht der Auftrag auf „Ergebnis ungeklärt“, bis Tessera ihn mit AutoDNS abgeglichen hat. Den Stand jeder Registrierung sehen Sie im Reiter „Aufträge“; er wird beim Öffnen und danach alle 30 Sekunden mit AutoDNS abgeglichen.
@@ -230,6 +230,7 @@ export function ContactsTab({
<input type="checkbox" checked={grouped} onChange={(e) => setGrouped(e.target.checked)} /> <input type="checkbox" checked={grouped} onChange={(e) => setGrouped(e.target.checked)} />
{tc('groupByCustomer')} {tc('groupByCustomer')}
</label> </label>
{canManage && (
<button <button
type="button" type="button"
className={SECONDARY_BUTTON} className={SECONDARY_BUTTON}
@@ -238,6 +239,7 @@ export function ContactsTab({
> >
{t('refresh')} {t('refresh')}
</button> </button>
)}
{canManage && !creating && ( {canManage && !creating && (
<button type="button" className={PRIMARY_BUTTON} onClick={() => setCreating(true)}> <button type="button" className={PRIMARY_BUTTON} onClick={() => setCreating(true)}>
{t('newContact')} {t('newContact')}
@@ -83,7 +83,14 @@ function DomainTable({ rows }: { rows: DomainsDomain[] }) {
* (ueber den Inhaber-Kontakt), Inhaber, Ablaufdatum und Status — filterbar und * (ueber den Inhaber-Kontakt), Inhaber, Ablaufdatum und Status — filterbar und
* nach Kunde gruppierbar. Nur lesend; sichtbar fuer alle mit "Benutzen". * nach Kunde gruppierbar. Nur lesend; sichtbar fuer alle mit "Benutzen".
*/ */
export function DomainsTab({ customers }: { customers: DomainsCustomer[] }) { export function DomainsTab({
customers,
canManage,
}: {
customers: DomainsCustomer[];
/** Nur Verwalter duerfen den Zwischenspeicher umgehen (Neuabruf bei AutoDNS). */
canManage: boolean;
}) {
const t = useTranslations('domains.domainList'); const t = useTranslations('domains.domainList');
const tc = useTranslations('domains.common'); const tc = useTranslations('domains.common');
const [data, setData] = useState<DomainsDomainList | null>(null); const [data, setData] = useState<DomainsDomainList | null>(null);
@@ -162,6 +169,7 @@ export function DomainsTab({ customers }: { customers: DomainsCustomer[] }) {
<input type="checkbox" checked={grouped} onChange={(e) => setGrouped(e.target.checked)} /> <input type="checkbox" checked={grouped} onChange={(e) => setGrouped(e.target.checked)} />
{tc('groupByCustomer')} {tc('groupByCustomer')}
</label> </label>
{canManage && (
<button <button
type="button" type="button"
className={SECONDARY_BUTTON} className={SECONDARY_BUTTON}
@@ -170,6 +178,7 @@ export function DomainsTab({ customers }: { customers: DomainsCustomer[] }) {
> >
{t('refresh')} {t('refresh')}
</button> </button>
)}
</div> </div>
{error && ( {error && (
@@ -384,8 +384,8 @@ describe('Reiter Domains, Kontakte und Kunden', () => {
expect(screen.queryByRole('button', { name: 'Neuer Kontakt' })).toBeNull(); expect(screen.queryByRole('button', { name: 'Neuer Kontakt' })).toBeNull();
expect(screen.queryByRole('button', { name: 'Zuordnen' })).toBeNull(); expect(screen.queryByRole('button', { name: 'Zuordnen' })).toBeNull();
expect(screen.queryByRole('checkbox', { name: /auswählen/ })).toBeNull(); expect(screen.queryByRole('checkbox', { name: /auswählen/ })).toBeNull();
// Lesen darf jeder: neu einlesen steht allen zur Verfuegung. // Der Neuabruf bei AutoDNS ist Verwaltern vorbehalten (der Server ignoriert ihn sonst).
expect(screen.getByRole('button', { name: 'Aus AutoDNS neu einlesen' })).toBeTruthy(); expect(screen.queryByRole('button', { name: 'Aus AutoDNS neu einlesen' })).toBeNull();
fireEvent.click(screen.getByRole('button', { name: 'Kunden' })); fireEvent.click(screen.getByRole('button', { name: 'Kunden' }));
await screen.findByText('Alpha GmbH'); await screen.findByText('Alpha GmbH');
@@ -104,7 +104,9 @@ export default function DomainsPage() {
{tabs.length > 0 && activeTab && ( {tabs.length > 0 && activeTab && (
<> <>
<TabBar tabs={tabs} active={activeTab} onChange={setTab} /> <TabBar tabs={tabs} active={activeTab} onChange={setTab} />
{activeTab === 'domains' && status?.configured && <DomainsTab customers={customers} />} {activeTab === 'domains' && status?.configured && (
<DomainsTab customers={customers} canManage={canManage} />
)}
{activeTab === 'contacts' && status?.configured && ( {activeTab === 'contacts' && status?.configured && (
<ContactsTab <ContactsTab
customers={customers} customers={customers}