@aprendomx/sinpapel-vue

Vue 3 workflow-tracking widgets for the sinpapel-drf API
732
Install
npm install @aprendomx/sinpapel-vue
Latest Version:0.4.2
Vue:3
License:GPL-3.0-or-later
Last Updated:Aug 31, 2026
Links: GitHub  ·  npm
Maintainer: aprendomx

@aprendomx/sinpapel-vue

v0.4.1 — Vue 3 UI layer for sinpapel.

Workflow-tracking widgets on top of the sinpapel-drf REST API: audit history, document requirements + uploads, structured metadata, transition preview, SLA status, and polymorphic electronic signature — without hand-writing a single request, store, or form.

🇪🇸 Leer en Español

npm Vue Quasar Node License: GPL v3 Tests


Table of Contents

  1. What is sinpapel-vue?
  2. Installation
  3. Quick start
  4. Components
  5. Client API
  6. Store & composables
  7. Internationalization (i18n)
  8. Theming
  9. TypeScript
  10. Compatibility
  11. Development & testing
  12. Known limitations & Roadmap
  13. Versioning & Stability
  14. Documentation & agent skills
  15. License & Contributing

1. What is sinpapel-vue?

@aprendomx/sinpapel-vue is the front-end layer of the sinpapel ecosystem. Where sinpapel-drf auto-publishes REST endpoints for every @workflow_enabled Django model, this library auto-renders the UI that drives them: one <SeguimientoPanel> gives an end user the full case-tracking experience.

Where it fits

Package Runtime Role
sinpapel Django Engine — versioned state machines, immutable audit, signing backends, predicates, SLA, metadata
sinpapel-drf Django + DRF HTTP layer — the API this package consumes
sinpapel-webhooks Django Event-driven outbound/inbound HTTP communication
sinpapel-reports Django Template-driven document generation (PDF overlay + DOCX)
@aprendomx/sinpapel-vue Vue 3 Runtime UI — case tracking for end users (this package)
sinpapel-designer Vue 3 SPA Design-time UI — visual flow editor, schema v0.2 import/export

Rule of thumb: sinpapel-designer models the flow, sinpapel-vue runs it. The designer is a standalone SPA for authoring flows; this package is an embeddable component library for the people who move cases through those flows.

Endpoint coverage

Every sinpapel-drf instance endpoint has a client method and a component behind it:

sinpapel-drf endpoint Verb Client method Component
available-transitions/ GET availableTransitions() TransitionDialog (target selector)
transition/ POST transition(payload) TransitionDialog
history/ GET history({page, pageSize}) HistoryTimeline
preview-transition/ POST previewTransition(targetState) PreviewTransitionPanel
metadatos/ GET / PATCH getMetadatos() / patchMetadatos(values) MetadatosForm
sla-status/ POST slaStatus() SlaStatusPanel
requisitos/ GET requisitos() RequisitosPanel, DocumentosPanel
documentos/ GET / POST listDocumentos() / uploadDocumento(payload) DocumentosPanel
documentos/<id>/ DELETE deleteDocumento(id) DocumentosPanel

Design pillars

  • Zero boilerplate in the consumer. No stores, no serializers, no fetch code. Mount one component with a resource slug and a pk.
  • Bring your own transport. You inject a configured axios instance (auth, CSRF, baseURL, interceptors). The library ships no HTTP dependency of its own.
  • Polymorphic signature UI. TransitionDialog mirrors the backend's SignatureRequestSerializer dispatch: FIEL client-side (recommended), FIEL server-side (gated), manual, or fake.
  • Backend drives enforcement. Whether a transition requires a signature comes from preview-transition's firma_requerida, not from client-side config.
  • Graceful degradation. Features that need a newer sinpapel-drf detect their absence and fall back (e.g. without firma_requerida the signature stays optional).
  • Headless-friendly. The client, the Pinia store and the composables are exported, so you can keep the logic and render your own UI.

2. Installation

npm install @aprendomx/sinpapel-vue
# required peer dependencies:
npm install vue pinia quasar

