Naar inhoud
Pivotick
Main Navigation Startpagina
Aan de slag
Configuratie
Gegenereerde API-documentatie
GalerijProjectenProbeer het uit!

Nederlands

English
简体中文
Français
Deutsch
Português
日本語
العربية
Español

Nederlands

English
简体中文
Français
Deutsch
Português
日本語
العربية
Español

Weergave

Sidebar Navigation

Aan de slag

Projecten met Pivotick

Configuratie

Callbacks

Verbindingslagen

Vereenvoudigen

Indeling

Weergave

Simulatie

Interface aanpassen

Zijbalk

Tooltip

Contextmenu

Filters

Legenda

Gegevenstabel

Interface vormgeven

Interface vertalen

Plug-ins

Pivotick-API

Pivots en verrijking

Pivotresultaten opslaan

Ongedaan maken en geschiedenis

Beveiliging

API-documentatie

Galerij

Basis

Knopen vormgeven

Verbindingen vormgeven

Indelingen

Gebeurtenissen en callbacks

Interface aanpassen

Bewerken en maken

Notities en annotaties

Filteren, zoeken en hiërarchie

Programmatische besturing

Thema's en prestaties

Pivots en verrijking

Uitgelichte voorbeelden

Doorgaan met verwijderen, bewerken en maken ​

Wanneer de grafiek een weergave van persistente records is, kan geen enkele schrijfwijze optimistisch zijn. Drie before-hooks zorgen ervoor dat elke door de gebruiker geïnitieerde tekst een voorstel schrijft waar de consument over beslist, dus het canvas en de database kunnen het nooit oneens zijn:

  • onBeforeDelete — wordt geactiveerd voor elke verwijdermogelijkheid (de bulkrij van de zijbalk, de node / edge / note contextmenu-items) zodra de hele doelset is opgelost, inclusief cascadingEdges: de relaties die het verwijderen van een knooppunt zou vernietigen. Geef false terug om een veto uit te spreken, of { accept: true, nodes, edges } om alleen te behouden wat de server daadwerkelijk verwijderd. ctx.confirm() is het ingebouwde bevestigingsmodaliteit.
  • onBeforeNodeCreate — wordt geactiveerd voor Maken ▸ Knooppunt en de canvasmenu's toevoegen Voeg hier een knooppunt toe, met de grafiekruimte position en een promptData()-vorm. Wat wat u teruggeeft, is wat in de grafiek terechtkomt.
  • onBeforeEdgeEditCommit — wordt geactiveerd wanneer een randbewerking wordt uitgevoerd (klik met de rechtermuisknop op een rand ▸ Rand bewerken). Weiger het en de edge behoudt zijn gegevens.

Alle drie kunnen asynchroon zijn en een tweede gebaar wordt genegeerd terwijl er één in behandeling is. Programmatic graph.removeNode() / addNode() zijn nooit beveiligd, dus uw eigen code wordt niet geblokkeerd door je eigen hook.

Probeer het: selecteer knooppunten en druk op Delete in de zijbalk (het record gepubliceerd verschijnt terug geweigerd), klik met de rechtermuisknop op een rand om de relatie ervan te wijzigen, of gebruik Maken ▸ Toevoegen knooppunt. Stel editors.deletion.enabled: false in om de verwijdermogelijkheden te verwijderen helemaal in plaats van elke klik te vetoën.

js
const options = {
    // Label each attribute with its value, so an edit's effect is visible.
    render: {
        defaultNodeStyle: {
            size: 16,
            textColor: '#334155',
            text: (node) => node.getData()?.label,
            textVerticalShift: -1.6
        }
    },
    UI: {
        mode: 'full',
        // Off: `full` mode brings a minimap and the data dock, and this card is about
        // neither (see the Minimap and Data table cards for those).
        minimap: false,
        table: false,
        // Give the edge editor a relationship dropdown instead of a free-text field.
        editors: {
            edgeEditor: {
                fields: [{
                    key: 'label',
                    label: 'Relationship',
                    type: 'select',
                    options: RELATIONSHIPS.map((value) => ({ value, label: value }))
                }]
            }
        }
    },
    callbacks: {
        // Nothing leaves the model until the server agrees. The library resolves the
        // whole target set first — including `cascadingEdges`, the relationships that
        // removing a node would take with it — so you can persist the real consequence.
        onBeforeDelete: async ({ nodes, edges, cascadingEdges, origin, confirm }) => {
            const links = edges.length + cascadingEdges.length
            const ok = await confirm({
                title: 'Delete from event?',
                body: `${nodes.length} attribute(s) and ${links} relationship(s) will be `
                    + `deleted server-side. (asked from the ${origin})`,
                confirmLabel: 'Delete'
            })
            if (!ok) return false

            graph.notifier.info('Saving…', 'POST /events/delete')
            await wait(700) // a backend call that could fail

            // The server refused the published record: keep exactly what it deleted.
            const refused = nodes.filter((node) => node.getData().published)
            if (refused.length) {
                graph.notifier.warning('Kept', `${refused[0].getData().label} is published — not deleted.`)
            }
            return { accept: true, nodes: nodes.filter((node) => !node.getData().published) }
        },

        // Create ▸ Add node, or the canvas menu's "Add Node Here". `promptData` opens a
        // form; the id/data you return is what enters the graph.
        onBeforeNodeCreate: async ({ position, promptData }) => {
            const values = await promptData({
                title: 'New attribute',
                fields: [
                    { key: 'label', label: 'Value', type: 'text' },
                    {
                        key: 'type', label: 'Type', type: 'select', defaultValue: 'ip-src',
                        options: ['ip-src', 'domain', 'md5', 'url'].map((v) => ({ value: v, label: v }))
                    }
                ]
            })
            if (!values) return false // cancelled

            graph.notifier.info('Saving…', 'POST /attributes/add')
            await wait(500)
            graph.notifier.success('Created', `${values.label} at ${Math.round(position.x)},${Math.round(position.y)}`)
            return { accept: true, id: `attr-${values.label}`, data: values }
        },

        // Right-click an edge ▸ Edit Edge. The commit is a proposal too: refuse it and
        // the edge keeps its data, with the modal still open to correct.
        onBeforeEdgeEditCommit: async ({ previousData, nextData }) => {
            if (!RELATIONSHIPS.includes(nextData.label)) {
                graph.notifier.warning('Rejected', `"${nextData.label}" is not a known relationship.`)
                return false
            }
            graph.notifier.info('Saving…', 'PUT /object_references')
            await wait(500)
            graph.notifier.success('Updated', `${previousData.label} → ${nextData.label}`)
            return true
        }
    }
}
js
const data = {
    nodes: [
        { id: 'ip-8888', data: { label: '8.8.8.8', type: 'ip-src' } },
        { id: 'dom-evil', data: { label: 'evil.example.com', type: 'domain' } },
        { id: 'md5', data: { label: 'd41d8cd9…f8427e', type: 'md5' } },
        // The server refuses to delete this one — a published record.
        { id: 'file-obj', data: { label: 'invoice.doc', type: 'file', published: true } }
    ],
    edges: [
        { id: 'r1', from: 'file-obj', to: 'md5', data: { label: 'contains' } },
        { id: 'r2', from: 'dom-evil', to: 'ip-8888', data: { label: 'resolves-to' } }
    ]
}
Pager
Volgende paginaAan de slag