跳到主要内容

Wiki custom macros

Requirements​

This capability is available in ONES 7.45.0. Install and enable the app, using the following tools:

ComponentVersion
ONES7.45.0
@ones-open/web-sdk0.0.20
create-ones-app0.0.20
@ones-open/node-sdk (for backend static updates)0.0.20

Overview​

Wiki custom macros embed custom document blocks directly in the Wiki page body to display and interact with custom content. The macro becomes part of the page content.

The app defines the macro name, edit dialog content, display styles and export content. Wiki manages insertion, viewing and editing. Wiki supplies the edit dialog container; the app defines the configuration UI and its styles inside it.

CapabilityProvided by WikiImplemented by the app
DisplayLoads the render entry into the page body and supplies contextMacro name, display styles and business interactions
EditingToolbar, edit dialog container, permissions and collaboration controlsEdit dialog content, validation and save logic
Static outputDisplays app-defined static content for sharing, mobile, search and exportDefinition and updates of static content

Architecture​

Macros integrate with Wiki through the open platform. Wiki manages the page and macro workflows, the platform connects apps to the product, and the app implements custom content and business logic. Declare macro configuration and entries in opkx.json; after installation and activation, the platform makes them available to Wiki.

Capability relationships​

customData and resource references are saved with the Wiki document; exportSpec is stored in the Wiki macro card. The app manages its own business data. After business data changes, the app backend must explicitly update static content; see Update static content from the app backend.

Viewing, editing and static display​

The configuration flow shows saving and finishing. Cancelling or closing the dialog restores pre-session macro content. App frontend business actions and backend data updates are managed by the app and are separate from saving or cancelling macro configuration.

What users see​

Insert​

In page editing mode, type /, followed by the macro shortcut declared by the app. Each menu row shows the macro icon and name on the left and the shortcut, such as /custom, on the right.

Edit​

Select the macro to insert app content into the page body. In page editing mode, Wiki provides a toolbar with the macro icon, name and declared action buttons. An action opens the configuration form in a dialog. Wiki supplies the dialog container and collaboration controls; the app supplies the configuration UI, validation and save logic.

Finishing editing keeps saved changes. Cancelling or closing the dialog restores macro content from before this edit. See Collaborative editing for multi-user restrictions.

View​

App content appears inside the container provided by Wiki. Your app should provide the display and interactions required by its business logic. Viewing mode does not show the Wiki configuration toolbar.

Static output​

Public sharing, mobile and exports display saved static content without running the macro. Static content supports text, links and images; search extracts searchable text from it.

Capability configuration​

Macros integrate through an app declaration and page entries. The following snippets illustrate configuration and SDK usage without prescribing a business implementation.

Extension declaration​

Merge the following configuration into app.extensions in your app's opkx.json:

opkx.json (excerpt)
{
"app": {
"extensions": {
"wikiMacro": [
{
"key": "customMacro",
"slots": {
"ones:wiki:macro:render": "/web/pages/macro.html",
"ones:wiki:macro:edit": "/web/pages/macro-editor.html"
},
"config": {
"name": "Custom macro",
"shortcut": "custom",
"actions": [{ "id": "configure", "title": "Configure" }]
}
}
]
}
}
}
ConfigurationRequiredPurpose
keyYesUnique macro identifier within the app; keep it stable across upgrades
slotsYesMacro render entries
slots.ones:wiki:macro:renderYesContent render area inserted into the Wiki page body
slots.ones:wiki:macro:editConditionalConfiguration render entry; required when actions are declared. Wiki renders it in an edit dialog during editing
configYesMacro name, icon, shortcut and actions
config.nameYesMacro name in the insertion menu and toolbar
config.shortcutNoShortcut used to find the macro, such as /custom
config.iconNoApp image path; omission uses the transparent default icon
config.actionsNoAction buttons in the Wiki toolbar
config.actions[].idFor each actionUnique action ID within the macro, passed as toolbarState.actionId
config.actions[].titleFor each actionAction button label
config.actions[].iconNoApp icon path for the action button

