Skip to main content

[!WARNING] This package is deprecated and no longer maintained. Please migrate to arches-vue-components instead.

Arches Component Lab

A Vue 3 / PrimeVue component library for building custom Arches applications.

Installation

pip install arches-component-lab

Project Configuration

  1. If you do not already have an Arches project, create one by following the instructions in the Arches documentation.

  2. Add arches_querysets and arches_component_lab to INSTALLED_APPS below the name of your project but above arches. For Arches >= 8.x, also add pgtrigger:

INSTALLED_APPS = (
    "my_project_name",
    ...
    "arches_querysets",
    "arches_component_lab",
    "arches",
    ...
    "pgtrigger",
)
  1. Add arches_component_lab as a dependency in package.json:
"dependencies": {
    "arches_component_lab": "archesproject/arches-component-lab#main"
}
  1. Add the arches_component_lab URLs to urls.py:
urlpatterns = [
    path("", include("arches_component_lab.urls")),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  1. Start your project and install frontend dependencies:
python manage.py runserver
npm install && npm run build_development
  1. Check for missing WidgetMapping records:
python manage.py validate --codes 2001 --verbosity 2

See Extending Arches Component Lab if any are missing.

Frontend API

Bootstrapping an app

import MyComponent from '@/my_project/MyComponent.vue';

import { createVueApplication } from '@/arches_component_lab/application';

createVueApplication({ component: MyComponent }).then(app => app.mount('#app'));

Widgets

GenericWidget looks up the widget mapped to a node (see Extending Arches Component Lab) and resolves the real component at runtime. In edit mode it wraps the resolved widget in a GenericFormField, which registers the node as a PrimeVue Forms FormField keyed by nodeAlias, ties its dirty/touched state and validation errors into an ancestor <Form>, and renders those errors:

<script setup lang="ts">
import { ref } from 'vue';

import GenericWidget from '@/arches_component_lab/generics/GenericWidget/GenericWidget.vue';

import type { WidgetMode } from '@/arches_component_lab/widgets';
import type { AliasedNodeData } from '@/arches_component_lab/generics';

const MODE: WidgetMode = 'edit';
const nodeData = ref<AliasedNodeData | null>(null);
</script>

<template>
    <GenericWidget
        node-alias="my_text_node"
        graph-slug="my_graph"
        :mode="MODE"
        :aliased-node-data="nodeData"
        @update:aliased-node-data="nodeData = $event"
    />
</template>

aliasedNodeData/value are both optional. Without either, GenericWidget falls back to the node's configured default (cardXNodeXWidgetData.config.defaultValue, part of the widget config it already fetches), so it renders from just graphSlug/nodeAlias/mode:

<template>
    <GenericWidget
        node-alias="my_text_node"
        graph-slug="my_graph"
        mode="edit"
    />
</template>

Importing a widget directly skips the runtime resolution and the FormField integration described above. The widget emits update:aliasedNodeData/update:value on its own (some widgets also emit update:isDirty); the caller wires that into any surrounding form:

<script setup lang="ts">
import { ref } from 'vue';

import { TextWidget } from '@/arches_component_lab/widgets';

import type { WidgetMode } from '@/arches_component_lab/widgets';
import type { StringAliasedNodeData } from '@/arches_component_lab/datatypes';

const MODE: WidgetMode = 'edit';
const nodeData = ref<StringAliasedNodeData | null>(null);
</script>

<template>
    <TextWidget
        :mode="MODE"
        :aliased-node-data="nodeData"
        @update:aliased-node-data="nodeData = $event"
    />
</template>

Cards

GenericCard renders a whole nodegroup. It fetches the tile (fetchTileData) and every node's widget config, then renders GenericCardEditor or GenericCardViewer depending on mode. The editor wraps a PrimeVue Form and renders one GenericWidget per node, and saves the collected tile with upsertTile — from its own save button, or by calling .save() on it directly (exposed via defineExpose).

<script setup lang="ts">
import { ref } from 'vue';

import GenericCard from '@/arches_component_lab/generics/GenericCard/GenericCard.vue';

import type { AliasedTileData } from '@/arches_component_lab/generics';

const tileData = ref<AliasedTileData>();
</script>

<template>
    <GenericCard
        graph-slug="my_graph"
        nodegroup-alias="my_nodegroup"
        :resource-instance-id="resourceInstanceId"
        :tile-id="tileId"
        :tile-data="tileData"
        mode="edit"
        @update:tile-data="tileData = $event"
        @save="tileData = $event"
        @reset="() => {}"
    />
</template>

Reference

@/arches_component_lab/widgets

Name Type Description
WidgetMode 'edit' | 'view' | 'configure' The three states a widget can render in
BaseWidgetProps { mode: WidgetMode; nodeAlias?: string; graphSlug?: string } Props every widget accepts

Every widget's aliasedNodeData/cardXNodeXWidgetData prop is typed to one specific datatype. Where no widget-specific cardXNodeXWidgetData type is listed, the widget uses the base CardXNodeXWidgetData (no extra config fields). Both columns import from @/arches_component_lab/datatypes:

Widget aliasedNodeData type cardXNodeXWidgetData type
TextWidget, RichTextWidget StringAliasedNodeData StringCardXNodeXWidgetData
NonLocalizedTextWidget NonLocalizedTextAliasedNodeData CardXNodeXWidgetData
NumberWidget NumberAliasedNodeData NumberCardXNodeXWidgetData
DatePickerWidget DateAliasedNodeData DateCardXNodeXWidgetData
EDTFWidget EDTFAliasedNodeData CardXNodeXWidgetData
ConceptSelectWidget ConceptAliasedNodeData CardXNodeXWidgetData
ConceptRadioWidget ConceptAliasedNodeData ConceptCardXNodeXWidgetData
ConceptMultiselectWidget ConceptListAliasedNodeData CardXNodeXWidgetData
DomainSelectWidget, DomainRadioWidget DomainAliasedNodeData DomainCardXNodeXWidgetData
DomainCheckboxWidget, DomainMultiselectWidget DomainListAliasedNodeData DomainCardXNodeXWidgetData
LanguageSelectWidget LanguageAliasedNodeData CardXNodeXWidgetData
RadioBooleanWidget, SwitchWidget BooleanAliasedNodeData BooleanCardXNodeXWidgetData
ResourceInstanceSelectWidget ResourceInstanceAliasedNodeData ResourceInstanceCardXNodeXWidgetData
ResourceInstanceMultiselectWidget ResourceInstanceListAliasedNodeData ResourceInstanceListCardXNodeXWidgetData
FileListWidget FileListAliasedNodeData FileListCardXNodeXWidgetData
NodeValueSelectWidget NodeValueAliasedNodeData CardXNodeXWidgetData
URLWidget URLAliasedNodeData CardXNodeXWidgetData
MapWidget GeoJSONFeatureCollectionAliasedNodeData MapCardXNodeXWidgetData

@/arches_component_lab/generics

GenericWidget/GenericCard resolve their concrete component at runtime instead of being imported directly — that is the "generic" here, not a TypeScript <T>.

Export Description
GenericCard Card editor/viewer for a nodegroup
GenericWidget Single widget resolved from widget config
GenericCardProps, GenericWidgetProps Props interfaces
AliasedNodeData, AliasedTileData Node/tile value types

GenericWidgetProps:

Name Type Description
graphSlug string Graph the node belongs to
nodeAlias string Node to render
mode WidgetMode 'edit', 'view', or 'configure'
aliasedNodeData AliasedNodeData | null Current value; takes priority over value
value unknown Raw value fallback, used only if aliasedNodeData is omitted
cardXNodeXWidgetData CardXNodeXWidgetData Pre-fetched widget config; skips GenericWidget's own fetch
cardXNodeXWidgetDataOverrides Partial<CardXNodeXWidgetData> Merged into the fetched config after fetching
isDirty boolean Marks the field dirty on the surrounding <Form>
shouldShowLabel boolean Show the node's label (default true)

GenericCardProps:

Name Type Description
graphSlug string Graph the nodegroup belongs to
nodegroupAlias string Nodegroup to render
mode WidgetMode 'edit', 'view', or 'configure'
resourceInstanceId string | null Resource this tile belongs to, for a new tile
selectedNodeAlias string | null Node to focus within the card
shouldShowFormButtons boolean Show the built-in save/reset buttons (default true)
tileData AliasedTileData Pre-fetched tile; skips GenericCard's own fetch
tileId string | null Tile to fetch when tileData is not provided

@/arches_component_lab/datatypes

*AliasedNodeData types are listed in the widget table above. Supporting types:

Export Description
LanguageValue Per-language string value ({ value: string; direction: 'ltr' | 'rtl' })
URLNodeValue URL node value ({ url: string; url_label: string })
FileReference File attachment reference
ResourceInstanceReference Resource instance link reference
DomainOption Domain value option

@/arches_component_lab/application

Name Type
createVueApplication (options: CreateVueApplicationOptions) => Promise<App>
generateArchesURL (urlName: string, urlParameters?: Record<string, string | number>, queryParameters?: Record<string, string | number>, languageCode?: string) => string
CreateVueApplicationOptions { component: Component; themeConfiguration?: ArchesThemeConfiguration; initialProps?: Record<string, unknown> }

@/arches_component_lab/themes

Name Type Description
DEFAULT_THEME ArchesThemeConfiguration Theme createVueApplication uses when themeConfiguration is not passed
ArchesThemeConfiguration PrimeVue theme configuration shape

Creating a Custom Widget

A widget is an editor/viewer pair plus a dispatcher that picks between them by mode. The example below, RatingWidget, is a new widget for the existing number datatype.

[!IMPORTANT] Use defineProps([...])/defineEmits([...]) cast as the real type, shown below — never defineProps<T>()/defineEmits<T>() with a generic argument. That generic argument makes @vue/compiler-sfc resolve types via its own tsconfig walk, separate from webpack, which breaks on a real (non-editable) pip install.

  1. Create widgets/RatingWidget/ with a types.ts extending BaseWidgetProps:
import type { BaseWidgetProps } from "@/arches_component_lab/widgets/types.ts";
import type {
    NumberAliasedNodeData,
    NumberCardXNodeXWidgetData,
} from "@/arches_component_lab/datatypes/number/types.ts";

export interface RatingWidgetProps extends BaseWidgetProps {
    cardXNodeXWidgetData?: NumberCardXNodeXWidgetData;
    aliasedNodeData?: NumberAliasedNodeData | null;
    value?: number | null;
}
  1. Add RatingWidget.vue, the dispatcher — switches on mode, re-emits update:aliasedNodeData, update:value, initialized:
<script setup lang="ts">
import { computed } from "vue";

import RatingWidgetEditor from "@/arches_component_lab/widgets/RatingWidget/components/RatingWidgetEditor.vue";
import RatingWidgetViewer from "@/arches_component_lab/widgets/RatingWidget/components/RatingWidgetViewer.vue";

import { EDIT, VIEW } from "@/arches_component_lab/widgets/constants.ts";
import { buildNumberAliasedNodeData } from "@/arches_component_lab/datatypes/number/utils.ts";

import type { NumberAliasedNodeData } from "@/arches_component_lab/datatypes/number/types.ts";
import type { RatingWidgetProps } from "@/arches_component_lab/widgets/RatingWidget/types.ts";

const { aliasedNodeData, value } = defineProps([
    "mode",
    "nodeAlias",
    "graphSlug",
    "cardXNodeXWidgetData",
    "aliasedNodeData",
    "value",
]) as RatingWidgetProps;

const emit = defineEmits([
    "update:value",
    "update:aliasedNodeData",
    "initialized",
]) as {
    (event: "update:value", updatedValue: number | null): void;
    (event: "update:aliasedNodeData", updatedValue: NumberAliasedNodeData): void;
    (event: "initialized", updatedValue: NumberAliasedNodeData): void;
};

const resolvedAliasedNodeData = computed(
    () => aliasedNodeData ?? buildNumberAliasedNodeData(value ?? null),
);

function onUpdateAliasedNodeData(updated: NumberAliasedNodeData) {
    emit("update:aliasedNodeData", updated);
    emit("update:value", updated.node_value);
}
</script>

<template>
    <RatingWidgetEditor
        v-if="mode === EDIT"
        :card-x-node-x-widget-data="cardXNodeXWidgetData"
        :aliased-node-data="resolvedAliasedNodeData"
        @update:aliased-node-data="onUpdateAliasedNodeData"
        @initialized="emit('initialized', $event)"
    />
    <RatingWidgetViewer
        v-else-if="mode === VIEW"
        :aliased-node-data="resolvedAliasedNodeData"
        @initialized="emit('initialized', $event)"
    />
</template>
  1. Add the editor and viewer. Both emit initialized on mount:
<!-- components/RatingWidgetEditor.vue -->
<script setup lang="ts">
import { onMounted } from "vue";
import Rating from "primevue/rating";

import { buildNumberAliasedNodeData } from "@/arches_component_lab/datatypes/number/utils.ts";

import type { NumberAliasedNodeData } from "@/arches_component_lab/datatypes/number/types.ts";

const { aliasedNodeData } = defineProps(["aliasedNodeData"]) as {
    aliasedNodeData: NumberAliasedNodeData | null;
};

const emit = defineEmits(["update:aliasedNodeData", "initialized"]) as {
    (event: "update:aliasedNodeData", updatedValue: NumberAliasedNodeData): void;
    (event: "initialized", updatedValue: NumberAliasedNodeData): void;
};

onMounted(() => {
    emit("initialized", aliasedNodeData ?? buildNumberAliasedNodeData(null));
});

function onUpdateModelValue(updatedValue: number | null) {
    emit("update:aliasedNodeData", buildNumberAliasedNodeData(updatedValue));
}
</script>

<template>
    <Rating
        :model-value="aliasedNodeData?.node_value ?? null"
        @update:model-value="onUpdateModelValue($event)"
    />
</template>
<!-- components/RatingWidgetViewer.vue -->
<script setup lang="ts">
import { onMounted } from "vue";

import type { NumberAliasedNodeData } from "@/arches_component_lab/datatypes/number/types.ts";

const { aliasedNodeData } = defineProps(["aliasedNodeData"]) as {
    aliasedNodeData: NumberAliasedNodeData;
};

const emit = defineEmits(["initialized"]) as {
    (event: "initialized", updatedValue: NumberAliasedNodeData): void;
};

onMounted(() => emit("initialized", aliasedNodeData));
</script>

<template>
    <div>{{ aliasedNodeData?.display_value }}</div>
</template>
  1. Reuse an existing datatype module (@/arches_component_lab/datatypes — string, number, boolean, concept, domain, etc.) for the value shape, as above, or add a new one following the same types.ts + build<Datatype>AliasedNodeData utils.ts pattern.

  2. If contributing to Arches Component Lab, export it from widgets/index.ts:

export { default as RatingWidget } from "@/arches_component_lab/widgets/RatingWidget/RatingWidget.vue";
export type { RatingWidgetProps } from "@/arches_component_lab/widgets/RatingWidget/types.ts";
  1. Register it — see Extending Arches Component Lab.

Extending Arches Component Lab

Arches Component Lab uses the WidgetMapping model to map widgets to their Vue components. To check for missing mappings:

python manage.py widget check_mappings

To add a mapping:

python manage.py widget add_mapping -wn language-select -cp arches_component_lab/widgets/LanguageSelectWidget/LanguageSelectWidget.vue

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

arches_component_lab-0.1.0.tar.gz (317.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arches_component_lab-0.1.0-py3-none-any.whl (219.8 kB view details)

Uploaded Python 3

File details

Details for the file arches_component_lab-0.1.0.tar.gz.

File metadata

  • Download URL: arches_component_lab-0.1.0.tar.gz
  • Upload date:
  • Size: 317.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.5

File hashes

Hashes for arches_component_lab-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f31341ea85039dd402f189ebaafe8d4915c059592d30302644954d5be5626919
MD5 1ce7240bb2664a347feec7efada9ebb1
BLAKE2b-256 443b91edcddc2abcbe07f92705669beaf519e230c258e482b9082363271043be

See more details on using hashes here.

File details

Details for the file arches_component_lab-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for arches_component_lab-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 796d416aa232f3b64c30f505ea93e7a39a945937e8fb825c9d4f03fee9c48e07
MD5 7742b21b7dce4b328d25d5f795c89bfd
BLAKE2b-256 95773333a1315ab3c02051bca6438e887f012c1bc836a1734819622f0abfdbab

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page