treege 3.0.0-beta.87 → 3.0.0-beta.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -36
- package/dist/{editor-B3qu0VAn.js → editor-BPx-285N.js} +1 -1
- package/dist/editor.js +1 -1
- package/dist/main.js +3 -3
- package/dist/renderer/features/TreegeRenderer/useTreegeRenderer.d.ts +1 -1
- package/dist/renderer/features/TreegeRenderer/web/TreegeRenderer.d.ts +1 -1
- package/dist/renderer/hooks/useSubmitHandler.d.ts +3 -2
- package/dist/renderer/types/renderer.d.ts +24 -0
- package/dist/renderer/utils/extraPayload.d.ts +21 -0
- package/dist/renderer/utils/submit.d.ts +3 -2
- package/dist/{renderer-D2-LozgF.js → renderer-Bpgwbsub.js} +175 -174
- package/dist/renderer-native.js +167 -166
- package/dist/renderer.js +2 -2
- package/dist/{useRenderNode-DQ5lvXuj.js → useRenderNode-CgDdKXTw.js} +203 -192
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,6 +47,7 @@ Treege is a modern React library for creating and rendering interactive decision
|
|
|
47
47
|
- **Conditional Logic**: Dynamic field visibility based on user input and conditional edges
|
|
48
48
|
- **Multi-Step Forms**: Group nodes are automatically turned into navigable steps with Back/Continue controls, an `onBack` bridge to outer flows, and external-button submission via `formId`
|
|
49
49
|
- **Edit Mode**: Pre-fill with `initialValues` (accepts name keys, reactive) to round-trip and edit previously submitted records
|
|
50
|
+
- **Host Data Injection**: Attach app-owned fields (e.g. a user id) to every submission with `extraPayload` — merged into both the `onSubmit` payload and the HTTP submit body
|
|
50
51
|
- **Loading State**: Built-in `isLoading` prop renders a customizable skeleton while the flow is being fetched, plus `isSubmitting` to drive the button's loading state from async submits
|
|
51
52
|
- **Fully Customizable**: Override any component (form, inputs, inputLabel, ui, step, submitButton, submitButtonWrapper, loadingSkeleton)
|
|
52
53
|
- **Optional Dependencies**: Graceful degradation when optional packages like `react-native-document-picker` aren't installed
|
|
@@ -457,24 +458,25 @@ You can implement these inputs using popular React Native libraries:
|
|
|
457
458
|
|
|
458
459
|
The React Native renderer shares the same API as the web renderer, with some platform-specific props:
|
|
459
460
|
|
|
460
|
-
| Prop | Type
|
|
461
|
-
|
|
462
|
-
| `flow` | `Flow \| null`
|
|
463
|
-
| `onSubmit` | `(values: FormValues, meta?: Meta) => void`
|
|
464
|
-
| `
|
|
465
|
-
| `
|
|
466
|
-
| `
|
|
467
|
-
| `
|
|
468
|
-
| `
|
|
469
|
-
| `
|
|
470
|
-
| `
|
|
471
|
-
| `
|
|
472
|
-
| `
|
|
473
|
-
| `
|
|
474
|
-
| `
|
|
475
|
-
| `
|
|
476
|
-
| `
|
|
477
|
-
| `
|
|
461
|
+
| Prop | Type | Default | Description |
|
|
462
|
+
|-------------------------|-------------------------------------------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
463
|
+
| `flow` | `Flow \| null` | - | Decision tree to render |
|
|
464
|
+
| `onSubmit` | `(values: FormValues, meta?: Meta) => void` | - | Form submission handler (meta includes HTTP response data) |
|
|
465
|
+
| `extraPayload` | `Record<string, unknown> \| (values) => Record` | - | Host-owned fields merged into every submission — the `onSubmit` payload **and** the HTTP submit body. Object or function of the current values (see below) |
|
|
466
|
+
| `onChange` | `(values: FormValues) => void` | - | Form change handler |
|
|
467
|
+
| `validate` | `(values, nodes) => Record<string, string>` | - | Custom validation function |
|
|
468
|
+
| `initialValues` | `FormValues` | `{}` | Pre-fill values to edit a record. Accepts `node.id` or name keys; reactive (re-seeds if it changes after mount) |
|
|
469
|
+
| `components` | `TreegeRendererComponents` | - | Custom component overrides |
|
|
470
|
+
| `language` | `string` | `"en"` | UI language |
|
|
471
|
+
| `validationMode` | `"onSubmit" \| "onChange"` | `"onSubmit"` | When to validate |
|
|
472
|
+
| `theme` | `"light" \| "dark"` | `"dark"` | Renderer theme |
|
|
473
|
+
| `googleApiKey` | `string` | - | API key for address input |
|
|
474
|
+
| `headers` | `HttpHeaders` | - | HTTP headers as `{ name: value }`, applied to every request (field-level wins) |
|
|
475
|
+
| `isLoading` | `boolean` | `false` | Render a loading skeleton instead of the form |
|
|
476
|
+
| `isSubmitting` | `boolean` | `false` | Force the submit/continue button into its loading state (OR-ed with internal state) |
|
|
477
|
+
| `onBack` | `() => void` | - | Called when Back is clicked on the first step; bridges to an outer flow |
|
|
478
|
+
| `style` | `ViewStyle` | - | ScrollView style (RN only) |
|
|
479
|
+
| `contentContainerStyle` | `ViewStyle` | - | Content container style (RN) |
|
|
478
480
|
|
|
479
481
|
## Node Types
|
|
480
482
|
|
|
@@ -776,6 +778,28 @@ The stored value is a single `SerializableFile` (or an array when the field is `
|
|
|
776
778
|
/>
|
|
777
779
|
```
|
|
778
780
|
|
|
781
|
+
### Injecting Host Data (`extraPayload`)
|
|
782
|
+
|
|
783
|
+
Use `extraPayload` to attach data owned by the host app — not by the form itself — to every submission (e.g. the logged-in user id, a tenant id). The fields are merged at the **top level** of both the `onSubmit` payload and the built-in HTTP submit body, so they ride along wherever the form data goes:
|
|
784
|
+
|
|
785
|
+
```tsx
|
|
786
|
+
<TreegeRenderer flow={flow} extraPayload={{ userId }} onSubmit={handleSubmit} />
|
|
787
|
+
// onSubmit receives → { ...formValues, userId }
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
Pass a **function** when the value must be read at submit time rather than captured at render — a rotating auth token, a timestamp, or a value derived from the current answers (it receives the same name-keyed values you get in `onSubmit`):
|
|
791
|
+
|
|
792
|
+
```tsx
|
|
793
|
+
<TreegeRenderer flow={flow} extraPayload={() => ({ token: auth.getToken() })} />
|
|
794
|
+
<TreegeRenderer flow={flow} extraPayload={(values) => ({ fullName: `${values.firstName} ${values.lastName}` })} />
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
Notes:
|
|
798
|
+
|
|
799
|
+
- The extra fields are spread **last**, so a key here intentionally overrides a same-named form field.
|
|
800
|
+
- It also applies to the built-in HTTP submit (`submitConfig`): the fields are merged into the request body, respecting any `payloadTemplate` shape. If the config would otherwise send no body, the extra is sent on its own — your data is never silently dropped.
|
|
801
|
+
- A function that returns a non-object (array / primitive) is ignored.
|
|
802
|
+
|
|
779
803
|
### Submitting State
|
|
780
804
|
|
|
781
805
|
Pass `isSubmitting` to keep the submit/continue button in its loading state (spinner + disabled) while an async `onSubmit` resolves on your side. It's OR-ed with the renderer's own internal submitting state (e.g. during an HTTP `submitConfig` call):
|
|
@@ -919,24 +943,25 @@ Once the development server is running, you can access these examples:
|
|
|
919
943
|
|
|
920
944
|
### TreegeRenderer Props
|
|
921
945
|
|
|
922
|
-
| Prop | Type
|
|
923
|
-
|
|
924
|
-
| `flow` | `Flow \| null`
|
|
925
|
-
| `onSubmit` | `(values: FormValues, meta?: Meta) => void`
|
|
926
|
-
| `
|
|
927
|
-
| `
|
|
928
|
-
| `
|
|
929
|
-
| `
|
|
930
|
-
| `
|
|
931
|
-
| `
|
|
932
|
-
| `
|
|
933
|
-
| `
|
|
934
|
-
| `
|
|
935
|
-
| `
|
|
936
|
-
| `
|
|
937
|
-
| `
|
|
938
|
-
| `
|
|
939
|
-
| `
|
|
946
|
+
| Prop | Type | Default | Description |
|
|
947
|
+
|------------------|-------------------------------------------------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
948
|
+
| `flow` | `Flow \| null` | - | Decision tree to render |
|
|
949
|
+
| `onSubmit` | `(values: FormValues, meta?: Meta) => void` | - | Form submission handler (meta includes HTTP response data) |
|
|
950
|
+
| `extraPayload` | `Record<string, unknown> \| (values) => Record` | - | Host-owned fields merged into every submission — the `onSubmit` payload **and** the HTTP submit body. Object or function of the current values (see below) |
|
|
951
|
+
| `onChange` | `(values: FormValues) => void` | - | Form change handler |
|
|
952
|
+
| `validate` | `(values, nodes) => Record<string, string>` | - | Custom validation function |
|
|
953
|
+
| `initialValues` | `FormValues` | `{}` | Pre-fill values to edit a submitted record. Accepts `node.id` **or** name keys (same shape as `onSubmit`); reactive — re-seeds if it changes after mount (see below) |
|
|
954
|
+
| `components` | `TreegeRendererComponents` | - | Custom component overrides |
|
|
955
|
+
| `language` | `string` | `"en"` | UI language |
|
|
956
|
+
| `validationMode` | `"onSubmit" \| "onChange"` | `"onSubmit"` | When to validate |
|
|
957
|
+
| `theme` | `"light" \| "dark"` | `"dark"` | Renderer theme |
|
|
958
|
+
| `googleApiKey` | `string` | - | API key for address input |
|
|
959
|
+
| `headers` | `HttpHeaders` | - | HTTP headers as `{ name: value }`, applied to every request (field-level wins) |
|
|
960
|
+
| `isLoading` | `boolean` | `false` | Render a loading skeleton instead of the form (see below) |
|
|
961
|
+
| `isSubmitting` | `boolean` | `false` | Force the submit/continue button into its loading state (spinner + disabled). OR-ed with the internal submitting state — useful with an async `onSubmit` |
|
|
962
|
+
| `onBack` | `() => void` | - | Called when Back is clicked on the **first step**; bridges back-navigation to an outer flow (e.g. a parent modal). Shows a Back button on step 0 when provided |
|
|
963
|
+
| `formId` | `string` | - | Sets the `<form>` `id` so a submit button outside the renderer can target it via the native `form` attribute. Web only; submits only on the last step in multi-step flows |
|
|
964
|
+
| `className` | `string` | - | Additional CSS class names for custom styling |
|
|
940
965
|
|
|
941
966
|
## Development
|
|
942
967
|
|
|
@@ -3739,7 +3739,7 @@ var ca = ({ aiConfig: e, onGenerate: t }) => {
|
|
|
3739
3739
|
/* @__PURE__ */ K(fr, {}),
|
|
3740
3740
|
/* @__PURE__ */ q(dr, {
|
|
3741
3741
|
className: "tg:font-normal tg:text-muted-foreground tg:text-xs",
|
|
3742
|
-
children: ["v", "3.0.0-beta.
|
|
3742
|
+
children: ["v", "3.0.0-beta.88"]
|
|
3743
3743
|
})
|
|
3744
3744
|
]
|
|
3745
3745
|
})]
|
package/dist/editor.js
CHANGED
package/dist/main.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { t as e } from "./editor-
|
|
1
|
+
import { t as e } from "./editor-BPx-285N.js";
|
|
2
2
|
import { G as t, I as n, J as r, K as i, L as a, U as o, W as s, Y as c, _ as l, a as u, b as d, c as f, g as p, h as m, i as h, l as g, m as _, n as v, o as y, q as b, r as x, s as S, t as C, v as w, y as T } from "./ThemeContext-BnPOFQC7.js";
|
|
3
3
|
import { C as E, L as D, S as O, _ as k, a as A, b as j, c as M, d as N, g as P, h as F, i as I, m as L, n as R, o as z, r as B, u as V, v as H, x as U, y as W } from "./DefaultSubmitButton-DpeL3OxC.js";
|
|
4
|
-
import { a as G, c as K, i as q, l as J, n as Y, o as X, r as Z, s as Q } from "./useRenderNode-
|
|
5
|
-
import { a as $, c as ee, i as te, l as ne, n as re, o as ie, r as ae, s as oe, t as se } from "./renderer-
|
|
4
|
+
import { a as G, c as K, i as q, l as J, n as Y, o as X, r as Z, s as Q } from "./useRenderNode-CgDdKXTw.js";
|
|
5
|
+
import { a as $, c as ee, i as te, l as ne, n as re, o as ie, r as ae, s as oe, t as se } from "./renderer-Bpgwbsub.js";
|
|
6
6
|
export { E as DefaultAddressInput, O as DefaultAutocompleteInput, U as DefaultCheckboxInput, j as DefaultDateInput, W as DefaultDateRangeInput, H as DefaultFileInput, k as DefaultHiddenInput, P as DefaultHttpInput, D as DefaultInputLabel, F as DefaultNumberInput, L as DefaultPasswordInput, N as DefaultRadioInput, V as DefaultSelectInput, M as DefaultSwitchInput, z as DefaultTextAreaInput, A as DefaultTextInput, I as DefaultTimeInput, B as DefaultTimeRangeInput, ie as Divider, C as ThemeProvider, oe as Title, e as TreegeEditor, $ as TreegeRenderer, K as TreegeRendererProvider, se as TreegeViewer, ne as TreegeViewerProvider, x as applyReferenceTransformation, h as buildInitialFormValues, u as calculateReferenceFieldUpdates, y as checkFormFieldHasValue, S as convertFormValuesToNamedFormat, R as defaultInputRenderers, ee as defaultUI, X as evaluateCondition, Q as evaluateConditions, _ as fileNameFromUrl, m as fileToSerializable, p as filesToSerializable, Z as findStartNode, l as formatFileSize, q as getFlowRenderState, o as getStaticTranslations, s as getTranslatableValue, t as getTranslatedText, re as getViewerFields, f as isFieldEmpty, b as isGroupNode, ae as isImageFile, r as isInputNode, w as isRemoteFileData, G as isStartNode, c as isUINode, T as normalizeSerializableFiles, g as resolveNodeDefaultValue, n as sanitize, a as sanitizeHttpResponse, d as serializableToFile, i as setTranslatableValue, v as useTheme, Y as useTreegeRenderer, J as useTreegeRendererConfig, te as viewerFieldsFromResponse };
|
|
@@ -19,7 +19,7 @@ import { GroupNodeData, TreegeNodeData } from '../../../shared/types/node';
|
|
|
19
19
|
* @param props - Configuration props (flow, initialValues, callbacks, etc.)
|
|
20
20
|
* @returns Complete form state and control methods
|
|
21
21
|
*/
|
|
22
|
-
export declare const useTreegeRenderer: ({ baseUrl, components, flow, googleApiKey, headers, language, onChange, onSubmit, showPoweredBy, theme, validate, validationMode, initialValues, }: Pick<TreegeRendererProps, "baseUrl" | "components" | "flow" | "googleApiKey" | "headers" | "initialValues" | "language" | "onChange" | "onSubmit" | "showPoweredBy" | "theme" | "validate" | "validationMode">) => {
|
|
22
|
+
export declare const useTreegeRenderer: ({ baseUrl, components, extraPayload, flow, googleApiKey, headers, language, onChange, onSubmit, showPoweredBy, theme, validate, validationMode, initialValues, }: Pick<TreegeRendererProps, "baseUrl" | "components" | "extraPayload" | "flow" | "googleApiKey" | "headers" | "initialValues" | "language" | "onChange" | "onSubmit" | "showPoweredBy" | "theme" | "validate" | "validationMode">) => {
|
|
23
23
|
canContinueStep: boolean;
|
|
24
24
|
canSubmit: boolean;
|
|
25
25
|
clearSubmitMessage: () => void;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { TreegeRendererProps } from '../../../types/renderer';
|
|
2
|
-
declare const TreegeRenderer: ({ baseUrl, components, className, flow, formId, googleApiKey, headers, language, onBack, onChange, onSubmit, showPoweredBy, theme, validate, validationMode, initialValues, isLoading, isSubmitting: isSubmittingProp, }: TreegeRendererProps) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
declare const TreegeRenderer: ({ baseUrl, components, className, extraPayload, flow, formId, googleApiKey, headers, language, onBack, onChange, onSubmit, showPoweredBy, theme, validate, validationMode, initialValues, isLoading, isSubmitting: isSubmittingProp, }: TreegeRendererProps) => import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
export default TreegeRenderer;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Node } from '@xyflow/react';
|
|
2
|
-
import { FormValues } from '../types/renderer';
|
|
2
|
+
import { ExtraPayload, FormValues } from '../types/renderer';
|
|
3
3
|
import { SubmitResult } from '../utils/submit';
|
|
4
4
|
import { HttpHeaders, InputNodeData, TreegeNodeData } from '../../shared/types/node';
|
|
5
5
|
/**
|
|
@@ -18,9 +18,10 @@ import { HttpHeaders, InputNodeData, TreegeNodeData } from '../../shared/types/n
|
|
|
18
18
|
* @param inputNodes - All input nodes for form data conversion
|
|
19
19
|
* @param headers
|
|
20
20
|
* @param baseUrl - Base URL prepended to a relative submit url
|
|
21
|
+
* @param extraPayload - Consumer-injected fields merged into the submit body
|
|
21
22
|
* @returns Submit handler state and functions
|
|
22
23
|
*/
|
|
23
|
-
export declare const useSubmitHandler: (visibleNodes: Node<TreegeNodeData>[], formValues: FormValues, language: string, inputNodes: Node<InputNodeData>[], headers?: HttpHeaders, baseUrl?: string) => {
|
|
24
|
+
export declare const useSubmitHandler: (visibleNodes: Node<TreegeNodeData>[], formValues: FormValues, language: string, inputNodes: Node<InputNodeData>[], headers?: HttpHeaders, baseUrl?: string, extraPayload?: ExtraPayload) => {
|
|
24
25
|
clearSubmitMessage: () => void;
|
|
25
26
|
handleSubmitWithConfig: (onSuccess?: (data: unknown) => void) => Promise<SubmitResult | null>;
|
|
26
27
|
hasSubmitConfig: boolean;
|
|
@@ -33,6 +33,18 @@ export type FormValues = Record<string, any>;
|
|
|
33
33
|
export type Meta = {
|
|
34
34
|
httpResponse?: unknown;
|
|
35
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Extra data injected by the consuming app into every submission, merged at the
|
|
38
|
+
* top level of the payload — both the object passed to `onSubmit` and the body
|
|
39
|
+
* of the built-in HTTP submit request. Use it for fields that live in the host
|
|
40
|
+
* app rather than the form itself (e.g. the logged-in `userId`, a tenant id).
|
|
41
|
+
*
|
|
42
|
+
* Either a static object or a function of the current (name-keyed) form values,
|
|
43
|
+
* evaluated at submit time so the extra data can be derived from the answers or
|
|
44
|
+
* read fresh (e.g. a rotating auth token). The extra keys are spread last, so
|
|
45
|
+
* they intentionally override a same-named form field.
|
|
46
|
+
*/
|
|
47
|
+
export type ExtraPayload = Record<string, unknown> | ((values: FormValues) => Record<string, unknown>);
|
|
36
48
|
/**
|
|
37
49
|
* Union of all possible input value types
|
|
38
50
|
*/
|
|
@@ -400,6 +412,18 @@ export interface TreegeRendererProps extends TreegeRendererConfig {
|
|
|
400
412
|
* Additional class name for the renderer container
|
|
401
413
|
*/
|
|
402
414
|
className?: string;
|
|
415
|
+
/**
|
|
416
|
+
* Extra data injected into every submission, merged at the top level of both
|
|
417
|
+
* the `onSubmit` payload and the built-in HTTP submit body. Use it for values
|
|
418
|
+
* owned by the host app rather than the form (e.g. the logged-in `userId`).
|
|
419
|
+
* See {@link ExtraPayload}.
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* <TreegeRenderer flow={tree} extraPayload={{ userId }} />
|
|
423
|
+
* @example
|
|
424
|
+
* <TreegeRenderer flow={tree} extraPayload={() => ({ token: getToken() })} />
|
|
425
|
+
*/
|
|
426
|
+
extraPayload?: ExtraPayload;
|
|
403
427
|
/**
|
|
404
428
|
* Flow to render. `null` / `undefined` renders nothing.
|
|
405
429
|
*/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ExtraPayload, FormValues } from '../types/renderer';
|
|
2
|
+
/**
|
|
3
|
+
* Merge the consumer-provided `extraPayload` onto a base submission payload.
|
|
4
|
+
* This is the single chokepoint behind the `extraPayload` prop, used both for
|
|
5
|
+
* the `onSubmit` callback payload and the built-in HTTP submit body.
|
|
6
|
+
*
|
|
7
|
+
* `extraPayload` may be a static object or a function of the current
|
|
8
|
+
* (name-keyed) values — the function form lets the extra data be read at submit
|
|
9
|
+
* time (e.g. a freshly-read auth token). The extra fields are spread **last**,
|
|
10
|
+
* so a consumer-injected key (e.g. `userId`) intentionally wins over a
|
|
11
|
+
* same-named form field.
|
|
12
|
+
*
|
|
13
|
+
* Edge cases:
|
|
14
|
+
* - No `extraPayload`, or it resolves to a non-object (array / primitive) →
|
|
15
|
+
* the base is returned untouched (nothing to merge).
|
|
16
|
+
* - Base is `undefined`/`null` (e.g. a submit config that would otherwise send
|
|
17
|
+
* no body) → the extra is sent on its own, so the injected data still goes out.
|
|
18
|
+
* - Base is a non-object → returned untouched, since there is no top level to
|
|
19
|
+
* merge into.
|
|
20
|
+
*/
|
|
21
|
+
export declare const mergeExtraPayload: <T>(base: T, extraPayload: ExtraPayload | undefined, values: FormValues) => T | Record<string, unknown>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Node } from '@xyflow/react';
|
|
2
|
-
import { FormValues } from '../types/renderer';
|
|
2
|
+
import { ExtraPayload, FormValues } from '../types/renderer';
|
|
3
3
|
import { HttpHeaders, InputNodeData, SubmitConfig } from '../../shared/types/node';
|
|
4
4
|
/**
|
|
5
5
|
* Result of a form submission
|
|
@@ -36,9 +36,10 @@ export interface SubmitResult {
|
|
|
36
36
|
* @param inputNodes - All input nodes (required when sendAllFormValues is true)
|
|
37
37
|
* @param headers
|
|
38
38
|
* @param baseUrl - Base URL prepended to a relative submit url
|
|
39
|
+
* @param extraPayload - Consumer-injected fields merged into the request body
|
|
39
40
|
* @returns Promise with submission result
|
|
40
41
|
*/
|
|
41
|
-
export declare const submitFormData: (config: SubmitConfig, formValues: FormValues, inputNodes: Node<InputNodeData>[], headers?: HttpHeaders, baseUrl?: string) => Promise<SubmitResult>;
|
|
42
|
+
export declare const submitFormData: (config: SubmitConfig, formValues: FormValues, inputNodes: Node<InputNodeData>[], headers?: HttpHeaders, baseUrl?: string, extraPayload?: ExtraPayload) => Promise<SubmitResult>;
|
|
42
43
|
/**
|
|
43
44
|
* Perform redirect to the specified URL
|
|
44
45
|
*
|