Entry and icon paths must start with / and refer to resources included in your app build. Use transparent SVG or PNG files for custom icons. Macro keys and action IDs accept letters and digits, up to 64 characters.

Full declaration constraints

Wiki Macro Declaration

Macro context​

Both the render and edit entries can use ONES.getExtensionContext to read the current macro context or subscribe to changes:

Read context once
import { ONES } from '@ones-open/web-sdk'
import type { WikiMacroContext } from '@ones-open/web-sdk'

const context = await ONES.getExtensionContext<WikiMacroContext>()
console.log(context.customData, context.scene, context.writable)
Subscribe to context changes
import { ONES } from '@ones-open/web-sdk'
import type { WikiMacroContext } from '@ones-open/web-sdk'

const unsubscribe = ONES.getExtensionContext<WikiMacroContext>((context) => {
// Update the UI using the latest configuration, scene and editability.
console.log(context.customData, context.scene, context.writable)
})
// Keep unsubscribe and call unsubscribe() when the entry unmounts.
// In React, return it from useEffect; see the render component example below.
InformationFieldsDescription
App and macro identityappId, installationId, macroKeyCurrent app, installation and macro definition
Document locationteamId, pageId, documentId, blockId, cardUuidTeam, page, collaborative document, macro block and static content card
Document contentcustomData, resourcesMacro data and resource IDs saved for the displayed version
Document versiondocumentVersionCurrent collaborative revision or displayed page version
Page scenesceneActive runtime scenes are edit, view and history
Document editabilitywritableWhether configuration editing is allowed, subject to permissions, scene and locks
Insertion stateisInsertedByCurrentUserWhether the current user inserted this runtime instance; useful for first-time setup guidance
Macro editing statetoolbarState{ state: 'init' } or { state: 'editing', actionId, customParams? }

getExtensionContext reads context; it neither saves data nor retrieves the published exportSpec. Public sharing, mobile and search do not run macros and send no context callbacks to the app.

writable controls document configuration editing, not app business permissions. Viewing mode may allow business actions under app permissions; historical versions must disable all mutations. Subscribe to changes, and authenticate and authorize business actions on your backend.

Implementation​

After declaring the extension, implement the render and edit entries and use macro context to connect configuration with content. The examples below support the insertion, editing and viewing flow described above.

Render entry​

The render entry displays content from customData. Mount this component using your app template at the entry declared by ones:wiki:macro:render:

web/pages/macro/index.tsx (render component example)
import { ONES } from '@ones-open/web-sdk'
import type { WikiMacroContext } from '@ones-open/web-sdk'
import { useEffect, useState } from 'react'

export default function MacroContent() {
const [context, setContext] = useState<WikiMacroContext>()

useEffect(() => ONES.getExtensionContext<WikiMacroContext>(setContext), [])

if (!context) return <p>Loading…</p>

const data = context.customData
const text =
data && typeof data === 'object' && !Array.isArray(data) && typeof data.text === 'string'
? data.text
: 'No content yet'

return (
<section>
<p>{text}</p>
{context.scene === 'history' && <p>Historical version · Read only</p>}
</section>
)
}

If your app needs an additional configuration entry inside macro content, show it only when scene === 'edit', writable === true and toolbarState.state === 'init', then call Wiki.macro.openEditor({ actionId: 'configure' }).

Edit entry and content saving​

The edit entry is the configuration UI declared by ones:wiki:macro:edit. Wiki page and macro editing have distinct lifecycles:

StageWiki behaviorApp responsibility
App enabled or page openedOffers insertion or loads an existing macro's render entryReads saved customData; loading alone does not change the document
Macro inserted and first configuredCreates the instance; a declared action opens configurationInitializes and saves customData, exportSpec and resources through saveData
Configuration reopenedAcquires an edit session and opens the entry with actionIdInitializes a draft from current customData and identifies the selected action
Macro content savedConfirms data and static content while keeping editing openSubmits complete content through saveData; retains the draft on failure
Editing finishedfinishEdit ends the session and keeps acknowledged savesWaits for saveData before finishing; finishing does not save the form itself
Editing cancelled or dialog closedRestores data, static content and resource references from before this editCalls cancelEdit; separate app database writes are not rolled back
Wiki page publishedSaves a page version through the page publication flowSaving or finishing a macro does not publish the entire Wiki page