Note: Quasar is a hard peer dependency. Widgets reuse q-* components (e.g., q-dialog, q-icon).

axios is not a dependency: you pass your own instance (see below).


3. Quick start

<script setup>
import axios from 'axios'
import { SeguimientoPanel } from '@aprendomx/sinpapel-vue'
import '@aprendomx/sinpapel-vue/style.css'

const http = axios.create({ withCredentials: true })
</script>

<template>
  <SeguimientoPanel
    :axios="http"
    base-path="/sinpapel/api"
    resource="solicitudes"
    :pk="42"
    current-state="EN_REVISION"
  />
</template>

base-path must match where you mounted the SinpapelRouter in urls.py. The resource prop must be the effective_slug of the model decorated with @workflow_enabled (i.e. endpoint_slug if declared, otherwise workflow_key + "s"). There is no auto-discovery.

Important: SeguimientoPanel creates its store from the initial props. If pk or resource change dynamically, pass :key="pk" to force a remount.


4. Components

SeguimientoPanel

Main composed widget. Renders the current state badge, the tab bar (History / Requirements / Documents / Preview / Metadata / SLA) and the transition dialog.

Props:

Prop Type Required Default Description
axios Object Yes — Axios instance (auth, baseURL, interceptors)
basePath string No /sinpapel/api Base path where the API is mounted
resource string Yes — Resource slug (effective_slug)
pk number | string Yes — Instance ID
currentState string No '' Current state to show in the badge
canEvaluateSla boolean No false Show the SLA tab
locale string No 'es' Language (es or en)

Emits: none (everything handled internally via the store).

StateBadge

State pill with a color dot.

Props:

Prop Type Required Default
estado string Yes —
color string No ''
label string No ''

The default label humanizes the state name (EN_REVISION → EN REVISION). If color is passed, color-mix is used for the background.

HistoryTimeline

Vertical timeline over history entries.

Props:

Prop Type Default Description
entries Array [] History rows
page number 1 Current page
pageSize number 0 Page size (0 = no pagination)
count number 0 Total records

Emits: prev, next.

TransitionDialog

Modal dialog to execute a state transition. Includes target state selector, comments, conditions and polymorphic signature (FIEL client-side/server-side, manual, fake).

Props:

Prop Type Required Default
modelValue boolean No false
client Object Yes —
currentState string No ''
estados Array No []

Emits: update:modelValue, transitioned(result).

Validation:

  • Target state is required
  • A signature backend is required when the backend reports firma_requerida for the chosen target (the "no signature" option is disabled and the fieldset is marked as required)
  • .cer, .key files and password required for FIEL server-side

PreviewTransitionPanel

Read-only panel that previews the impact of a transition before executing it: blocking reasons, missing documents, failed predicates, and a "requires signature" indicator when the report carries firma_requerida.

Props:

Prop Type Required Default
client Object Yes —
targetState string No ''

Debounced by 300ms on targetState changes.

MetadatosForm

Form generated from the backend metadata schema (SCHEMA_METADATOS exposed by GET .../metadatos/).

Props:

Prop Type Required
client Object Yes

Emits: saved(values).

SlaStatusPanel

Panel to evaluate SLA status (admin only — the endpoint is permission-gated server-side).

Props:

Prop Type Required
client Object Yes

RequisitosPanel

Read-only checklist of documentary requirements for the current state (RequisitoEstadoDocumento fulfillment). Consumes GET …/requisitos/.

Props:

Prop Type Required
client Object Yes

DocumentosPanel

Lists, uploads (multipart) and deletes documents for the case. Consumes GET/POST …/documentos/, DELETE …/documentos/{id}/ and GET …/requisitos/. The upload form uses selects: the document type comes from the current state's requirements and the document is a dependent select of the type (e.g. "Identificación" → "Pasaporte" / "INE"). No percentage is asked — it is set by the requirement config (RequisitoEstadoDocumento.porcentaje). Requires sinpapel-drf >= 0.4.0.

Props:

Prop Type Required
client Object Yes

Emits: changed (after upload or delete).


