Skip to content

Data Persistence

Apps can store data in different ways. The choice of storage depends on the use case and the requirements of the app.

Canvas context

For storing data that is specific to a given canvas, the context object can be used. Context is a JSON object that can be manipulated by the app components. The context object is persisted in the canvas and is publicly available to all components and apps to read and write.

Since context is part of the canvas, any changes to it must be persisted on the server through a request. This means it can take a while to persist.

Summary: Access context via the useCanvas composable, which provides the activeCanvas property and saveCanvasContext method. Apps can read and modify specific sections of the context object using their own namespaces.

Apps DB

Apps DB is a simple key-value store that is either instance specific or user-instance specific. Each Apps DB entry is scoped to:

  • instance_id: the id of CatalogIQ instance the entry belongs to
  • store_name: arbitrary name of the store that can be used to group entries
  • key: the key of the entry
  • user_id: the id of the user the entry belongs to (only used for user-instance specific entries)

For the full specification, check out the Apps DB REST API documentation.

Summary: Use the useAppsDb composable to interact with Apps DB. This gives you access to methods like upsertEntry, getEntry, and deleteEntry for storing and retrieving data.

Browser storage

For storing data that is specific to the user and the browser, the localStorage can be used. localStorage is a key-value store that is persisted in the browser and is available to the app even after the page is reloaded.

Due to its nature you can use the localStorage object to instantly share data between different apps that are running on the page without burdening the server.

Keep in mind that localStorage can be removed at any time, has a size limit that depends on the browser and that it is not shared between different browsers or devices.

Other browser storage mechanisms like sessionStorage or IndexedDB can also be used.

Summary: The Canvas UI system primarily uses VueUse's useLocalStorage and useSessionStorage composables for reactive browser storage. For larger datasets, IndexedDB implementation is available in some components.

External storage

Since apps are web pages, they can use any external server as a storage mechanism. Please note that in this case the app is responsible for the security and availability of the data.

Summary: Implement HTTP requests to external servers using the Fetch API or Axios. Ensure proper authentication and error handling when connecting to external services.


Implementation Examples

Canvas Context

typescript
// Access canvas context
import { useCanvas } from '@canvas-builder/composables/useCanvas'

const { saveCanvasContext, activeCanvas } = useCanvas()

// Read order data from context
const submittedOrders = computed(() => 
  activeCanvas.value?.context?.omAppData?.submittedOrders || []
)
const orderReference = activeCanvas.value?.context?.omAppData?.draftOrder?.custRef || ''

// Save data to context
async function saveOrderData(draftOrder) {
  await saveCanvasContext({
    omAppData: {
      draftOrder,
      lastUpdated: new Date().toISOString()
    }
  })
}

Apps DB

typescript
import { useAppsDb } from '@lib/composables/appsDb.use'
import { APPS_DB } from '@lib/constants/appsDb.const'

const appsDb = useAppsDb({ pitcherInfo, restApiAxios })

// Save block overrides
async function saveBlockOverrides(blockId, overrides) {
  await appsDb.upsertEntry({
    store_name: APPS_DB.STORES.BLOCK_OVERRIDES,
    user_id: myUser.value.id,
    entry_key: `${APPS_DB.ENTRIES.BLOCK_OVERRIDES}_${blockId.toLowerCase()}`,
    data: overrides,
  })
}

// Get agenda items
async function getAgenda() {
  const result = await appsDb.getEntry({
    store_name: APPS_DB.STORES.PITCH_MASTER,
    user_id: myUser.value.id,
    entry_key: APPS_DB.ENTRIES.AGENDA,
  })
  return result?.data
}

Browser Storage

typescript
// Using VueUse for reactive localStorage
import { useLocalStorage } from '@vueuse/core'

// Smart folders path storage
const currentPath = useLocalStorage('canvas_smart-folders_current_path', [], {
  serializer: {
    read: (v) => JSON.parse(v || '[]'),
    write: (v) => JSON.stringify(v),
  },
})

// Using sessionStorage for pagination
import { useSessionStorage } from '@vueuse/core'

const pageSize = useSessionStorage('canvases-pageSize', 10)
const currentFilters = useSessionStorage('canvases-filters', {})

External Storage

typescript
// Call Pitcher API to store data
async function savePitcherData(data) {
  const response = await restApiAxios.post('/api/v2/data/store', {
    data_type: 'canvas_external_data',
    content: JSON.stringify(data),
    instance_id: pitcherInfo.instanceId
  })
  
  return response.data
}