Initialize the form from context and identify the action through toolbarState.actionId. Each saved field has a distinct purpose:

  • customData initializes and changes macro configuration, such as display settings, form content or a business record ID.
  • exportSpec defines static content for sharing, mobile, search and export; update it when data changes affect static output.
  • resources contains referenced document resource IDs, not original filenames or binary file content.

On confirmation, save complete content before ending editing:

web/pages/macro-editor/index.tsx (form save logic excerpt)
import { ONES, Wiki } from '@ones-open/web-sdk'
import type { WikiMacroContext } from '@ones-open/web-sdk'

async function saveMacroContent(text: string) {
const context = await ONES.getExtensionContext<WikiMacroContext>()
if (!context.writable || context.toolbarState.state !== 'editing') return

await Wiki.macro.saveData({
customData: { text },
exportSpec: [{ type: 'text', data: text }],
resources: [],
})
await Wiki.macro.finishEdit()
}

async function cancelMacroEdit() {
await Wiki.macro.cancelEdit()
}

saveData submits complete content, not a partial update:

FieldContent
customDataApp JSON data such as display configuration or a business record ID; at most 32 KiB of serialized UTF-8 content
exportSpecStatic content for sharing, mobile, search and export, displayed in array order
resourcesDocument resource IDs referenced by the macro; pass [] when none are needed

Document configuration is stored in customData and participates in Wiki page versioning. Business data can be stored separately in Hosted Storage or an app database, with a business record ID referenced from customData.

On a save failure, retain the draft and show an error. Do not call finishEdit or report success early. Disable duplicate submissions while saving and update form editability when context changes.

Call saveData only from the macro edit entry, never from ordinary viewing mode.

Build and install​

After the app is built, installed and enabled, its macros appear in the Wiki insertion menu. Follow the insertion and editing flow above to configure a macro, then publish the page.

Wiki pages displayed in Project directory components also support macros without an extra entry. Work item descriptions do not support macros; pasted macro blocks are filtered out.

Static content and data updates​

exportSpec supports these formats. Text is plain text and does not interpret HTML:

const imageId = await Wiki.macro.uploadResource(file)

await Wiki.macro.saveData({
customData: {
text: 'Content summary',
image: { resourceId: imageId, originalName: file.name },
},
exportSpec: [
{ type: 'text', data: 'Content summary' },
{ type: 'link', data: { title: 'Instructions', url: 'https://example.com/details' } },
{ type: 'image', data: imageId },
],
resources: [imageId],
})

Use this excerpt in the macro edit entry; file comes from your file selection form. uploadResource returns a Wiki document resource ID. Files must not exceed 20 MiB and are subject to Wiki file type and quota restrictions. Uploading does not save macro content; reference the resource in a later save. This replaces complete content, so also submit any other configuration and resources you need to retain.

Uploads and original filenames​

After obtaining a File from a file selection form, the app can read file.name, the original selected filename. The SDK submits this name together with the uploaded content.

Wiki.macro.uploadResource(file) returns only Promise<string>, containing the document resource ID. It does not return an additional original filename. The image example above saves file.name alongside the resource ID in customData.image, so reopening the macro can restore both from context. resources still contains IDs only.

Do not infer filenames from resource IDs. The macro SDK currently has no method to look up original filenames by resource ID. Backend uploads take an app-supplied filename through uploadResource({ name, data }); retain it in the app when needed.

Update static content from the app backend​

When app business data changes, the backend can call saveExportSpec to update the associated macro’s static content. Business persistence and static updates are separate operations and do not synchronize automatically.

App backend: update static content for the current macro
import { wiki } from '@ones-open/node-sdk'