5. Client API

import { createSinpapelClient } from '@aprendomx/sinpapel-vue'

const client = createSinpapelClient({
  axios: myAxiosInstance,     // required
  basePath: '/sinpapel/api',  // default
  resource: 'solicitudes',    // required
  pk: 42,                     // can be changed later via client.pk = ...
})

Methods:

Method HTTP Path Returns
availableTransitions() GET /{resource}/{pk}/available-transitions/ Estado[]
history({page, pageSize}) GET /{resource}/{pk}/history/ HistoryResponse | HistoryEntry[]
previewTransition(targetState) POST /{resource}/{pk}/preview-transition/ PreviewReport
getMetadatos() GET /{resource}/{pk}/metadatos/ {schema, values}
patchMetadatos(values) PATCH /{resource}/{pk}/metadatos/ updated values
slaStatus() POST /{resource}/{pk}/sla-status/ SlaAction[]
transition(payload) POST /{resource}/{pk}/transition/ TransitionResult
requisitos() GET /{resource}/{pk}/requisitos/ RequisitoStatus[]
listDocumentos() GET /{resource}/{pk}/documentos/ InstanciaDocumento[]
uploadDocumento(payload) POST /{resource}/{pk}/documentos/ InstanciaDocumento
deleteDocumento(id) DELETE /{resource}/{pk}/documentos/{id}/ —

transition(payload) accepts { target_state, comentarios?, condiciones?, signature? }. The exported helper buildTransitionRequest(payload) picks the wire format: plain JSON, or multipart/form-data when the signature block carries FIEL server-side files.

uploadDocumento({ archivo, documento?, tipo_documento?, porcentaje?, metadatos? }) is sent as multipart/form-data and must include documento or tipo_documento. The buildDocumentoUpload(payload) helper builds the FormData (encoding metadatos as JSON).

All calls support AbortController for cancellation. The store creates an AbortController per action and exposes cancel().

Error mapping follows sinpapel-drf: 403 for permission/predicate failures, 400 for validation and signature errors. Responses surface untouched in store.error / tx.error.


6. Store & composables

useSeguimientoStore

import { useSeguimientoStore } from '@aprendomx/sinpapel-vue'

const store = useSeguimientoStore({ axios, resource: 'solicitudes', pk: 42 })

Reactive state:

  • estados, historial, historialCount, metadatos, preview, slaActions, documentos, requisitos
  • loading: { estados, historial, metadatos, transicion, documentos, requisitos } (booleans)
  • error: last API error

Actions:

  • cargarEstados(), cargarHistorial(page?), ejecutarTransicion(payload), cargarMetadatos(), guardarMetadatos(values), cargarPreview(targetState), evaluarSla()
  • cargarRequisitos(), cargarDocumentos(), subirDocumento(payload), eliminarDocumento(id) (the last two refresh list + requirements)
  • cancel(): aborts all in-flight requests

useTransition(client)

Manages the state and logic of a transition.

const tx = useTransition(client)
tx.targetState.value = 'APROBADA'
await tx.checkFirmaRequerida()   // asks preview-transition whether a signature is mandatory
tx.comentarios.value = 'Approved by committee'
await tx.submit()                // validates, builds payload, sends, resets on success

Returns: { targetState, comentarios, condiciones, signatureBackend, signatureMode, signatureFields, signaturePayload, firmaRequerida, checkFirmaRequerida, loading, error, errors, buildPayload, submit, reset, validate }

checkFirmaRequerida() is tolerant: clients without previewTransition, older backends, or network errors all resolve to false (signature optional).

useSpLabels()

Gets localized labels. Used automatically inside child components of SeguimientoPanel.

buildSignaturePayload(backend, mode, fields)

Pure helper that shapes the signature block per backend × mode, mirroring SignatureRequestSerializer. Exported for custom transition UIs.


7. Internationalization (i18n)

Supports es (Spanish) and en (English) with no external dependencies.

<SeguimientoPanel ... locale="en" />

To add a new language, create a file in src/locales/ and register it in useSpLabels.js.


