Parcourir la source

docs(admin-ui): Add docs for common Admin UI APIs

Michael Bromley il y a 4 ans
Parent
commit
a9c740e75b
50 fichiers modifiés avec 805 ajouts et 45 suppressions
  1. 2 0
      .gitignore
  2. 13 0
      docs/content/admin-ui-api/_index.md
  3. 39 0
      packages/admin-ui/src/lib/core/src/common/base-detail.component.ts
  4. 28 1
      packages/admin-ui/src/lib/core/src/common/base-entity-resolver.ts
  5. 75 1
      packages/admin-ui/src/lib/core/src/common/base-list.component.ts
  6. 31 0
      packages/admin-ui/src/lib/core/src/common/component-registry-types.ts
  7. 54 12
      packages/admin-ui/src/lib/core/src/data/providers/data.service.ts
  8. 14 4
      packages/admin-ui/src/lib/core/src/data/query-result.ts
  9. 43 14
      packages/admin-ui/src/lib/core/src/providers/modal/modal.service.ts
  10. 5 1
      packages/admin-ui/src/lib/core/src/providers/nav-builder/nav-builder.service.ts
  11. 41 2
      packages/admin-ui/src/lib/core/src/providers/notification/notification.service.ts
  12. 18 0
      packages/admin-ui/src/lib/core/src/shared/components/asset-picker-dialog/asset-picker-dialog.component.ts
  13. 20 0
      packages/admin-ui/src/lib/core/src/shared/components/chip/chip.component.ts
  14. 11 0
      packages/admin-ui/src/lib/core/src/shared/components/currency-input/currency-input.component.ts
  15. 59 0
      packages/admin-ui/src/lib/core/src/shared/components/data-table/data-table.component.ts
  16. 17 0
      packages/admin-ui/src/lib/core/src/shared/components/datetime-picker/datetime-picker.component.ts
  17. 25 0
      packages/admin-ui/src/lib/core/src/shared/components/dropdown/dropdown.component.ts
  18. 22 0
      packages/admin-ui/src/lib/core/src/shared/components/facet-value-selector/facet-value-selector.component.ts
  19. 1 1
      packages/admin-ui/src/lib/core/src/shared/components/modal-dialog/modal-dialog.component.ts
  20. 8 0
      packages/admin-ui/src/lib/core/src/shared/components/object-tree/object-tree.component.ts
  21. 10 0
      packages/admin-ui/src/lib/core/src/shared/components/order-state-label/order-state-label.component.ts
  22. 12 0
      packages/admin-ui/src/lib/core/src/shared/components/product-selector/product-selector.component.ts
  23. 12 1
      packages/admin-ui/src/lib/core/src/shared/components/rich-text-editor/rich-text-editor.component.ts
  24. 14 0
      packages/admin-ui/src/lib/core/src/shared/directives/if-multichannel.directive.ts
  25. 3 0
      packages/admin-ui/src/lib/core/src/shared/directives/if-permissions.directive.ts
  26. 7 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/boolean-form-input/boolean-form-input.component.ts
  27. 8 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/code-editor-form-input/json-editor-form-input.component.ts
  28. 7 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/currency-form-input/currency-form-input.component.ts
  29. 8 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/customer-group-form-input/customer-group-form-input.component.ts
  30. 7 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/date-form-input/date-form-input.component.ts
  31. 8 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/facet-value-form-input/facet-value-form-input.component.ts
  32. 7 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/number-form-input/number-form-input.component.ts
  33. 7 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/password-form-input/password-form-input.component.ts
  34. 8 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/product-selector-form-input/product-selector-form-input.component.ts
  35. 33 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/register-dynamic-input-components.ts
  36. 9 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/relation-form-input/relation-form-input.component.ts
  37. 7 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/rich-text-form-input/rich-text-form-input.component.ts
  38. 8 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/select-form-input/select-form-input.component.ts
  39. 7 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/text-form-input/text-form-input.component.ts
  40. 7 0
      packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/textarea-form-input/textarea-form-input.component.ts
  41. 14 0
      packages/admin-ui/src/lib/core/src/shared/pipes/asset-preview.pipe.ts
  42. 8 0
      packages/admin-ui/src/lib/core/src/shared/pipes/duration.pipe.ts
  43. 8 0
      packages/admin-ui/src/lib/core/src/shared/pipes/file-size.pipe.ts
  44. 3 1
      packages/admin-ui/src/lib/core/src/shared/pipes/has-permission.pipe.ts
  45. 15 5
      packages/admin-ui/src/lib/core/src/shared/pipes/locale-currency-name.pipe.ts
  46. 13 0
      packages/admin-ui/src/lib/core/src/shared/pipes/locale-currency.pipe.ts
  47. 7 0
      packages/admin-ui/src/lib/core/src/shared/pipes/locale-date.pipe.ts
  48. 9 1
      packages/admin-ui/src/lib/core/src/shared/pipes/locale-language-name.pipe.ts
  49. 8 0
      packages/admin-ui/src/lib/core/src/shared/pipes/time-ago.pipe.ts
  50. 5 1
      scripts/docs/generate-typescript-docs.ts

+ 2 - 0
.gitignore

