Skip to content

Commit

Permalink
Merge pull request #114 from xenit-eu/ACC-1677
Browse files Browse the repository at this point in the history
[ACC-1677] Add ability to specify remote options for HAL-FORMS properties
  • Loading branch information
vierbergenlars authored Oct 18, 2024
2 parents 74d32e6 + 2001f4f commit 693d6e1
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 13 deletions.
56 changes: 43 additions & 13 deletions packages/hal-forms/src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { HalFormsProperty, HalFormsPropertyInlineOptions, HalFormsPropertyOption
import { MATCH_ANYTHING, MATCH_NOTHING } from "./_internal";
import { TypedRequestSpec } from "@contentgrid/typed-fetch";
import { HalFormsPropertyType, HalFormsPropertyValue } from "./_shape";
import { SimpleLink } from "@contentgrid/hal";

export class HalFormsTemplateBuilder<Body, Response> implements HalFormsTemplate<TypedRequestSpec<Body, Response>> {

Expand Down Expand Up @@ -119,7 +120,7 @@ export class HalFormsPropertyBuilder implements HalFormsProperty {
return this.withOptions(opts => opts.withInline(options));
}
if(typeof options === "function") {
return new HalFormsPropertyBuilder(this.name, this.type, this.readOnly, this.required, options(this._options ?? new HalFormsPropertyInlineOptionsImpl([])), this.regex, this.minLength, this.maxLength, this.prompt, this.value);
return new HalFormsPropertyBuilder(this.name, this.type, this.readOnly, this.required, options(this._options ?? new HalFormsPropertyOptionsImpl()), this.regex, this.minLength, this.maxLength, this.prompt, this.value);
}
throw new Error("Unknown type of options");
}
Expand Down Expand Up @@ -153,63 +154,92 @@ export class HalFormsPropertyBuilder implements HalFormsProperty {
export interface HalFormsPropertyOptionsBuilder {
withInline(inline: readonly HalFormsPropertyOption[]): HalFormsPropertyOptionsBuilder;
addInlineOption(option: HalFormsPropertyOption): HalFormsPropertyOptionsBuilder;
withRemote(link: SimpleLink): HalFormsPropertyOptionsBuilder;
withMaxItems(maxItems: number): HalFormsPropertyOptionsBuilder;
withMinItems(minItems: number): HalFormsPropertyOptionsBuilder;
build(): HalFormsPropertyInlineOptions | HalFormsPropertyRemoteOptions;
}

class HalFormsPropertyInlineOptionsImpl implements HalFormsPropertyInlineOptions<HalFormsPropertyOption>, HalFormsPropertyOptionsBuilder {
type Writeable<T> = {
-readonly [P in keyof T]?: T[P];
}

class HalFormsPropertyOptionsImpl implements HalFormsPropertyInlineOptions<HalFormsPropertyOption>, HalFormsPropertyRemoteOptions<HalFormsPropertyOption>, HalFormsPropertyOptionsBuilder {


public constructor(
public readonly inline: readonly HalFormsPropertyOption[],
public readonly inline: readonly HalFormsPropertyOption[] = undefined!,
public readonly link: SimpleLink = undefined!,
public readonly maxItems: number = Infinity,
public readonly minItems: number = 0,
) {

// This is to ensure that the 'inline' or 'link' properties are really not available when they are unset,
// without having to create two separate classes for them
if(!link) {
delete (this as Writeable<this>).link;
}
if(!inline) {
delete (this as Writeable<this>).inline
}
}

public withInline(inline: readonly HalFormsPropertyOption[]): HalFormsPropertyOptionsBuilder {
return new HalFormsPropertyInlineOptionsImpl(inline, this.maxItems, this.minItems);
return new HalFormsPropertyOptionsImpl(inline, undefined!, this.maxItems, this.minItems);
}

public addInlineOption(option: HalFormsPropertyOption): HalFormsPropertyOptionsBuilder {
return this.withInline(this.inline.concat([option]));
return this.withInline((this.inline ?? []).concat([option]));
}

public withRemote(link: SimpleLink): HalFormsPropertyOptionsBuilder {
return new HalFormsPropertyOptionsImpl(undefined!, link, this.maxItems, this.minItems);
}

public withMaxItems(maxItems: number): HalFormsPropertyOptionsBuilder {
return new HalFormsPropertyInlineOptionsImpl(this.inline, maxItems, this.minItems);
return new HalFormsPropertyOptionsImpl(this.inline, this.link, maxItems, this.minItems);
}

public withMinItems(minItems: number): HalFormsPropertyOptionsBuilder {
return new HalFormsPropertyInlineOptionsImpl(this.inline, this.maxItems, minItems);
return new HalFormsPropertyOptionsImpl(this.inline, this.link, this.maxItems, minItems);
}

public build(): HalFormsPropertyInlineOptions<unknown> | HalFormsPropertyRemoteOptions<unknown> {
return this;
}

public get selectedValues(): readonly string[] {
return[]
return [];
}

public toOption(data: HalFormsPropertyOption): HalFormsPropertyOption {
return data;
}

public loadOptions(): Promise<readonly HalFormsPropertyOption[]> {
return Promise.resolve(this.inline);
public async loadOptions(): Promise<readonly HalFormsPropertyOption[]>;
public async loadOptions(fetcher: (link: SimpleLink) => Promise<readonly HalFormsPropertyOption[]>): Promise<readonly HalFormsPropertyOption[]>;
public async loadOptions(fetcher?: (link: SimpleLink) => Promise<readonly HalFormsPropertyOption[]>): Promise<readonly HalFormsPropertyOption[]> {
if (this.isRemote() && fetcher) {
return await fetcher(this.link);
}

if (this.isInline()) {
return this.inline;
}

throw new Error("Options are not inline or remote");
}

public isInline(): this is HalFormsPropertyInlineOptions<HalFormsPropertyOption> {
return true;
return this.inline !== undefined;
}

public isRemote(): this is HalFormsPropertyRemoteOptions<HalFormsPropertyOption> {
return false;
return this.link !== undefined;
}

}


export default function buildTemplate<B, R>(method: string, url: string): HalFormsTemplateBuilder<B, R> {
return HalFormsTemplateBuilder.from<B, R>({ method, url })
}
15 changes: 15 additions & 0 deletions packages/hal/src/Link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ export class SimpleLink {

}

public static to(href: string): SimpleLink {
return new SimpleLink({ href });
}

public static templated(template: UriTemplate): SimpleLink {
return new SimpleLink({
href: template.template,
templated: true
})
}

// @internal
#warnDeprecation() {
if(this.deprecation && !this.#deprecationWarned) {
Expand Down Expand Up @@ -50,6 +61,10 @@ export class SimpleLink {
return this.data.deprecation;
}

public withRel(rel: LinkRelation): Link {
return new Link(rel, this.data);
}

public toString() {
return `<${this.href}>; ${toLinkParams({
name: this.name,
Expand Down

0 comments on commit 693d6e1

Please sign in to comment.