2.7 KiB
Contribution Guide for unraid/api/web
Web Components
For legacy compatibility, Unraid ships web components to the webgui. These components
are written as Vue and turned into web components as a build step. By convention,
Vue components that are built as top-level web components are suffixed with *.ce.vue
for "custom element", which comes from the tool used for compilation: nuxt-custom-elements.
Note: nuxt-custom-elements is currently pinned to a specific version because
our build process breaks in later versions.
Graphql
Unraid uses graphql to fetch & update server-related data. The web code uses graphql-codegen to
sync graphql schemas & generate typescript types & utilities.
During development, we often have npm run codegen:watch running in the background.
When using graphql, import helper functions from ~/composables, e.g.:
import { graphql } from "~/composables/gql/gql";
Use it to define type fragments, queries, and mutations, e.g.:
export const NOTIFICATION_FRAGMENT = graphql(/* GraphQL */ `
fragment NotificationFragment on Notification {
id
title
subject
description
importance
link
type
timestamp
}
`);
export const getNotifications = graphql(/* GraphQL */ `
query Notifications($filter: NotificationFilter!) {
notifications {
id
list(filter: $filter) {
...NotificationFragment
}
}
}
`);
export const archiveNotification = graphql(/* GraphQL */ `
mutation ArchiveNotification($id: String!) {
archiveNotification(id: $id) {
...NotificationFragment
}
}
`);
Note the /* GraphQL */ pragma. This enables syntax highlighting & type-sense for
graphql stuff. It also helps the codegen and codegen:watch npm scripts validate mutations,
queries, etc against the graphql schema.
You should define graphql-related snippets outside of your Vue components, so they're easier to re-use and independently validate. We recommend placing them in the same component folder.
Fragments
Graphql fragments help keep your graphql requests simpler and more maintainable, but they also make responses type-safe. Here's an example.
const { result } = useQuery(getNotifications);
const notifications = computed(() => {
if (!result.value?.notifications.list) return [];
const list = useFragment(
NOTIFICATION_FRAGMENT,
result.value?.notifications.list
);
return list;
});
Through useFragment, list will always be the correct type: a list of notification fragments.
Since the codegen npm scripts keep our types and schemas synced with the api, breaking
changes will cause a type-error that can easily be caught during development, testing, and CI.