@@ -18,8 +18,10 @@ docs/static/intro.js*
 docs/static/intro.css*
 docs/public
 docs/content/typescript-api/*
+docs/content/admin-ui-api/*
 docs/data/build.json
 !docs/content/typescript-api/_index.md
+!docs/content/admin-ui-api/_index.md
 docs/content/graphql-api/*
 !docs/content/graphql-api/_index.md
 !docs/content/graphql-api/shop/_index.md

+ 13 - 0
docs/content/admin-ui-api/_index.md

@@ -0,0 +1,13 @@
+---
+title: "Admin UI API"
+weight: 10
+showtoc: false
+---
+
+# Vendure Admin UI API Docs
+
+These APIs are used when building your own custom extensions to the Admin UI provided by the AdminUiPlugin.
+
+{{% alert %}}
+All documentation in this section is auto-generated from the TypeScript & HTML source of the Vendure Admin UI package.
+{{< /alert >}}

+ 39 - 0
packages/admin-ui/src/lib/core/src/common/base-detail.component.ts

@@ -11,6 +11,45 @@ import { CustomFieldConfig, CustomFields, LanguageCode } from './generated-types
 import { TranslationOf } from './utilities/find-translation';
 import { getDefaultUiLanguage } from './utilities/get-default-ui-language';
 
+/**
+ * @description
+ * A base class for entity detail views. It should be used in conjunction with the
+ * {@link BaseEntityResolver}.
+ *
+ * @example
+ * ```TypeScript
+ * \@Component({
+ *   selector: 'app-my-entity',
+ *   templateUrl: './my-entity.component.html',
+ *   styleUrls: ['./my-entity.component.scss'],
+ *   changeDetection: ChangeDetectionStrategy.OnPush,
+ * })
+ * export class GlobalSettingsComponent extends BaseDetailComponent<MyEntity.Fragment> implements OnInit {
+ *   detailForm: FormGroup;
+ *
+ *   constructor(
+ *     router: Router,
+ *     route: ActivatedRoute,
+ *     serverConfigService: ServerConfigService,
+ *     protected dataService: DataService,
+ *     private formBuilder: FormBuilder,
+ *   ) {
+ *     super(route, router, serverConfigService, dataService);
+ *     this.detailForm = this.formBuilder.group({
+ *       name: [''],
+ *     });
+ *   }
+ *
+ *   protected setFormValues(entity: MyEntity.Fragment, languageCode: LanguageCode): void {
+ *     this.detailForm.patchValue({
+ *       name: entity.name,
+ *     });
+ *   }
+ * }
+ * ```
+ *
+ * @docsCategory list-detail-views
+ */
 export abstract class BaseDetailComponent<Entity extends { id: string; updatedAt?: string }>
     implements DeactivateAware
 {

+ 28 - 1
packages/admin-ui/src/lib/core/src/common/base-entity-resolver.ts

@@ -24,8 +24,34 @@ export function createResolveData<T extends BaseEntityResolver<R>, R>(
 }
 
 /**
+ * @description
  * A base resolver for an entity detail route. Resolves to an observable of the given entity, or a "blank"
- * version if the route id equals "create".
+ * version if the route id equals "create". Should be used together with details views which extend the
+ * {@link BaseDetailComponent}.
+ *
+ * @example
+ * ```TypeScript
+ * \@Injectable({
+ *   providedIn: 'root',
+ * })
+ * export class MyEntityResolver extends BaseEntityResolver<MyEntity.Fragment> {
+ *   constructor(router: Router, dataService: DataService) {
+ *     super(
+ *       router,
+ *       {
+ *         __typename: 'MyEntity',
+ *         id: '',
+ *         createdAt: '',
+ *         updatedAt: '',
+ *         name: '',
+ *       },
+ *       id => dataService.query(GET_MY_ENTITY, { id }).mapStream(data => data.myEntity),
+ *     );
+ *   }
+ * }
+ * ```
+ *
+ * @docsCategory list-detail-views
  */
 export class BaseEntityResolver<T> implements Resolve<Observable<T>> {
     constructor(
@@ -34,6 +60,7 @@ export class BaseEntityResolver<T> implements Resolve<Observable<T>> {
         private entityStream: (id: string) => Observable<T | null | undefined>,
     ) {}
 
+    /** @internal */
     resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Observable<T>> {
         const id = route.paramMap.get('id');
 

+ 75 - 1
packages/admin-ui/src/lib/core/src/common/base-list.component.ts

@@ -10,8 +10,70 @@ export type MappingFn<T, R> = (result: R) => { items: T[]; totalItems: number };
 export type OnPageChangeFn<V> = (skip: number, take: number) => V;
 
 /**
+ * @description
  * This is a base class which implements the logic required to fetch and manipulate
  * a list of data from a query which returns a PaginatedList type.
+ *
+ * @example
+ * ```TypeScript
+ * \@Component({
+ *   selector: 'my-entity-list',
+ *   templateUrl: './my-entity-list.component.html',
+ *   styleUrls: ['./my-entity-list.component.scss'],
+ *   changeDetection: ChangeDetectionStrategy.OnPush,
+ * })
+ * export class MyEntityListComponent extends BaseListComponent<GetMyEntityList.Query, GetMyEntityList.Items> {
+ *   constructor(
+ *     private dataService: DataService,
+ *     router: Router,
+ *     route: ActivatedRoute,
+ *   ) {
+ *     super(router, route);
+ *     super.setQueryFn(
+ *       (...args: any[]) => this.dataService.query<GetMyEntityList.Query>(GET_MY_ENTITY_LIST),
+ *       data => data.myEntities,
+ *     );
+ *   }
+ * }
+ * ```
+ *
+ * The template for the component will typically use the {@link DataTableComponent} to display the results.
+ *
+ * @example
+ * ```HTML
+ * <vdr-action-bar>
+ *   <vdr-ab-right>
+ *     <a class="btn btn-primary" [routerLink]="['./create']" *vdrIfPermissions="['CreateSettings', 'CreateTaxRate']">
+ *       <clr-icon shape="plus"></clr-icon>
+ *       Create new my entity
+ *     </a>
+ *   </vdr-ab-right>
+ * </vdr-action-bar>
+ *
+ * <vdr-data-table
+ *   [items]="items$ | async"
+ *   [itemsPerPage]="itemsPerPage$ | async"
+ *   [totalItems]="totalItems$ | async"
+ *   [currentPage]="currentPage$ | async"
+ *   (pageChange)="setPageNumber($event)"
+ *   (itemsPerPageChange)="setItemsPerPage($event)"
+ * >
+ *   <vdr-dt-column>{{ 'common.name' | translate }}</vdr-dt-column>
+ *   <vdr-dt-column></vdr-dt-column>
+ *   <ng-template let-myEntity="item">
+ *     <td class="left align-middle">{{ myEntity.name }}</td>
+ *     <td class="right align-middle">
+ *       <vdr-table-row-action
+ *         iconShape="edit"
+ *         [label]="'common.edit' | translate"
+ *         [linkTo]="['./', myEntity.id]"
+ *       ></vdr-table-row-action>
+ *     </td>
+ *   </ng-template>
+ * </vdr-data-table>
+ * ```
+ *
+ * @docsCategory list-detail-views
  */
 @Directive()
 // tslint:disable-next-line:directive-class-suffix
@@ -33,6 +95,7 @@ export class BaseListComponent<ResultType, ItemType, VariableType = any> impleme
     constructor(protected router: Router, protected route: ActivatedRoute) {}
 
     /**
+     * @description
      * Sets the fetch function for the list being implemented.
      */
     setQueryFn(
@@ -51,6 +114,7 @@ export class BaseListComponent<ResultType, ItemType, VariableType = any> impleme
         }
     }
 
+    /** @internal */
     ngOnInit() {
         if (!this.listQueryFn) {
             throw new Error(
@@ -84,22 +148,32 @@ export class BaseListComponent<ResultType, ItemType, VariableType = any> impleme
             .subscribe(fetchPage);
     }
 
+    /** @internal */
     ngOnDestroy() {
         this.destroy$.next();
         this.destroy$.complete();
         this.listQuery.completed$.next();
     }
 
+    /**
+     * @description
+     * Sets the current page number in the url.
+     */
     setPageNumber(page: number) {
         this.setQueryParam('page', page, { replaceUrl: true });
     }
 
+    /**
+     * @description
+     * Sets the number of items per page in the url.
+     */
     setItemsPerPage(perPage: number) {
         this.setQueryParam('perPage', perPage, { replaceUrl: true });
     }
 
     /**
-     * Re-fetch the current page
+     * @description
+     * Re-fetch the current page of results.
      */
     refresh() {
         this.refresh$.next(undefined);

+ 31 - 0
packages/admin-ui/src/lib/core/src/common/component-registry-types.ts

@@ -1,9 +1,40 @@
 import { FormControl } from '@angular/forms';
 
+/**
+ * @description
+ * This interface should be implemented by any component being used as a custom input. For example,
+ * inputs for custom fields, or for configurable arguments.
+ *
+ * @docsCategory custom-input-components
+ */
 export interface FormInputComponent<C = InputComponentConfig> {
+    /**
+     * @description
+     * Should be set to `true` if this component is designed to handle lists.
+     * If `true` then the formControl value will be an array of all the
+     * values in the list.
+     */
     isListInput?: boolean;
+    /**
+     * @description
+     * This is set by the Admin UI when consuming this component, indicating that the
+     * component should be rendered in a read-only state.
+     */
     readonly: boolean;
+    /**
+     * @description
+     * This controls the actual value of the form item. The current value is available
+     * as `this.formControl.value`, and an Observable stream of value changes is available
+     * as `this.formControl.valueChanges`. To update the value, use `.setValue(val)` and then
+     * `.markAsDirty()`.
+     *
+     * Full documentation can be found in the [Angular docs](https://angular.io/api/forms/FormControl).
+     */
     formControl: FormControl;
+    /**
+     * @description
+     * The `config` property contains the full configuration object of the custom field or configurable argument.
+     */
     config: C;
 }
 

+ 54 - 12
packages/admin-ui/src/lib/core/src/data/providers/data.service.ts

@@ -18,20 +18,32 @@ import { PromotionDataService } from './promotion-data.service';
 import { SettingsDataService } from './settings-data.service';
 import { ShippingMethodDataService } from './shipping-method-data.service';
 
+/**
+ * @description
+ * Used to interact with the Admin API via GraphQL queries. Internally this service uses the
+ * Apollo Client, which means it maintains a normalized entity cache. For this reason, it is
+ * advisable to always select the `id` field of any entity, which will allow the returned data
+ * to be effectively cached.
+ *
+ * @docsCategory providers
+ * @docsPage DataService
+ * @docsWeight 0
+ */
 @Injectable()
 export class DataService {
-    promotion: PromotionDataService;
-    administrator: AdministratorDataService;
-    auth: AuthDataService;
-    collection: CollectionDataService;
-    product: ProductDataService;
-    client: ClientDataService;
-    facet: FacetDataService;
-    order: OrderDataService;
-    settings: SettingsDataService;
-    customer: CustomerDataService;
-    shippingMethod: ShippingMethodDataService;
+    /** @internal */ promotion: PromotionDataService;
+    /** @internal */ administrator: AdministratorDataService;
+    /** @internal */ auth: AuthDataService;
+    /** @internal */ collection: CollectionDataService;
+    /** @internal */ product: ProductDataService;
+    /** @internal */ client: ClientDataService;
+    /** @internal */ facet: FacetDataService;
+    /** @internal */ order: OrderDataService;
+    /** @internal */ settings: SettingsDataService;
+    /** @internal */ customer: CustomerDataService;
+    /** @internal */ shippingMethod: ShippingMethodDataService;
 
+    /** @internal */
     constructor(private baseDataService: BaseDataService) {
         this.promotion = new PromotionDataService(baseDataService);
         this.administrator = new AdministratorDataService(baseDataService);
@@ -47,7 +59,23 @@ export class DataService {
     }
 
     /**
-     * Perform a GraphQL query.
+     * @description
+     * Perform a GraphQL query. Returns a {@link QueryResult} which allows further control over
+     * they type of result returned, e.g. stream of values, single value etc.
+     *
+     * @example
+     * ```TypeScript
+     * const result$ = this.dataService.query(gql`
+     *   query MyQuery($id: ID!) {
+     *     product(id: $id) {
+     *       id
+     *       name
+     *       slug
+     *     }
+     *   },
+     *   { id: 123 },
+     * ).mapSingle(data => data.product);
+     * ```
      */
     query<T, V = Record<string, any>>(
         query: DocumentNode,
@@ -58,7 +86,21 @@ export class DataService {
     }
 
     /**
+     * @description
      * Perform a GraphQL mutation.
+     *
+     * @example
+     * ```TypeScript
+     * const result$ = this.dataService.mutate(gql`
+     *   mutation MyMutation($input: UpdateEntityInput!) {
+     *     updateEntity(input: $input) {
+     *       id
+     *       name
+     *     }
+     *   },
+     *   { input: updateEntityInput },
+     * );
+     * ```
      */
     mutate<T, V = Record<string, any>>(
         mutation: DocumentNode,

+ 14 - 4
packages/admin-ui/src/lib/core/src/data/query-result.ts

@@ -9,8 +9,12 @@ import { GetUserStatus } from '../common/generated-types';
 import { GET_USER_STATUS } from './definitions/client-definitions';
 
 /**
+ * @description
  * This class wraps the Apollo Angular QueryRef object and exposes some getters
  * for convenience.
+ *
+ * @docsCategory providers
+ * @docsPage DataService
  */
 export class QueryResult<T, V = Record<string, any>> {
     constructor(private queryRef: QueryRef<T, V>, private apollo: Apollo) {
@@ -21,11 +25,13 @@ export class QueryResult<T, V = Record<string, any>> {
     private valueChanges: Observable<ApolloQueryResult<T>>;
 
     /**
-     * Refetch this query whenever the active Channel changes.
+     * @description
+     * Re-fetch this query whenever the active Channel changes.
      */
-    refetchOnChannelChange() {
-        const userStatus$ = this.apollo.watchQuery<GetUserStatus.Query>({ query: GET_USER_STATUS })
-            .valueChanges;
+    refetchOnChannelChange(): QueryResult<T, V> {
+        const userStatus$ = this.apollo.watchQuery<GetUserStatus.Query>({
+            query: GET_USER_STATUS,
+        }).valueChanges;
         const activeChannelId$ = userStatus$.pipe(
             map(data => data.data.userStatus.activeChannelId),
             filter(notNullOrUndefined),
@@ -56,6 +62,7 @@ export class QueryResult<T, V = Record<string, any>> {
     }
 
     /**
+     * @description
      * Returns an Observable which emits a single result and then completes.
      */
     get single$(): Observable<T> {
@@ -71,6 +78,7 @@ export class QueryResult<T, V = Record<string, any>> {
     }
 
     /**
+     * @description
      * Returns an Observable which emits until unsubscribed.
      */
     get stream$(): Observable<T> {
@@ -89,6 +97,7 @@ export class QueryResult<T, V = Record<string, any>> {
     }
 
     /**
+     * @description
      * Returns a single-result Observable after applying the map function.
      */
     mapSingle<R>(mapFn: (item: T) => R): Observable<R> {
@@ -96,6 +105,7 @@ export class QueryResult<T, V = Record<string, any>> {
     }
 
     /**
+     * @description
      * Returns a multiple-result Observable after applying the map function.
      */
     mapStream<R>(mapFn: (item: T) => R): Observable<R> {

+ 43 - 14
packages/admin-ui/src/lib/core/src/providers/modal/modal.service.ts

@@ -8,11 +8,16 @@ import { SimpleDialogComponent } from '../../shared/components/simple-dialog/sim
 import { OverlayHostService } from '../overlay-host/overlay-host.service';
 
 /**
+ * @description
  * Any component intended to be used with the ModalService.fromComponent() method must implement
  * this interface.
+ *
+ * @docsCategory providers
+ * @docsPage ModalService
  */
 export interface Dialog<R = any> {
     /**
+     * @description
      * Function to be invoked in order to close the dialog when the action is complete.
      * The Observable returned from the .fromComponent() method will emit the value passed
      * to this method and then complete.
@@ -27,7 +32,11 @@ export interface DialogButtonConfig<T> {
 }
 
 /**
+ * @description
  * Configures a generic modal dialog.
+ *
+ * @docsCategory providers
+ * @docsPage ModalService
  */
 export interface DialogConfig<T> {
     title: string;
@@ -37,27 +46,44 @@ export interface DialogConfig<T> {
 }
 
 /**
+ * @description
  * Options to configure the behaviour of the modal.
+ *
+ * @docsCategory providers
+ * @docsPage ModalService
  */
 export interface ModalOptions<T> {
-    /** Sets the width of the dialog */
+    /**
+     * @description
+     * Sets the width of the dialog
+     */
     size?: 'sm' | 'md' | 'lg' | 'xl';
-    /** Sets the vertical alignment of the dialog */
+    /**
+     * @description
+     * Sets the vertical alignment of the dialog
+     */
     verticalAlign?: 'top' | 'center' | 'bottom';
     /**
+     * @description
      * When true, the "x" icon is shown
      * and clicking it or the mask will close the dialog
      */
     closable?: boolean;
     /**
-     * Values to be passed directly to the component.
+     * @description
+     * Values to be passed directly to the component being instantiated inside the dialog.
      */
     locals?: Partial<T>;
 }
 
 /**
+ * @description
  * This service is responsible for instantiating a ModalDialog component and
  * embedding the specified component within.
+ *
+ * @docsCategory providers
+ * @docsPage ModalService
+ * @docsWeight 0
  */
 @Injectable({
     providedIn: 'root',
@@ -69,12 +95,13 @@ export class ModalService {
     ) {}
 
     /**
+     * @description
      * Create a modal from a component. The component must implement the {@link Dialog} interface.
      * Additionally, the component should include templates for the title and the buttons to be
      * displayed in the modal dialog. See example:
      *
      * @example
-     * ```
+     * ```HTML
      * class MyDialog implements Dialog {
      *  resolveWith: (result?: any) => void;
      *
@@ -90,20 +117,21 @@ export class ModalService {
      * }
      * ```
      *
-     * ```
+     * @example
+     * ```HTML
      * <ng-template vdrDialogTitle>Title of the modal</ng-template>
      *
      * <p>
-     *     My Content
+     *   My Content
      * </p>
      *
      * <ng-template vdrDialogButtons>
-     *     <button type="button"
-     *             class="btn"
-     *             (click)="cancel()">Cancel</button>
-     *     <button type="button"
-     *             class="btn btn-primary"
-     *             (click)="okay()">Okay</button>
+     *   <button type="button"
+     *           class="btn"
+     *           (click)="cancel()">Cancel</button>
+     *   <button type="button"
+     *           class="btn btn-primary"
+     *           (click)="okay()">Okay</button>
      * </ng-template>
      * ```
      */
@@ -114,13 +142,13 @@ export class ModalService {
         const modalFactory = this.componentFactoryResolver.resolveComponentFactory(ModalDialogComponent);
 
         return from(this.overlayHostService.getHostView()).pipe(
-            mergeMap((hostView) => {
+            mergeMap(hostView => {
                 const modalComponentRef = hostView.createComponent(modalFactory);
                 const modalInstance: ModalDialogComponent<any> = modalComponentRef.instance;
                 modalInstance.childComponentType = component;
                 modalInstance.options = options;
 
-                return new Observable<R>((subscriber) => {
+                return new Observable<R>(subscriber => {
                     modalInstance.closeModal = (result: R) => {
                         modalComponentRef.destroy();
                         subscriber.next(result);
@@ -132,6 +160,7 @@ export class ModalService {
     }
 
     /**
+     * @description
      * Displays a modal dialog with the provided title, body and buttons.
      */
     dialog<T>(config: DialogConfig<T>): Observable<T | undefined> {

+ 5 - 1
packages/admin-ui/src/lib/core/src/providers/nav-builder/nav-builder.service.ts

@@ -38,6 +38,7 @@ import {
  * })
  * export class MyUiExtensionModule {}
  * ```
+ * @docsCategory navigation
  */
 export function addNavMenuSection(config: NavMenuSection, before?: string): Provider {
     return {
@@ -76,7 +77,9 @@ export function addNavMenuSection(config: NavMenuSection, before?: string): Prov
  *   ],
  * })
  * export class MyUiExtensionModule {}
- * ```
+ * ``
+ *
+ * @docsCategory navigation
  */
 export function addNavMenuItem(config: NavMenuItem, sectionId: string, before?: string): Provider {
     return {
@@ -112,6 +115,7 @@ export function addNavMenuItem(config: NavMenuItem, sectionId: string, before?:
  * })
  * export class MyUiExtensionModule {}
  * ```
+ * @docsCategory navigation
  */
 export function addActionBarItem(config: ActionBarItem): Provider {
     return {

+ 41 - 2
packages/admin-ui/src/lib/core/src/providers/notification/notification.service.ts

@@ -4,7 +4,22 @@ import { NotificationComponent } from '../../components/notification/notificatio
 import { I18nService } from '../i18n/i18n.service';
 import { OverlayHostService } from '../overlay-host/overlay-host.service';
 
+/**
+ * @description
+ * The types of notification available.
+ *
+ * @docsCategory providers
+ * @docsPage NotificationService
+ */
 export type NotificationType = 'info' | 'success' | 'error' | 'warning';
+
+/**
+ * @description
+ * Configuration for a toast notification.
+ *
+ * @docsCategory providers
+ * @docsPage NotificationService
+ */
 export interface ToastConfig {
     message: string;
     translationVars?: { [key: string]: string | number };
@@ -16,7 +31,25 @@ export interface ToastConfig {
 const TOAST_DURATION = 3000;
 
 /**
+ * @description
  * Provides toast notification functionality.
+ *
+ * @example
+ * ```TypeScript
+ * class MyComponent {
+ *   constructor(private notificationService: NotificationService) {}
+ *
+ *   save() {
+ *     this.notificationService
+ *         .success(_('asset.notify-create-assets-success'), {
+ *           count: successCount,
+ *         });
+ *   }
+ * }
+ *
+ * @docsCategory providers
+ * @docsPage NotificationService
+ * @docsWeight 0
  */
 @Injectable({
     providedIn: 'root',
@@ -25,6 +58,7 @@ export class NotificationService {
     private get hostView(): Promise<ViewContainerRef> {
         return this.overlayHostService.getHostView();
     }
+
     private openToastRefs: Array<{ ref: ComponentRef<NotificationComponent>; timerId: any }> = [];
 
     constructor(
@@ -34,6 +68,7 @@ export class NotificationService {
     ) {}
 
     /**
+     * @description
      * Display a success toast notification
      */
     success(message: string, translationVars?: { [key: string]: string | number }): void {
@@ -45,6 +80,7 @@ export class NotificationService {
     }
 
     /**
+     * @description
      * Display an info toast notification
      */
     info(message: string, translationVars?: { [key: string]: string | number }): void {
@@ -56,6 +92,7 @@ export class NotificationService {
     }
 
     /**
+     * @description
      * Display a warning toast notification
      */
     warning(message: string, translationVars?: { [key: string]: string | number }): void {
@@ -67,6 +104,7 @@ export class NotificationService {
     }
 
     /**
+     * @description
      * Display an error toast notification
      */
     error(message: string, translationVars?: { [key: string]: string | number }): void {
@@ -79,6 +117,7 @@ export class NotificationService {
     }
 
     /**
+     * @description
      * Display a toast notification.
      */
     notify(config: ToastConfig): void {
@@ -142,9 +181,9 @@ export class NotificationService {
         });
     }
 
-    private translateTranslationVars(translationVars: {
+    private translateTranslationVars(translationVars: { [key: string]: string | number }): {
         [key: string]: string | number;
-    }): { [key: string]: string | number } {
+    } {
         for (const [key, val] of Object.entries(translationVars)) {
             if (typeof val === 'string') {
                 translationVars[key] = this.i18nService.translate(val);

+ 18 - 0
packages/admin-ui/src/lib/core/src/shared/components/asset-picker-dialog/asset-picker-dialog.component.ts

@@ -27,7 +27,25 @@ import { AssetGalleryComponent } from '../asset-gallery/asset-gallery.component'
 import { AssetSearchInputComponent } from '../asset-search-input/asset-search-input.component';
 
 /**
+ * @description
  * A dialog which allows the creation and selection of assets.
+ *
+ * @example
+ * ```TypeScript
+ * selectAssets() {
+ *   this.modalService
+ *     .fromComponent(AssetPickerDialogComponent, {
+ *         size: 'xl',
+ *     })
+ *     .subscribe(result => {
+ *         if (result && result.length) {
+ *             // ...
+ *         }
+ *     });
+ * }
+ * ```
+ *
+ * @docsCategory components
  */
 @Component({
     selector: 'vdr-asset-picker-dialog',

+ 20 - 0
packages/admin-ui/src/lib/core/src/shared/components/chip/chip.component.ts

@@ -1,7 +1,17 @@
 import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
 
 /**
+ * @description
  * A chip component for displaying a label with an optional action icon.
+ *
+ * @example
+ * ```HTML
+ * <vdr-chip [colorFrom]="item.value"
+ *           icon="close"
+ *           (iconClick)="clear(item)">
+ * {{ item.value }}</vdr-chip>
+ * ```
+ * @docsCategory components
  */
 @Component({
     selector: 'vdr-chip',
@@ -10,13 +20,23 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from
     changeDetection: ChangeDetectionStrategy.OnPush,
 })
 export class ChipComponent {
+    /**
+     * @description
+     * The icon should be the name of one of the available Clarity icons: https://clarity.design/foundation/icons/shapes/
+     *
+     */
     @Input() icon: string;
     @Input() invert = false;
     /**
+     * @description
      * If set, the chip will have an auto-generated background
      * color based on the string value passed in.
      */
     @Input() colorFrom = '';
+    /**
+     * @description
+     * The color of the chip can also be one of the standard status colors.
+     */
     @Input() colorType: 'error' | 'success' | 'warning';
     @Output() iconClick = new EventEmitter<MouseEvent>();
 }

+ 11 - 0
packages/admin-ui/src/lib/core/src/shared/components/currency-input/currency-input.component.ts

@@ -16,8 +16,19 @@ import { map } from 'rxjs/operators';
 import { DataService } from '../../../data/providers/data.service';
 
 /**
+ * @description
  * A form input control which displays currency in decimal format, whilst working
  * with the integer cent value in the background.
+ *
+ * @example
+ * ```HTML
+ * <vdr-currency-input
+ *     [(ngModel)]="entityPrice"
+ *     [currencyCode]="currencyCode"
+ * ></vdr-currency-input>
+ * ```
+ *
+ * @docsCategory components
  */
 @Component({
     selector: 'vdr-currency-input',

+ 59 - 0
packages/admin-ui/src/lib/core/src/shared/components/data-table/data-table.component.ts

@@ -14,6 +14,65 @@ import { PaginationService } from 'ngx-pagination';
 
 import { DataTableColumnComponent } from './data-table-column.component';
 
+/**
+ * @description
+ * A table for displaying PaginatedList results. It is designed to be used inside components which
+ * extend the {@link BaseListComponent} class.
+ *
+ * @example
+ * ```HTML
+ * <vdr-data-table
+ *   [items]="items$ | async"
+ *   [itemsPerPage]="itemsPerPage$ | async"
+ *   [totalItems]="totalItems$ | async"
+ *   [currentPage]="currentPage$ | async"
+ *   (pageChange)="setPageNumber($event)"
+ *   (itemsPerPageChange)="setItemsPerPage($event)"
+ * >
+ *   <!-- The header columns are defined first -->
+ *   <vdr-dt-column>{{ 'common.name' | translate }}</vdr-dt-column>
+ *   <vdr-dt-column></vdr-dt-column>
+ *   <vdr-dt-column></vdr-dt-column>
+ *
+ *   <!-- Then we define how a row is rendered -->
+ *   <ng-template let-taxRate="item">
+ *     <td class="left align-middle">{{ taxRate.name }}</td>
+ *     <td class="left align-middle">{{ taxRate.category.name }}</td>
+ *     <td class="left align-middle">{{ taxRate.zone.name }}</td>
+ *     <td class="left align-middle">{{ taxRate.value }}%</td>
+ *     <td class="right align-middle">
+ *       <vdr-table-row-action
+ *         iconShape="edit"
+ *         [label]="'common.edit' | translate"
+ *         [linkTo]="['./', taxRate.id]"
+ *       ></vdr-table-row-action>
+ *     </td>
+ *     <td class="right align-middle">
+ *       <vdr-dropdown>
+ *         <button type="button" class="btn btn-link btn-sm" vdrDropdownTrigger>
+ *           {{ 'common.actions' | translate }}
+ *           <clr-icon shape="caret down"></clr-icon>
+ *         </button>
+ *         <vdr-dropdown-menu vdrPosition="bottom-right">
+ *           <button
+ *               type="button"
+ *               class="delete-button"
+ *               (click)="deleteTaxRate(taxRate)"
+ *               [disabled]="!(['DeleteSettings', 'DeleteTaxRate'] | hasPermission)"
+ *               vdrDropdownItem
+ *           >
+ *               <clr-icon shape="trash" class="is-danger"></clr-icon>
+ *               {{ 'common.delete' | translate }}
+ *           </button>
+ *         </vdr-dropdown-menu>
+ *       </vdr-dropdown>
+ *     </td>
+ *   </ng-template>
+ * </vdr-data-table>
+ * ```
+ *
+ * @docsCategory components
+ */
 @Component({
     selector: 'vdr-data-table',
     templateUrl: 'data-table.component.html',

+ 17 - 0
packages/admin-ui/src/lib/core/src/shared/components/datetime-picker/datetime-picker.component.ts

@@ -25,6 +25,17 @@ export type CurrentView = {
     year: number;
 };
 
+/**
+ * @description
+ * A form input for selecting datetime values.
+ *
+ * @example
+ * ```HTML
+ * <vdr-datetime-picker [(ngModel)]="startDate"></vdr-datetime-picker>
+ * ```
+ *
+ * @docsCategory components
+ */
 @Component({
     selector: 'vdr-datetime-picker',
     templateUrl: './datetime-picker.component.html',
@@ -41,28 +52,34 @@ export type CurrentView = {
 })
 export class DatetimePickerComponent implements ControlValueAccessor, AfterViewInit, OnInit, OnDestroy {
     /**
+     * @description
      * The range above and below the current year which is selectable from
      * the year select control. If a min or max value is set, these will
      * override the yearRange.
      */
     @Input() yearRange;
     /**
+     * @description
      * The day that the week should start with in the calendar view.
      */
     @Input() weekStartDay: DayOfWeek = 'mon';
     /**
+     * @description
      * The granularity of the minutes time picker
      */
     @Input() timeGranularityInterval = 5;
     /**
+     * @description
      * The minimum date as an ISO string
      */
     @Input() min: string | null = null;
     /**
+     * @description
      * The maximum date as an ISO string
      */
     @Input() max: string | null = null;
     /**
+     * @description
      * Sets the readonly state
      */
     @Input() readonly = false;

+ 25 - 0
packages/admin-ui/src/lib/core/src/shared/components/dropdown/dropdown.component.ts

@@ -1,5 +1,30 @@
 import { ChangeDetectionStrategy, Component, ElementRef, Input } from '@angular/core';
 
+/**
+ * @description
+ * Used for building dropdown menus.
+ *
+ * @example
+ * ```HTML
+ * <vdr-dropdown>
+ *   <button class="btn btn-outline" vdrDropdownTrigger>
+ *       <clr-icon shape="plus"></clr-icon>
+ *       Select type
+ *   </button>
+ *   <vdr-dropdown-menu vdrPosition="bottom-left">
+ *     <button
+ *       *ngFor="let typeName of allTypes"
+ *       type="button"
+ *       vdrDropdownItem
+ *       (click)="selectType(typeName)"
+ *     >
+ *       typeName
+ *     </button>
+ *   </vdr-dropdown-menu>
+ * </vdr-dropdown>
+ * ```
+ * @docsCategory components
+ */
 @Component({
     selector: 'vdr-dropdown',
     templateUrl: './dropdown.component.html',

+ 22 - 0
packages/admin-ui/src/lib/core/src/shared/components/facet-value-selector/facet-value-selector.component.ts

@@ -21,6 +21,28 @@ export type FacetValueSeletorItem = {
     value: FacetValue.Fragment;
 };
 
+/**
+ * @description
+ * A form control for selecting facet values.
+ *
+ * @example
+ * ```HTML
+ * <vdr-facet-value-selector
+ *   [facets]="facets"
+ *   (selectedValuesChange)="selectedValues = $event"
+ * ></vdr-facet-value-selector>
+ * ```
+ * The `facets` input should be provided from the parent component
+ * like this:
+ *
+ * @example
+ * ```TypeScript
+ * this.facets = this.dataService
+ *   .facet.getAllFacets()
+ *   .mapSingle(data => data.facets.items);
+ * ```
+ * @docsCategory components
+ */
 @Component({
     selector: 'vdr-facet-value-selector',
     templateUrl: './facet-value-selector.component.html',

+ 1 - 1
packages/admin-ui/src/lib/core/src/shared/components/modal-dialog/modal-dialog.component.ts

@@ -15,7 +15,7 @@ import { Dialog, ModalOptions } from '../../../providers/modal/modal.service';
 import { DialogButtonsDirective } from './dialog-buttons.directive';
 
 /**
- * This component should only be instatiated dynamically by the ModalService. It should not be used
+ * This component should only be instantiated dynamically by the ModalService. It should not be used
  * directly in templates. See {@link ModalService.fromComponent} method for more detail.
  */
 @Component({

+ 8 - 0
packages/admin-ui/src/lib/core/src/shared/components/object-tree/object-tree.component.ts

@@ -1,7 +1,15 @@
 import { ChangeDetectionStrategy, Component, Input, OnInit, Optional, SkipSelf } from '@angular/core';
 
 /**
+ * @description
  * This component displays a plain JavaScript object as an expandable tree.
+ *
+ * @example
+ * ```HTML
+ * <vdr-object-tree [value]="payment.metadata"></vdr-object-tree>
+ * ```
+ *
+ * @docsCategory components
  */
 @Component({
     selector: 'vdr-object-tree',

+ 10 - 0
packages/admin-ui/src/lib/core/src/shared/components/order-state-label/order-state-label.component.ts

@@ -1,5 +1,15 @@
 import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
 
+/**
+ * @description
+ * Displays the state of an order in a colored chip.
+ *
+ * @example
+ * ```HTML
+ * <vdr-order-state-label [state]="order.state"></vdr-order-state-label>
+ * ```
+ * @docsCategory components
+ */
 @Component({
     selector: 'vdr-order-state-label',
     templateUrl: './order-state-label.component.html',

+ 12 - 0
packages/admin-ui/src/lib/core/src/shared/components/product-selector/product-selector.component.ts

@@ -6,6 +6,18 @@ import { debounceTime, distinctUntilChanged, mapTo, switchMap, tap, throttleTime
 import { ProductSelectorSearch } from '../../../common/generated-types';
 import { DataService } from '../../../data/providers/data.service';
 
+/**
+ * @description
+ * A component for selecting product variants via an autocomplete-style select input.
+ *
+ * @example
+ * ```HTML
+ * <vdr-product-selector
+ *   (productSelected)="selectResult($event)"></vdr-product-selector>
+ * ```
+ *
+ * @docsCategory components
+ */
 @Component({
     selector: 'vdr-product-selector',
     templateUrl: './product-selector.component.html',

+ 12 - 1
packages/admin-ui/src/lib/core/src/shared/components/rich-text-editor/rich-text-editor.component.ts

@@ -14,7 +14,18 @@ import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
 import { ProsemirrorService } from './prosemirror/prosemirror.service';
 
 /**
- * A rich text (HTML) editor based on Trix (https://github.com/basecamp/trix)
+ * @description
+ * A rich text (HTML) editor based on Prosemirror (https://prosemirror.net/)
+ *
+ * @example
+ * ```HTML
+ * <vdr-rich-text-editor
+ *     [(ngModel)]="description"
+ *     label="Description"
+ * ></vdr-rich-text-editor>
+ * ```
+ *
+ * @docsCategory components
  */
 @Component({
     selector: 'vdr-rich-text-editor',

+ 14 - 0
packages/admin-ui/src/lib/core/src/shared/directives/if-multichannel.directive.ts

@@ -4,6 +4,20 @@ import { DataService } from '../../data/providers/data.service';
 
 import { IfDirectiveBase } from './if-directive-base';
 
+/**
+ * @description
+ * Structural directive that displays the given element if the Vendure instance has multiple channels
+ * configured.
+ *
+ * @example
+ * ```html
+ * <div *vdrIfMultichannel class="channel-selector">
+ *   <!-- ... -->
+ * </ng-container>
+ * ```
+ *
+ * @docsCategory directives
+ */
 @Directive({
     selector: '[vdrIfMultichannel]',
 })

+ 3 - 0
packages/admin-ui/src/lib/core/src/shared/directives/if-permissions.directive.ts

@@ -15,6 +15,7 @@ import { DataService } from '../../data/providers/data.service';
 import { IfDirectiveBase } from './if-directive-base';
 
 /**
+ * @description
  * Conditionally shows/hides templates based on the current active user having the specified permission.
  * Based on the ngIf source. Also support "else" templates:
  *
@@ -26,6 +27,8 @@ import { IfDirectiveBase } from './if-directive-base';
  *
  * The permission can be a single string, or an array. If an array is passed, then _all_ of the permissions
  * must match (logical AND)
+ *
+ * @docsCategory directives
  */
 @Directive({
     selector: '[vdrIfPermissions]',

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/boolean-form-input/boolean-form-input.component.ts

@@ -4,6 +4,13 @@ import { DefaultFormComponentConfig, DefaultFormComponentId } from '@vendure/com
 
 import { FormInputComponent, InputComponentConfig } from '../../../common/component-registry-types';
 
+/**
+ * @description
+ * A checkbox input. The default input component for `boolean` fields.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-boolean-form-input',
     templateUrl: './boolean-form-input.component.html',

+ 8 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/code-editor-form-input/json-editor-form-input.component.ts

@@ -29,6 +29,14 @@ export function jsonValidator(): ValidatorFn {
     };
 }
 
+/**
+ * @description
+ * A JSON editor input with syntax highlighting and error detection. Works well
+ * with `text` type fields.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-json-editor-form-input',
     templateUrl: './json-editor-form-input.component.html',

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/currency-form-input/currency-form-input.component.ts

@@ -7,6 +7,13 @@ import { FormInputComponent, InputComponentConfig } from '../../../common/compon
 import { CurrencyCode } from '../../../common/generated-types';
 import { DataService } from '../../../data/providers/data.service';
 
+/**
+ * @description
+ * An input for monetary values. Should be used with `int` type fields.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-currency-form-input',
     templateUrl: './currency-form-input.component.html',

+ 8 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/customer-group-form-input/customer-group-form-input.component.ts

@@ -8,6 +8,14 @@ import { FormInputComponent } from '../../../common/component-registry-types';
 import { GetCustomerGroups } from '../../../common/generated-types';
 import { DataService } from '../../../data/providers/data.service';
 
+/**
+ * @description
+ * Allows the selection of a Customer via an autocomplete select input.
+ * Should be used with `ID` type fields which represent Customer IDs.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-customer-group-form-input',
     templateUrl: './customer-group-form-input.component.html',

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/date-form-input/date-form-input.component.ts

@@ -4,6 +4,13 @@ import { DefaultFormComponentConfig, DefaultFormComponentId } from '@vendure/com
 
 import { FormInputComponent } from '../../../common/component-registry-types';
 
+/**
+ * @description
+ * Allows selection of a datetime. Default input for `datetime` type fields.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-date-form-input',
     templateUrl: './date-form-input.component.html',

+ 8 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/facet-value-form-input/facet-value-form-input.component.ts

@@ -8,6 +8,14 @@ import { FormInputComponent, InputComponentConfig } from '../../../common/compon
 import { FacetWithValues } from '../../../common/generated-types';
 import { DataService } from '../../../data/providers/data.service';
 
+/**
+ * @description
+ * Allows the selection of multiple FacetValues via an autocomplete select input.
+ * Should be used with `ID` type **list** fields which represent FacetValue IDs.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-facet-value-form-input',
     templateUrl: './facet-value-form-input.component.html',

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/number-form-input/number-form-input.component.ts

@@ -4,6 +4,13 @@ import { DefaultFormComponentConfig, DefaultFormComponentId } from '@vendure/com
 
 import { FormInputComponent } from '../../../common/component-registry-types';
 
+/**
+ * @description
+ * Displays a number input. Default input for `int` and `float` type fields.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-number-form-input',
     templateUrl: './number-form-input.component.html',

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/password-form-input/password-form-input.component.ts

@@ -4,6 +4,13 @@ import { DefaultFormComponentId } from '@vendure/common/lib/shared-types';
 
 import { FormInputComponent, InputComponentConfig } from '../../../common/component-registry-types';
 
+/**
+ * @description
+ * Displays a password text input. Should be used with `string` type fields.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-password-form-input',
     templateUrl: './password-form-input.component.html',

+ 8 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/product-selector-form-input/product-selector-form-input.component.ts

@@ -9,6 +9,14 @@ import { FormInputComponent, InputComponentConfig } from '../../../common/compon
 import { GetProductVariant, ProductSelectorSearch } from '../../../common/generated-types';
 import { DataService } from '../../../data/providers/data.service';
 
+/**
+ * @description
+ * Allows the selection of multiple ProductVariants via an autocomplete select input.
+ * Should be used with `ID` type **list** fields which represent ProductVariant IDs.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-product-selector-form-input',
     templateUrl: './product-selector-form-input.component.html',

+ 33 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/register-dynamic-input-components.ts

@@ -57,6 +57,35 @@ export const defaultFormInputs = [
  * })
  * export class MyUiExtensionModule {}
  * ```
+ *
+ * This input component can then be used in a custom field:
+ *
+ * @example
+ * ```TypeScript
+ * const config = {
+ *   // ...
+ *   customFields: {
+ *     ProductVariant: [
+ *       {
+ *         name: 'rrp',
+ *         type: 'int',
+ *         ui: { component: 'my-custom-input' },
+ *       },
+ *     ]
+ *   }
+ * }
+ * ```
+ *
+ * or with an argument of a {@link ConfigurableOperationDef}:
+ *
+ * @example
+ * ```TypeScript
+ * args: {
+ *   rrp: { type: 'int', ui: { component: 'my-custom-input' } },
+ * }
+ * ```
+ *
+ * @docsCategory custom-input-components
  */
 export function registerFormInputComponent(id: string, component: Type<FormInputComponent>): FactoryProvider {
     return {
@@ -71,6 +100,8 @@ export function registerFormInputComponent(id: string, component: Type<FormInput
 
 /**
  * @description
+ * **Deprecated** use `registerFormInputComponent()` in combination with the customField `ui` config instead.
+ *
  * Registers a custom component to act as the form input control for the given custom field.
  * This should be used in the NgModule `providers` array of your ui extension module.
  *
@@ -87,6 +118,8 @@ export function registerFormInputComponent(id: string, component: Type<FormInput
  * ```
  *
  * @deprecated use `registerFormInputComponent()` in combination with the customField `ui` config instead.
+ *
+ * @docsCategory custom-input-components
  */
 export function registerCustomFieldComponent(
     entity: CustomFieldEntityName,

+ 9 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/relation-form-input/relation-form-input.component.ts

@@ -5,6 +5,15 @@ import { DefaultFormComponentId } from '@vendure/common/lib/shared-types';
 import { FormInputComponent } from '../../../common/component-registry-types';
 import { RelationCustomFieldConfig } from '../../../common/generated-types';
 
+/**
+ * @description
+ * The default input component for `relation` type custom fields. Allows the selection
+ * of a ProductVariant, Product, Customer or Asset. For other entity types, a custom
+ * implementation will need to be defined. See {@link registerFormInputComponent}.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-relation-form-input',
     templateUrl: './relation-form-input.component.html',

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/rich-text-form-input/rich-text-form-input.component.ts

@@ -4,6 +4,13 @@ import { DefaultFormComponentConfig, DefaultFormComponentId } from '@vendure/com
 
 import { FormInputComponent, InputComponentConfig } from '../../../common/component-registry-types';
 
+/**
+ * @description
+ * Uses the {@link RichTextEditorComponent} as in input for `text` type fields.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-rich-text-form-input',
     templateUrl: './rich-text-form-input.component.html',

+ 8 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/select-form-input/select-form-input.component.ts

@@ -5,6 +5,14 @@ import { DefaultFormComponentConfig, DefaultFormComponentId } from '@vendure/com
 import { FormInputComponent, InputComponentConfig } from '../../../common/component-registry-types';
 import { CustomFieldConfigFragment } from '../../../common/generated-types';
 
+/**
+ * @description
+ * Uses a select input to allow the selection of a string value. Should be used with
+ * `string` type fields with options.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-select-form-input',
     templateUrl: './select-form-input.component.html',

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/text-form-input/text-form-input.component.ts

@@ -4,6 +4,13 @@ import { DefaultFormComponentId } from '@vendure/common/lib/shared-types';
 
 import { FormInputComponent, InputComponentConfig } from '../../../common/component-registry-types';
 
+/**
+ * @description
+ * Uses a regular text form input. This is the default input for `string` and `localeString` type fields.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-text-form-input',
     templateUrl: './text-form-input.component.html',

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/dynamic-form-inputs/textarea-form-input/textarea-form-input.component.ts

@@ -4,6 +4,13 @@ import { DefaultFormComponentConfig, DefaultFormComponentId } from '@vendure/com
 
 import { FormInputComponent, InputComponentConfig } from '../../../common/component-registry-types';
 
+/**
+ * @description
+ * Uses textarea form input. This is the default input for `text` type fields.
+ *
+ * @docsCategory custom-input-components
+ * @docsPage default-inputs
+ */
 @Component({
     selector: 'vdr-textarea-form-input',
     templateUrl: './textarea-form-input.component.html',

+ 14 - 0
packages/admin-ui/src/lib/core/src/shared/pipes/asset-preview.pipe.ts

@@ -2,6 +2,20 @@ import { Pipe, PipeTransform } from '@angular/core';
 
 import { AssetFragment } from '../../common/generated-types';
 
+/**
+ * @description
+ * Given an Asset object (an object with `preview` and optionally `focalPoint` properties), this pipe
+ * returns a string with query parameters designed to work with the image resize capabilities of the
+ * AssetServerPlugin.
+ *
+ * @example
+ * ```HTML
+ * <img [src]="asset | assetPreview:'tiny'" />
+ * <img [src]="asset | assetPreview:150" />
+ * ```
+ *
+ * @docsCategory pipes
+ */
 @Pipe({
     name: 'assetPreview',
 })

+ 8 - 0
packages/admin-ui/src/lib/core/src/shared/pipes/duration.pipe.ts

@@ -4,8 +4,16 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import { I18nService } from '../../providers/i18n/i18n.service';
 
 /**
+ * @description
  * Displays a number of milliseconds in a more human-readable format,
  * e.g. "12ms", "33s", "2:03m"
+ *
+ * @example
+ * ```TypeScript
+ * {{ timeInMs | duration }}
+ * ```
+ *
+ * @docsCategory pipes
  */
 @Pipe({
     name: 'duration',

+ 8 - 0
packages/admin-ui/src/lib/core/src/shared/pipes/file-size.pipe.ts

@@ -1,7 +1,15 @@
 import { Pipe, PipeTransform } from '@angular/core';
 
 /**
+ * @description
  * Formats a number into a human-readable file size string.
+ *
+ * @example
+ * ```TypeScript
+ * {{ fileSizeInBytes | filesize }}
+ * ```
+ *
+ * @docsCategory pipes
  */
 @Pipe({ name: 'filesize' })
 export class FileSizePipe implements PipeTransform {

+ 3 - 1
packages/admin-ui/src/lib/core/src/shared/pipes/has-permission.pipe.ts

@@ -4,13 +4,15 @@ import { Observable, Subscription } from 'rxjs';
 import { DataService } from '../../data/providers/data.service';
 
 /**
+ * @description
  * A pipe which checks the provided permission against all the permissions of the current user.
  * Returns `true` if the current user has that permission.
  *
  * @example
- * ```
+ * ```HTML
  * <button [disabled]="!('UpdateCatalog' | hasPermission)">Save Changes</button>
  * ```
+ * @docsCategory pipes
  */
 @Pipe({
     name: 'hasPermission',

+ 15 - 5
packages/admin-ui/src/lib/core/src/shared/pipes/locale-currency-name.pipe.ts

@@ -5,7 +5,15 @@ import { DataService } from '../../data/providers/data.service';
 import { LocaleBasePipe } from './locale-base.pipe';
 
 /**
+ * @description
  * Displays a human-readable name for a given ISO 4217 currency code.
+ *
+ * @example
+ * ```HTML
+ * {{ order.currencyCode | localeCurrencyName }}
+ * ```
+ *
+ * @docsCategory pipes
  */
 @Pipe({
     name: 'localeCurrencyName',
@@ -35,11 +43,13 @@ export class LocaleCurrencyNamePipe extends LocaleBasePipe implements PipeTransf
             }).of(value);
         }
         if (display === 'full' || display === 'symbol') {
-            const parts = (new Intl.NumberFormat(activeLocale, {
-                style: 'currency',
-                currency: value,
-                currencyDisplay: 'symbol',
-            }) as any).formatToParts();
+            const parts = (
+                new Intl.NumberFormat(activeLocale, {
+                    style: 'currency',
+                    currency: value,
+                    currencyDisplay: 'symbol',
+                }) as any
+            ).formatToParts();
 
             symbol = parts.find(p => p.type === 'currency')?.value || value;
         }

+ 13 - 0
packages/admin-ui/src/lib/core/src/shared/pipes/locale-currency.pipe.ts

@@ -4,6 +4,18 @@ import { DataService } from '../../data/providers/data.service';
 
 import { LocaleBasePipe } from './locale-base.pipe';
 
+/**
+ * @description
+ * Formats a Vendure monetary value (in cents) into the correct format for the configured currency and display
+ * locale.
+ *
+ * @example
+ * ```HTML
+ * {{ variant.priceWithTax | localeCurrency }}
+ * ```
+ *
+ * @docsCategory pipes
+ */
 @Pipe({
     name: 'localeCurrency',
     pure: false,
@@ -12,6 +24,7 @@ export class LocaleCurrencyPipe extends LocaleBasePipe implements PipeTransform
     constructor(@Optional() dataService?: DataService, @Optional() changeDetectorRef?: ChangeDetectorRef) {
         super(dataService, changeDetectorRef);
     }
+
     transform(value: unknown, ...args: unknown[]): string | unknown {
         const [currencyCode, locale] = args;
         if (typeof value === 'number' && typeof currencyCode === 'string') {

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/pipes/locale-date.pipe.ts

@@ -8,6 +8,13 @@ import { LocaleBasePipe } from './locale-base.pipe';
  * @description
  * A replacement of the Angular DatePipe which makes use of the Intl API
  * to format dates according to the selected UI language.
+ *
+ * @example
+ * ```HTML
+ * {{ order.orderPlacedAt | localeDate }}
+ * ```
+ *
+ * @docsCategory pipes
  */
 @Pipe({
     name: 'localeDate',

+ 9 - 1
packages/admin-ui/src/lib/core/src/shared/pipes/locale-language-name.pipe.ts

@@ -5,7 +5,15 @@ import { DataService } from '../../data/providers/data.service';
 import { LocaleBasePipe } from './locale-base.pipe';
 
 /**
- * Displays a human-readable name for a given ISO 4217 currency code.
+ * @description
+ * Displays a human-readable name for a given ISO 639-1 language code.
+ *
+ * @example
+ * ```HTML
+ * {{ 'zh_Hant' | localeLanguageName }}
+ * ```
+ *
+ * @docsCategory pipes
  */
 @Pipe({
     name: 'localeLanguageName',

+ 8 - 0
packages/admin-ui/src/lib/core/src/shared/pipes/time-ago.pipe.ts

@@ -5,7 +5,15 @@ import dayjs from 'dayjs';
 import { I18nService } from '../../providers/i18n/i18n.service';
 
 /**
+ * @description
  * Converts a date into the format "3 minutes ago", "5 hours ago" etc.
+ *
+ * @example
+ * ```HTML
+ * {{ order.orderPlacedAt | timeAgo }}
+ * ```
+ *
+ * @docsCategory pipes
  */
 @Pipe({
     name: 'timeAgo',

+ 5 - 1
scripts/docs/generate-typescript-docs.ts

@@ -25,11 +25,15 @@ const sections: DocsSectionConfig[] = [
             'packages/elasticsearch-plugin/src/',
             'packages/job-queue-plugin/src/',
             'packages/testing/src/',
-            'packages/ui-devkit/src/',
         ],
         exclude: [/generated-shop-types/],
         outputPath: 'typescript-api',
     },
+    {
+        sourceDirs: ['packages/admin-ui/src/lib/', 'packages/ui-devkit/src/'],
+        exclude: [/generated-types/],
+        outputPath: 'admin-ui-api',
+    },
 ];
 
 generateTypescriptDocs(sections);