// installationInfo comes from installation callback data stored by the backend.
// context is supplied by the render entry; validate and retain the association.
const macro = wiki.macro(installationInfo).instance(context)
await macro.saveExportSpec([{ type: 'text', data: 'Content summary' }], [])

Keep installation credentials on the backend. saveExportSpec submits complete static content and resource references. It changes no macro configuration and creates no page version. Refresh the share or mobile page, or create a new export, to see successfully published updates. Existing exported files are unchanged.

If business persistence succeeds but publication fails, retry only static synchronization to avoid repeating the business operation. When multiple macros reference one business record, retain each macro's context and synchronize each separately.

Collaborative editing​

Only one session can edit a macro's configuration at a time. Wiki manages locks, release and state synchronization; your app does not need its own lock or unlock button.

ScenarioWhat users seeActions and restrictions
No session is editingPage editing mode shows the macro icon, name and action buttonsUsers with edit permission can open the configuration dialog
This window is editingThe dialog displays the app's form; configuration buttons in the page body are disabledConfigure, save or cancel in the dialog
Another window is editingA lock-status icon and inline editing hint replace configuration buttons; macro content remains visibleConfiguration editing is unavailable; the app receives writable: false
Editing finishes or is cancelledThe dialog closes; other windows restore configuration buttons after state synchronizationThe collaboration lock is released
Viewing, historical versions or no edit permissionNo Wiki editing toolbar or lock hintNo configuration editing; apps must also disable business mutations in historical versions

Two tabs signed in as the same account are separate sessions. A locked macro cannot be moved, deleted or replaced, including through its parent container. Other page content remains editable. Configuration entries inside your app must also react to writable and toolbarState. On failure, retain the draft and follow the error guidance to retry or reopen editing.

Display in other scenarios​

ScenarioDisplayApp responsibility
Desktop viewing and editingRuns the render entry; editing can open the configuration formAdapt configuration entries to context; authorize business actions in the app
Desktop historyRuns the render entry with historical configurationDisable mutations; business storage does not automatically return to a historical state
Public sharing, mobile and exportsUses the last successfully saved exportSpecProvide readable static content that does not depend on app execution
App disabled, uninstalled or macro load failureUses saved static content, or a placeholder when none existsDo not rely on the render entry to handle these scenarios

Wiki shows a skeleton while the macro loads. Your app handles loading its own business data. Existing macros can run again after the app is re-enabled. Keep macro identifiers stable across upgrades and support previously saved configuration.

FAQ​

Why does the share page show old content after the app content changes?

Publish results through backend saveExportSpec. Sharing and exports do not query application storage live. Refresh the page or export again after synchronization succeeds.

Do macro content updates create page versions?

Business data writes and saveExportSpec do not create page versions. Configuration changes through saveData participate in normal page editing and versioning.

Do historical versions restore app business data?

Wiki provides historical macro configuration, but application business storage is not rolled back. Store and read the relevant historical business data in your app when required.

Web SDK quick reference

See Wiki macro types for type definitions and every field, and ONES.getExtensionContext for callback parameters, return values and cleanup.

All methods return a Promise and act on the current macro.

MethodPurpose
openEditor({ actionId, customParams? })Opens a declared edit action
saveData({ customData, exportSpec, resources })Saves complete macro content and keeps editing open
finishEdit()Waits for saves and ends editing
cancelEdit()Restores content from before editing and exits
uploadResource(file)Uploads a document resource and returns its ID; requires sign-in and card read permission, but no edit session
setStatus('valid' | 'dataInvalid' | 'resourceInvalid')Reports render status; invalid states cause Wiki to show static content
Node SDK quick reference

See Wiki macro SDK for backend integration and Types and fields for installation data, macro context and file fields.

InterfacePurpose
wiki.macro(installationInfo)Create a client with installation credentials
client.instance(context)Bind an existing macro instance
macro.uploadResource({ name, data })Upload document resources and return resource IDs
macro.saveExportSpec(exportSpec, resources)Update complete static content and resource references