8. Theming

CSS variables --sp-* can be overridden in your scope:

:root {
  --sp-color-primary: #3a4a5c;
  --sp-surface: #ffffff;
  --sp-border: #dfe3e8;
  /* ...see src/styles/tokens.css */
}

Remember to import the stylesheet once: import '@aprendomx/sinpapel-vue/style.css'.


9. TypeScript

Type definitions are in types/index.d.ts and resolve automatically:

import { createSinpapelClient, SeguimientoPanel, useTransition } from '@aprendomx/sinpapel-vue'
import type { SinpapelClient, TransitionPayload, Estado, PreviewReport } from '@aprendomx/sinpapel-vue'

10. Compatibility

Vue Pinia Quasar Node (CI)
3.5+ 3.0+ 2.16+ 20, 22

Backend matrix:

Backend package Minimum Notes
sinpapel 0.8.x Engine behind the API
sinpapel-drf 0.3.x Baseline: transitions, history, preview, metadata, SLA
sinpapel-drf 0.4.0 Required by DocumentosPanel (dependent selects: tipo_documento_id, documentos_disponibles)
sinpapel-drf 0.4.4 Required for mandatory-signature enforcement (firma_requerida in the preview report)

Newer features degrade to their previous behavior on older backends rather than breaking.


11. Development & testing

npm install
npm run dev        # development server (demo/)
npm test           # full vitest suite (77 tests)
npm run test:watch # watch mode
npm run build      # library build → dist/
npm run lint       # eslint

CI (.github/workflows/ci.yml) runs lint, tests and build on Node 20 and 22 for every push and pull request to main/master.

Publishing: npm publish. The prepublishOnly script guarantees only code that passes lint + tests + build ships.


12. Known limitations & Roadmap

Limitations:

  • GET …/history/ returns thin django-simple-history records. Comments and signatures are not shown unless the backend exposes them.
  • No auto-discovery of the resource slug; the consumer must pass it explicitly.
  • SeguimientoPanel builds its store from the initial props — dynamic pk/resource need a :key remount.
  • Quasar is required even if you only use a subset of the widgets.

Roadmap:

  • Slot-based customization of the panel tabs.
  • Optional Quasar-free build.
  • Richer history rows once sinpapel-drf exposes them.

13. Versioning & Stability

This package follows Semantic Versioning. The current release is v0.4.0 (Beta). Pre-1.0 contract: minor releases may include breaking changes (documented in the changelog); patch releases are fixes only. Pin the minor ("@aprendomx/sinpapel-vue": "~0.4.0") until 1.0.0.

The public surface is what src/index.js exports: components, createSinpapelClient, buildTransitionRequest, buildDocumentoUpload, useSeguimientoStore, useTransition, buildSignaturePayload.


14. Documentation & agent skills

For AI agents: sinpapel-skills publishes multi-provider skills (Claude, Cursor, OpenCode) for the whole ecosystem. Four of them cover this package: sinpapel-vue-setup, sinpapel-vue-client, sinpapel-vue-components and sinpapel-vue-store.


15. License & Contributing

GPL-3.0-or-later — see LICENSE.

Copyright (C) 2024-2026 AprendoMX. This software is free: you can redistribute it and/or modify it under the terms of the GNU GPL v3. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.

Issues + PRs at https://github.com/aprendomx/sinpapel-vue/issues. Tag with area/sinpapel-vue.

Related projects:

Related Packages

@bildvitta/store-adapter

Adaptador de "stores" para pinia e vuex.

6,215
vue3-django

DRF metadata-driven Vue 3 framework

1,711
quasarwind

CLI for generating custom project vite with Quasar and Tailwind

1,544
pinia-plugin-capacitor-persist

A Vue 3 Pinia plugin which persists store content using the CapacitorJS Preferen...

21,737 9

Version History

Version Released Vue License
0.4.2 ^3.5.0 GPL-3.0-or-later
0.4.1 ^3.5.0 GPL-3.0
0.4.0 ^3.5.0 GPL-3.0