@ equinor/ 组合- 框架- 模块- 文本
融合框架的背景模块。 管理基于Fusion的应用程序和门户网站中的活性上下文(项目,设施,合同等),提供查询,验证,解析,以及从框出父子同步.
何时使用
当您的应用程序或门户需要时使用此模块:
- 设置、 读取或清除活性上下文( 如选择工程)
- 搜索和过滤 Fusion 上下文 API 中可用的上下文项目
- 验证某一上下文项目是否匹配允许的上下文类型
- 跨越父子提供方边界的解析上下文(门户网站 )
- 通过从 URL 路径取出上下文ID来进行深链接
应用程序开发者 通常使用高级
@equinor/fusion-framework-react-app/context包件, 包到底 模块带有反应钩和提供者.门户开发者 将使用
@equinor/fusion-framework-react/context在门户一级也是为了同样的目的.
如何融为一体
一个上下文模块从不孤立地生活。 这取决于
@equinor/fusion-framework-module-services 用于默认 HTTP 客户端的模块,可选
用途 @equinor/fusion-framework-module-event 发送和聆听背景变化事件,
并选择通过 @equinor/fusion-framework-module-navigation 改为
从路径中解决上下文。 这些不需要人工设置—— enableContext 需求
仅限 services· ; event 财务报告和审定财务报表 navigation 当您到场时会自动拾取.
模块也是 默认的层次意识: 当一个门户网站和一个App同时启用时 上下文, App 实例自动连接到 Portal 上下文 —— 除了两侧启用模块外,不需要接线。 见 生命周期 确切的说,同步是如何工作的 当它可以被推翻或致残.
文档
| 专题 | 说明 |
|---|---|
| 数据模型 | 形状 ContextItem,上下文类型如何相互联系,以及查询/相关参数 |
| 生命周期 | setCurrentContext校验/解析决定流程、启动时自动初始文本解析以及父/子背景传播 |
| 食谱 | OData 查询参数、 路径重写、 接受上下文类型家族以及自定义搜索错误 |
关键概念
| 概念 | 说明 |
|---|---|
| 背景项目 | 代表单个上下文实体(项目,设施等)的打出的记录. |
| 提供背景 | 运行时服务曝光查询,设置,验证,解析,以及事件API. |
| 背景模块配置器 | 流利地用于配置上下文类型,过滤器,客户端和钩子. |
| 启用内容 | 在模块配置器上注册模块的助手. |
| 背景决议 | 当上下文类型不符合所配置的类型时,自动查找相关上下文项目. |
| 父连接 | 双向同步介于父端门户上下文和子端应用上下文之间. |
快开始
import { enableContext } from '@equinor/fusion-framework-module-context';
export const configure = (configurator) => {
enableContext(configurator, (builder) => {
// only accept ProjectMaster context items
builder.setContextType(['ProjectMaster']);
});
};
初始化后, 从模块实例中访问提供者 :
// observe context changes
modules.context.currentContext$.subscribe((ctx) => {
console.log('context changed', ctx);
});
// search for context items
const items = await modules.context.queryContextAsync('Johan');
// set context by item
await modules.context.setCurrentContextAsync(items[0]);
// set context by ID
await modules.context.setCurrentContextByIdAsync('7fd97952-...');
// clear the active context
modules.context.clearCurrentContext();
操作遥测
IContextProvider 扩展 TelemetryConnectable。供应商使用
telemetry.scope('context')回到了懒惰的工厂 以古老的习俗
提供商,并关闭处置的共享手柄;
选择/分辨率观察仍保留在上下文模块中.
当主机注册遥测时, 每个队列 setCurrentContext 任务报告1
fusion.context.select.duration 结果。 每一份决议尝试报告
fusion.context.resolve.duration,无论来自选择,一个直接
resolveContext编号 :resolveContextAsync 调用或配置的解析器( n)by: 'item'),或
从后面的搜索 setCurrentContextById (单位:千美元)by: 'id':
failure有理无据validation验证失败而解析被禁;cancelled有理无据listener当onSetContextResolve, (中文(简体) ),onSetContextResolved或者说onCurrentContextChange听众的电话preventDefault()· ;cancelled当更新的任务取代任务时,调用者不订阅,或者 处理供应商(理由disposed) (中文(简体) ).
未验证的重设当前项目被跳过, 并且没有报告 .
背景标识,标题和值从不导出,背景行为不变.
同步解析器工厂故障记录并同步重投, 不包含
更改错误对象。 最终 onCurrentContextChange 否决权记录的取消
即刻,包括现有的去除-误差路径;遥测不改变
这条路的呼叫者行为.
见 操作遥测。 。 。 .
配置
所有配置流经 enableContext → ContextModuleConfigurator数字 :
enableContext(configurator, (builder) => {
// restrict accepted context types
builder.setContextType(['ProjectMaster', 'Facility']);
// post-query filter
builder.setContextFilter((items) => items.filter((i) => i.isActive));
// custom parameter mapping for the search API
builder.setContextParameterFn(({ search, type }) => ({
search,
filter: { type },
}));
// custom validation logic
builder.setValidateContext(function (item) {
return item !== null && this.validateContext(item);
});
// custom context resolution
builder.setResolveContext(function (item) {
return this.relatedContexts({ item, filter: { type: ['ProjectMaster'] } });
});
// connect (or disconnect) from parent context
// when enabled (default), onParentContextChanged fires before mirroring the parent's context locally
builder.connectParentContext(false);
// path ↔ context integration
// the default resolver uses extractContextIdFromPath to pull a GUID from the URL,
// then fetches the matching context item — see resolveInitialContext in utils
builder.setContextPathExtractor((path) => path.split('/')[2]);
builder.setContextPathGenerator((ctx, path) =>
path.replace(/\/context\/[^/]+/, `/context/${ctx.id}`),
);
// provide a fully custom context client
builder.setContextClient({
get: (args) => fetch(`/api/context/${args.id}`).then((r) => r.json()),
query: (args) => fetch(`/api/context?q=${args.search}`).then((r) => r.json()),
});
});
配置参考
| 构建方法 | 目的 |
|---|---|
setContextType(types) | 用于验证的上下文类型ID |
setContextFilter(fn) | 冲洗后结果过滤器 |
setContextParameterFn(fn) | 地图搜索 + 类型到 API 查询参数 |
setValidateContext(fn) | 自定义验证( O)this = 供应商) |
setResolveContext(fn) | 自定义分辨率( O)this = 供应商) |
connectParentContext(bool) | 启用/ 残疾父上下文同步( 火) onParentContextChanged 页:1 |
setContextPathExtractor(fn) | 从 URL 路径提取上下文 ID |
setContextPathGenerator(fn) | 从上下文项目生成 URL 路径 |
setResolveInitialContext(fn) | 覆盖初始上下文解析度( 默认使用) extractContextIdFromPath → resolveContextFromPath(中文(简体) ) |
setContextClient(client) | 自定义获取/取用/相关客户端 |
URL 中的背景运行
门户网站将活动上下文自动与浏览器 URL同步
通过 @equinor/fusion-framework-plugin-context-navigation 插件 。 作为应用
开发者,您控制 怎么样 上下文通过声明路径在您的 URL 中出现
在您的应用程序列表中的策略 .
宣布路线战略
设定 contextRouting 在你的清单 build.options数字 :
// app.manifest.config.ts
{
"build": {
"options": {
"contextRouting": "query"
}
}
}
| 数值 | URL 形状 | 何时使用 |
|---|---|---|
'path' (或省略) | /apps/{appKey}/{contextId}/sub-route | 默认——没有复杂路径路径的简单应用程序 |
'query' | /apps/{appKey}/route?$contextId={id} | 与上下文路径段相冲突的嵌入路线的应用程序 |
有自定义 URL 形状的应用程序可以省略 contextRouting 并登记自定义钩(见下文).
明确 contextRouting: 'query' 总是选择查询路由,即使注册了自定义钩.
[注] 何时
contextRouting未设定( 或设定为null),门户默认为 路径适配器 将上下文编码为应用程序键后的一个路径段. 如果您的应用程序也注册自定义钩( I)setContextPathExtractor编号 :setContextPathGenerator),自定义适配器优先于路径 用于路径路由或在没有宣布策略时的适配器。 明确contextRouting: 'query'选择查询适配器.
自定义URL形状
如果您的应用程序对上下文使用非标准的 URL 版式( 如. /route-a/{contextId}, (中文(简体) ),
注册自定义钩子而不是(或除此之外)声明 contextRouting数字 :
enableContext(configurator, (builder) => {
builder.setContextType(['ProjectMaster']);
// Tell the portal how to find the context id in your URL
builder.setContextPathExtractor((path) => {
const segments = path.split('/').filter(Boolean);
return segments[1]; // e.g. /route-a/{contextId}
});
// Tell the portal how to build a URL with context
builder.setContextPathGenerator((context, path) => {
const segments = path.split('/').filter(Boolean);
const route = segments[0] ?? '';
return `/${route}/${context.id}`;
});
});
这些钩子注册后,门户的自定义适配器会自动使用它们——
没有 contextRouting 名单中需要声明.
如何运作(供参考)
门户的上下文导航插件读取 contextRouting 从你的应用软件
在运行时显示并选择适当的 URL 适配器。 你不安装
或自行配置插件——门户处理。 您的应用程序只需要
宣布其倾向.
活动
上下文模块通过 @equinor/fusion-framework-module-event 系统。 所有事件都属于 ContextProvider 来源.
| 活动 | 何时 | 可取消 |
|---|---|---|
onCurrentContextChange | 在更新当前上下文之前 | 对 |
onCurrentContextChanged | 在当前环境发生变化后 | 没有 |
onParentContextChanged | 在本地镜像父上下文更改之前 | 对 |
onSetContextResolve | 在上下文解析开始前 | 对 |
onSetContextResolved | 上下文解析完成后 | 对 |
onSetContextValidationFailed | 当验证失败( 没有解析) | 没有 |
onSetContextResolveFailed | 解析失败时出错 | 没有 |
modules.event.addEventListener('onCurrentContextChanged', (e) => {
console.log('previous:', e.detail.previous);
console.log('next:', e.detail.next);
});
错误
模块导出 FusionContextSearchError (从) @equinor/fusion-framework-module-context/errors.js与搜索有关的失败:
import { FusionContextSearchError } from '@equinor/fusion-framework-module-context/errors.js';
try {
await modules.context.queryContextAsync('...');
} catch (err) {
if (err instanceof FusionContextSearchError) {
console.error(err.title, err.description);
}
}
测试
@equinor/fusion-framework-module-context/mock 提供 enableContextMock,一个目的所建的测试双人由一串种子上下文项的内存支撑——没有上下文 API,没有HTTP模拟,不需要服务发现模拟. 真实 ContextProvider 行为validateContext, (中文(简体) ), resolveContext,父文本传播)仍然运行在种子数据上;只有数据源被替换.
默认
- 上下文池开始为空, 没有选择当前上下文 .
- 查询空池不返回项目 .
- 查找一个未种子的ID会抛出一个错误,将ID和种子方法命名.
- 关联的context lookup使用种子池,排除源项,并按所请求的类型过滤.
setCurrentContext既种子项目,又选择初始应用分辨率;setContexts只有种子项目.
import { enableContextMock } from '@equinor/fusion-framework-module-context/mock';
enableContextMock(configurator, (mock) => {
mock.setCurrentContext({ id: 'my-ctx', type: { id: 'ProjectMaster' }, value: {} });
});
- 友好层 —— 说
setCurrentContext, (中文(简体) ),setContexts, (中文(简体) ),addContext, (中文(简体) ),setRelatedContexts——常见案例的上下文域词汇:种子一个已知项目,取回. - 逃逸舱门 —— 说
setResolver– 自定义的原始解析函数resolveContext策略或形状 友好层没有覆盖.
使用时 @equinor/fusion-framework/mock, (中文(简体) ), FrameworkMockConfigurator.context 返回相同的配置符,所以种子直接通过 configurator.context 不需要回电.
这是在测试中伪造上下文数据的两种方法之一. 另一个是直接嘲笑上下文 API的 HTTP 响应(与 configurator.http.addMiddleware(...)可选配对 @equinor/fusion-framework-module-http/mock是因为 createOpenApiMockMiddleware 用于直接从上下文的 OpenAPI spec 中获取的假冒数据 ) —— 用于练习真实 ContextModuleConfigurator/服务/HTTP管道,而不是取而代之. 到达 enableContextMock (d) 当试验需要覆盖管道本身时,HTTP中间器件的伸展范围。 用于实际种子数据的固定发电机(createContextItemFactory, (中文(简体) ), createContextItems可从下列网址获取: @equinor/fusion-framework-module-context/mock/fixtures。 。 。 .
生成决定性上下文定着
可选 /mock/fixtures 进入点用途 @faker-js/faker 产生现实但
可重复标题和可读标识。 仅在导入此切入点时安装 Faker .
import { enableContextMock } from '@equinor/fusion-framework-module-context/mock';
import { createContextItems } from '@equinor/fusion-framework-module-context/mock/fixtures';
const [project, contract] = createContextItems([
{ type: 'ProjectMaster' },
{ type: 'Contract', parentTypeIds: ['ProjectMaster'] },
]);
enableContextMock(configurator, (mock) => {
mock.setContexts([project, contract]);
mock.setCurrentContext(project);
});
使用 createContextItemFactory(prefix?) 用于一种类型的相继固定装置。 使用
createContextItems 用于多个类型和父/子类型元数据。 生成值为
确定/ id; 使用 setRelatedContexts 当每个特定项目的关系必须不同时.
公用事业
可向下列机构提供其他帮助: @equinor/fusion-framework-module-context/utils数字 :
| 导出 | 目的 |
|---|---|
enableContext | 在配置器上注册上下文模块 |
resolveInitialContext | 默认初始文本解析器( path ) – 父倒置) |
extractContextIdFromPath | 从 URL 路径中提取一个 GUID 格式上下文 ID |
resolveContextFromPath | 从 URL 路径获取上下文项的解析器函数 |
软件包出口
| 指定者 | 说明 |
|---|---|
@equinor/fusion-framework-module-context | 主要条目——模块,提供者,配置器,类型 |
@equinor/fusion-framework-module-context/errors.js | FusionContextSearchError |
@equinor/fusion-framework-module-context/utils | 路径解析和启用的功能 |
@equinor/fusion-framework-module-context/mock | enableContextMock, (中文(简体) ), ContextMockConfigurator - 模拟测试双倍 |
@equinor/fusion-framework-module-context/mock/fixtures | 生产上下文种子的固定工厂 |