@codenotch/codenotch.react 2.0.6 → 2.0.8

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/dist/env.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ import type { ICodenotchEnv } from "./models/Codenotch";
2
+ /**
3
+ * The Codenotch runtime environment, populated by `init()`.
4
+ * Prefer reading it through `useCodenotch().env`.
5
+ *
6
+ * Lives in its own module so that both the API (`index.ts`) and the ORM
7
+ * wrapper (`models/Codenotch.ts`) can read it without a circular import.
8
+ */
9
+ export declare const env: ICodenotchEnv;
10
+ export declare const MISSING_CLUSTER_URL_ERROR = "Codenotch cluster URL is not defined. Please set it in the Codenotch configuration.";
11
+ export declare const MISSING_SERVICE_NAME_ERROR = "Codenotch service name is not defined. Please set it in the Codenotch configuration.";
12
+ export declare const MISSING_TENANT_NAME_ERROR = "Codenotch tenant name is not defined. Please set it in the Codenotch configuration.";
13
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD;;;;;;GAMG;AACH,eAAO,MAAM,GAAG,EAAE,aAAkB,CAAC;AAErC,eAAO,MAAM,yBAAyB,wFAAwF,CAAC;AAC/H,eAAO,MAAM,0BAA0B,yFAAyF,CAAC;AACjI,eAAO,MAAM,yBAAyB,wFAAwF,CAAC"}
package/dist/env.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MISSING_TENANT_NAME_ERROR = exports.MISSING_SERVICE_NAME_ERROR = exports.MISSING_CLUSTER_URL_ERROR = exports.env = void 0;
4
+ /**
5
+ * The Codenotch runtime environment, populated by `init()`.
6
+ * Prefer reading it through `useCodenotch().env`.
7
+ *
8
+ * Lives in its own module so that both the API (`index.ts`) and the ORM
9
+ * wrapper (`models/Codenotch.ts`) can read it without a circular import.
10
+ */
11
+ exports.env = {};
12
+ exports.MISSING_CLUSTER_URL_ERROR = "Codenotch cluster URL is not defined. Please set it in the Codenotch configuration.";
13
+ exports.MISSING_SERVICE_NAME_ERROR = "Codenotch service name is not defined. Please set it in the Codenotch configuration.";
14
+ exports.MISSING_TENANT_NAME_ERROR = "Codenotch tenant name is not defined. Please set it in the Codenotch configuration.";
package/dist/index.d.ts CHANGED
@@ -1,12 +1,8 @@
1
1
  import { type ComponentType, type ComponentProps, type FunctionComponent, type RefAttributes } from "react";
2
2
  import { IDisposable } from "./models/Misc";
3
- import { ClientTables, ICodenotchApi, ICodenotchEnv, WithCodenotchProps } from "./models/Codenotch";
3
+ import { ClientTables, ICodenotchApi, WithCodenotchProps } from "./models/Codenotch";
4
+ import { env } from "./env";
4
5
  import CodeEditor from "./components/CodeEditor";
5
- /**
6
- * The Codenotch runtime environment, populated by {@link init}.
7
- * Prefer reading it through `useCodenotch().env`.
8
- */
9
- declare const env: ICodenotchEnv;
10
6
  /**
11
7
  * Initialize the Codenotch environment from the given key-value pairs.
12
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAkB,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAG1K,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAwB,YAAY,EAAE,aAAa,EAAoB,aAAa,EAA2B,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAErK,OAAO,UAAU,MAAM,yBAAyB,CAAC;AAEjD;;;GAGG;AACH,QAAA,MAAM,GAAG,EAAE,aAAkB,CAAC;AA6B9B;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,iBAAS,IAAI,CAAC,YAAY,EAAE,GAAG,GAAG,IAAI,CAkErC;AAySD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iBAAS,YAAY,IAAI,aAAa,CAErC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,iBAAS,YAAY,IAAI,aAAa,CAAC;AACvC,iBAAS,YAAY,CAAC,CAAC,SAAS,YAAY,EAAE,SAAS,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;AAY9E;;;;;;;;;;;;;;GAcG;AACH,iBAAS,iBAAiB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,WAAW,CAG5D;AAED,wFAAwF;AACxF,KAAK,qBAAqB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,kBAAkB,CAAC,CAAC;AAElE,8FAA8F;AAC9F,KAAK,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAElF;;;;;;;;;;GAUG;AACH,iBAAS,aAAa,CAAC,CAAC,SAAS,aAAa,CAAC,GAAG,CAAC,EAC/C,SAAS,EAAE,CAAC,GACb,iBAAiB,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAQnG;AAED,OAAO,EACH,GAAG,EACH,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,IAAI,EACJ,UAAU,EACb,CAAC;AAEF,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,KAAK,iBAAiB,EAAkB,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAG1K,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAwB,YAAY,EAAE,aAAa,EAA6C,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACtJ,OAAO,EAAE,GAAG,EAAoF,MAAM,OAAO,CAAC;AAE9G,OAAO,UAAU,MAAM,yBAAyB,CAAC;AA0BjD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,iBAAS,IAAI,CAAC,YAAY,EAAE,GAAG,GAAG,IAAI,CAkErC;AAySD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iBAAS,YAAY,IAAI,aAAa,CAErC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,iBAAS,YAAY,IAAI,aAAa,CAAC;AACvC,iBAAS,YAAY,CAAC,CAAC,SAAS,YAAY,EAAE,SAAS,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;AAY9E;;;;;;;;;;;;;;GAcG;AACH,iBAAS,iBAAiB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,WAAW,CAG5D;AAED,wFAAwF;AACxF,KAAK,qBAAqB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,MAAM,kBAAkB,CAAC,CAAC;AAElE,8FAA8F;AAC9F,KAAK,iBAAiB,CAAC,CAAC,IAAI,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAElF;;;;;;;;;;GAUG;AACH,iBAAS,aAAa,CAAC,CAAC,SAAS,aAAa,CAAC,GAAG,CAAC,EAC/C,SAAS,EAAE,CAAC,GACb,iBAAiB,CAAC,qBAAqB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAQnG;AAED,OAAO,EACH,GAAG,EACH,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,iBAAiB,EACjB,IAAI,EACJ,UAAU,EACb,CAAC;AAEF,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -26,18 +26,11 @@ exports.init = init;
26
26
  const react_1 = require("react");
27
27
  const react_dom_1 = require("react-dom");
28
28
  const client_1 = require("react-dom/client");
29
+ const env_1 = require("./env");
30
+ Object.defineProperty(exports, "env", { enumerable: true, get: function () { return env_1.env; } });
29
31
  const uuid_1 = require("uuid");
30
32
  const CodeEditor_1 = __importDefault(require("./components/CodeEditor"));
31
33
  exports.CodeEditor = CodeEditor_1.default;
32
- /**
33
- * The Codenotch runtime environment, populated by {@link init}.
34
- * Prefer reading it through `useCodenotch().env`.
35
- */
36
- const env = {};
37
- exports.env = env;
38
- const MISSING_CLUSTER_URL_ERROR = "Codenotch cluster URL is not defined. Please set it in the Codenotch configuration.";
39
- const MISSING_SERVICE_NAME_ERROR = "Codenotch service name is not defined. Please set it in the Codenotch configuration.";
40
- const MISSING_TENANT_NAME_ERROR = "Codenotch tenant name is not defined. Please set it in the Codenotch configuration.";
41
34
  // ---------------------------------------------------------------------------
42
35
  // Change tracking. `env` is a plain mutable object; every mutation done through
43
36
  // the public API (init, setTheme, setLanguage) goes through notify(), which
@@ -102,17 +95,17 @@ function init(envVariables) {
102
95
  return;
103
96
  }
104
97
  else {
105
- env[key] = envVariables[key];
98
+ env_1.env[key] = envVariables[key];
106
99
  if (['appManifest', 'projectManifest'].includes(key)) {
107
100
  // Must be Json
108
101
  try {
109
- env[key] = JSON.parse(envVariables[key]);
102
+ env_1.env[key] = JSON.parse(envVariables[key]);
110
103
  }
111
104
  catch (error) {
112
105
  console.warn(`Codenotch environment variable ${key} is not a valid JSON string. Using raw value.`);
113
106
  }
114
107
  }
115
- console.log(`Codenotch environment variable ${key} set to ${env[key]}`);
108
+ console.log(`Codenotch environment variable ${key} set to ${env_1.env[key]}`);
116
109
  }
117
110
  }
118
111
  catch (error) {
@@ -126,21 +119,21 @@ function init(envVariables) {
126
119
  if (urlParams["_theme"]) {
127
120
  let theme = urlParams["_theme"].toLowerCase();
128
121
  if (theme === "light" || theme === "dark") {
129
- env.theme = theme;
122
+ env_1.env.theme = theme;
130
123
  }
131
124
  }
132
125
  else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
133
- env.theme = 'dark';
126
+ env_1.env.theme = 'dark';
134
127
  }
135
128
  else {
136
- env.theme = 'light';
129
+ env_1.env.theme = 'light';
137
130
  }
138
131
  // Apply the resolved theme to <html> like setTheme does. Without this, getTheme()
139
132
  // and the DOM disagree until the first setTheme call, which can then be a visual
140
133
  // no-op (early return when env.theme already equals the requested theme).
141
- if (env.theme) {
142
- document.documentElement.classList.remove(env.theme === 'dark' ? 'light' : 'dark');
143
- document.documentElement.classList.add(env.theme);
134
+ if (env_1.env.theme) {
135
+ document.documentElement.classList.remove(env_1.env.theme === 'dark' ? 'light' : 'dark');
136
+ document.documentElement.classList.add(env_1.env.theme);
144
137
  }
145
138
  }
146
139
  catch {
@@ -154,18 +147,18 @@ function init(envVariables) {
154
147
  */
155
148
  function createApi() {
156
149
  const api = {
157
- env: env,
150
+ env: env_1.env,
158
151
  tables: {},
159
152
  uuid: () => (0, uuid_1.v4)(),
160
153
  getProjectFileUrl: (relativePath) => {
161
- if (env.clusterUrl === undefined)
162
- throw new Error(MISSING_CLUSTER_URL_ERROR);
163
- if (env.serviceName === undefined)
164
- throw new Error(MISSING_SERVICE_NAME_ERROR);
154
+ if (env_1.env.clusterUrl === undefined)
155
+ throw new Error(env_1.MISSING_CLUSTER_URL_ERROR);
156
+ if (env_1.env.serviceName === undefined)
157
+ throw new Error(env_1.MISSING_SERVICE_NAME_ERROR);
165
158
  relativePath = relativePath.replace(/\\/g, "/");
166
159
  if (relativePath.startsWith("/"))
167
160
  relativePath = relativePath.substring(1);
168
- let url = `${env.clusterUrl}/${env.serviceName}/project/file?name=""&path=${encodeURIComponent(relativePath)}`;
161
+ let url = `${env_1.env.clusterUrl}/${env_1.env.serviceName}/project/file?name=""&path=${encodeURIComponent(relativePath)}`;
169
162
  return url;
170
163
  },
171
164
  getProjectFile: async (relativePath) => {
@@ -178,10 +171,10 @@ function createApi() {
178
171
  return content;
179
172
  },
180
173
  requestCnql: async (cnql, verbose) => {
181
- if (env.clusterUrl === undefined)
182
- throw new Error(MISSING_CLUSTER_URL_ERROR);
183
- if (env.serviceName === undefined)
184
- throw new Error(MISSING_SERVICE_NAME_ERROR);
174
+ if (env_1.env.clusterUrl === undefined)
175
+ throw new Error(env_1.MISSING_CLUSTER_URL_ERROR);
176
+ if (env_1.env.serviceName === undefined)
177
+ throw new Error(env_1.MISSING_SERVICE_NAME_ERROR);
185
178
  const request = {
186
179
  method: 'POST',
187
180
  mode: 'cors',
@@ -189,14 +182,14 @@ function createApi() {
189
182
  headers: { 'Content-Type': 'application/json' },
190
183
  body: `"${cnql.replace(/\"/g, '\\\"')}"`
191
184
  };
192
- if (`${env.accessToken ?? ''}`.trim() !== "") {
193
- if (env.tenantName === undefined)
194
- throw new Error(MISSING_TENANT_NAME_ERROR);
185
+ if (`${env_1.env.accessToken ?? ''}`.trim() !== "") {
186
+ if (env_1.env.tenantName === undefined)
187
+ throw new Error(env_1.MISSING_TENANT_NAME_ERROR);
195
188
  request.headers = {
196
- ...request.headers, [`${env.tenantName}AccessToken`]: env.accessToken
189
+ ...request.headers, [`${env_1.env.tenantName}AccessToken`]: env_1.env.accessToken
197
190
  };
198
191
  }
199
- const response = await fetch(`${env.clusterUrl}/${env.serviceName}/cnql${verbose ? "?v=true" : ""}`, request);
192
+ const response = await fetch(`${env_1.env.clusterUrl}/${env_1.env.serviceName}/cnql${verbose ? "?v=true" : ""}`, request);
200
193
  if (!response.ok) {
201
194
  const error = await response.text();
202
195
  throw new Error(error);
@@ -207,10 +200,10 @@ function createApi() {
207
200
  return api.startProcessFromId(p.id, inputs);
208
201
  },
209
202
  startProcessFromId: async (processId, inputs) => {
210
- if (env.clusterUrl === undefined)
211
- throw new Error(MISSING_CLUSTER_URL_ERROR);
212
- if (env.serviceName === undefined)
213
- throw new Error(MISSING_SERVICE_NAME_ERROR);
203
+ if (env_1.env.clusterUrl === undefined)
204
+ throw new Error(env_1.MISSING_CLUSTER_URL_ERROR);
205
+ if (env_1.env.serviceName === undefined)
206
+ throw new Error(env_1.MISSING_SERVICE_NAME_ERROR);
214
207
  // Exemple url: http://127.0.0.1:5005/test1/processes/helloWorldProcess/instances
215
208
  // Format: {env.clusterUrl}/{env.serviceName}/processes/{process}/instances
216
209
  /*
@@ -221,7 +214,7 @@ function createApi() {
221
214
  }
222
215
  */
223
216
  // Starts the process
224
- const response = await fetch(`${env.clusterUrl}/${env.serviceName}/processes/${processId}/instances`, {
217
+ const response = await fetch(`${env_1.env.clusterUrl}/${env_1.env.serviceName}/processes/${processId}/instances`, {
225
218
  method: 'POST',
226
219
  body: JSON.stringify({
227
220
  "id": (0, uuid_1.v4)(),
@@ -265,7 +258,7 @@ function createApi() {
265
258
  "errors": []
266
259
  }
267
260
  */
268
- const instanceResp = await fetch(`${env.clusterUrl}/instances/${instanceData.instanceId}`, {
261
+ const instanceResp = await fetch(`${env_1.env.clusterUrl}/instances/${instanceData.instanceId}`, {
269
262
  method: 'GET',
270
263
  headers: {
271
264
  'Codenotch-Instance-Token': instanceData.instanceToken
@@ -390,37 +383,37 @@ function createApi() {
390
383
  return result;
391
384
  },
392
385
  setTheme: (theme) => {
393
- if (env.theme === theme)
386
+ if (env_1.env.theme === theme)
394
387
  return;
395
- if (env.theme)
396
- document.documentElement.classList.remove(env.theme);
397
- env.theme = theme;
388
+ if (env_1.env.theme)
389
+ document.documentElement.classList.remove(env_1.env.theme);
390
+ env_1.env.theme = theme;
398
391
  document.documentElement.classList.add(theme);
399
392
  notify();
400
393
  },
401
394
  setLanguage: (lang) => {
402
- if (env.language === lang)
395
+ if (env_1.env.language === lang)
403
396
  return;
404
- env.language = lang;
397
+ env_1.env.language = lang;
405
398
  notify();
406
399
  },
407
400
  getLanguages: () => {
408
- return env.projectManifest?.languages ?? [];
401
+ return env_1.env.projectManifest?.languages ?? [];
409
402
  },
410
403
  getLanguage: () => {
411
- return env.language;
404
+ return env_1.env.language;
412
405
  },
413
406
  getTheme: () => {
414
- return env.theme;
407
+ return env_1.env.theme;
415
408
  },
416
409
  getProjectManifest: () => {
417
- if (env.projectManifest === undefined) {
410
+ if (env_1.env.projectManifest === undefined) {
418
411
  throw new Error("Project manifest is not defined in Codenotch environment. Please set it in the Codenotch configuration.");
419
412
  }
420
- return env.projectManifest;
413
+ return env_1.env.projectManifest;
421
414
  },
422
415
  getAppManifest: () => {
423
- return env.appManifest;
416
+ return env_1.env.appManifest;
424
417
  }
425
418
  };
426
419
  return api;
@@ -1,6 +1,6 @@
1
1
  import type { ReactNode } from "react";
2
2
  import { IAppManifest, ICodenotchProjectManifest } from "@codenotch/codenotch.core";
3
- import { EntityMetadata, Query, Row, Predicate, Scope } from "@codenotch/orm";
3
+ import { EntityMetadata, Predicate, Scope } from "@codenotch/orm";
4
4
  /**
5
5
  * Runtime environment of a Codenotch application.
6
6
  *
@@ -45,18 +45,29 @@ export interface IProcessResult<T = any> {
45
45
  errorMessage: string;
46
46
  }
47
47
  export declare class ClientTableQueryable<T extends EntityMetadata> {
48
- private readonly _query;
49
- constructor(entity: T, serviceName: string);
50
- /** Wrap an existing query; used internally by the builder methods. */
51
- constructor(query: Query<T, Row<T>>);
48
+ private readonly _entity;
49
+ private readonly _filters;
50
+ /**
51
+ * @param entity The entity metadata, as returned by `defineEntity()`.
52
+ * @param filters Internal: predicates accumulated by {@link filter}. Leave empty.
53
+ */
54
+ constructor(entity: T, filters?: ReadonlyArray<(scope: Scope<T>) => Predicate>);
52
55
  /**
53
56
  * Add a predicate (AND-combined with the previous ones). Returns a new
54
57
  * queryable and leaves this one untouched, so a shared `tables.xxx`
55
58
  * instance can be reused for independent queries.
56
59
  */
57
60
  filter(predicate: (scope: Scope<T>) => Predicate): ClientTableQueryable<T>;
61
+ /**
62
+ * Build the query against the current environment (`env.serviceName`).
63
+ * Done lazily, at run time rather than in the constructor, because the
64
+ * generated tables module is evaluated at import time, before `init()`
65
+ * has populated the environment.
66
+ */
67
+ private toQuery;
58
68
  run(): Promise<T[]>;
59
69
  first(): Promise<T | undefined>;
70
+ private fetchResults;
60
71
  }
61
72
  /**
62
73
  * The project's tables, keyed by name — augmented via declaration merging by the
@@ -1 +1 @@
1
- {"version":3,"file":"Codenotch.d.ts","sourceRoot":"","sources":["../../src/models/Codenotch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Codenotch.d.ts","sourceRoot":"","sources":["../../src/models/Codenotch.ts"],"names":[],"mappings":"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"}
@@ -2,13 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ClientTableQueryable = void 0;
4
4
  const orm_1 = require("@codenotch/orm");
5
+ const env_1 = require("../env");
5
6
  /// ======================================================================================================================
6
7
  /// consomme @codenotch/orm
7
8
  class ClientTableQueryable {
8
- constructor(entityOrQuery, serviceName) {
9
- this._query = serviceName === undefined
10
- ? entityOrQuery
11
- : (0, orm_1.createReadContext)({ source: serviceName, now: () => orm_1.Instant.fromDate(new Date()) }).query(entityOrQuery);
9
+ /**
10
+ * @param entity The entity metadata, as returned by `defineEntity()`.
11
+ * @param filters Internal: predicates accumulated by {@link filter}. Leave empty.
12
+ */
13
+ constructor(entity, filters = []) {
14
+ this._entity = entity;
15
+ this._filters = filters;
12
16
  }
13
17
  /**
14
18
  * Add a predicate (AND-combined with the previous ones). Returns a new
@@ -16,19 +20,59 @@ class ClientTableQueryable {
16
20
  * instance can be reused for independent queries.
17
21
  */
18
22
  filter(predicate) {
19
- return new ClientTableQueryable(this._query.filter(predicate));
23
+ return new ClientTableQueryable(this._entity, [...this._filters, predicate]);
24
+ }
25
+ /**
26
+ * Build the query against the current environment (`env.serviceName`).
27
+ * Done lazily, at run time rather than in the constructor, because the
28
+ * generated tables module is evaluated at import time, before `init()`
29
+ * has populated the environment.
30
+ */
31
+ toQuery() {
32
+ if (env_1.env.serviceName === undefined)
33
+ throw new Error(env_1.MISSING_SERVICE_NAME_ERROR);
34
+ const context = (0, orm_1.createReadContext)({ source: env_1.env.serviceName, now: () => orm_1.Instant.fromDate(new Date()) });
35
+ const initial = context.query(this._entity);
36
+ return this._filters.reduce((query, predicate) => query.filter(predicate), initial);
20
37
  }
21
38
  async run() {
22
- const cnql = this._query.toXml();
39
+ const cnql = this.toQuery().toXml();
23
40
  // TODO
24
41
  console.log('this._query.toXml():', cnql);
42
+ const obj = await this.fetchResults(cnql);
43
+ console.log('this.fetchResults(cnql):', obj);
25
44
  return [];
26
45
  }
27
46
  async first() {
28
- const cnql = this._query.toXml();
29
- // TODO
30
- console.log('this._query.toXml():', cnql);
31
- return undefined;
47
+ // TODO: force pagesize to 1
48
+ const results = await this.run();
49
+ return results[0];
50
+ }
51
+ async fetchResults(cnql) {
52
+ if (env_1.env.clusterUrl === undefined)
53
+ throw new Error(env_1.MISSING_CLUSTER_URL_ERROR);
54
+ if (env_1.env.serviceName === undefined)
55
+ throw new Error(env_1.MISSING_SERVICE_NAME_ERROR);
56
+ const request = {
57
+ method: 'POST',
58
+ mode: 'cors',
59
+ credentials: 'same-origin',
60
+ headers: { 'Content-Type': 'application/json' },
61
+ body: `"${cnql.replace(/\"/g, '\\\"')}"`
62
+ };
63
+ if (`${env_1.env.accessToken ?? ''}`.trim() !== "") {
64
+ if (env_1.env.tenantName === undefined)
65
+ throw new Error(env_1.MISSING_TENANT_NAME_ERROR);
66
+ request.headers = {
67
+ ...request.headers, [`${env_1.env.tenantName}AccessToken`]: env_1.env.accessToken
68
+ };
69
+ }
70
+ const response = await fetch(`${env_1.env.clusterUrl}/${env_1.env.serviceName}/cnql?v=true`, request);
71
+ if (!response.ok) {
72
+ const error = await response.text();
73
+ throw new Error(error);
74
+ }
75
+ return await response.json();
32
76
  }
33
77
  }
34
78
  exports.ClientTableQueryable = ClientTableQueryable;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codenotch/codenotch.react",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "React bindings for Codenotch applications: start BPMN processes, run cnql queries, listen to real-time signals, manage theme and language.",
5
5
  "keywords": [
6
6
  "codenotch",
@@ -25,8 +25,8 @@
25
25
  "src/**/*"
26
26
  ],
27
27
  "dependencies": {
28
- "@codenotch/codenotch.core": "1.0.23",
29
- "@codenotch/orm": "0.1.1",
28
+ "@codenotch/codenotch.core": "^1.0.23",
29
+ "@codenotch/orm": "^0.1.2",
30
30
  "uuid": "^8.2.0"
31
31
  },
32
32
  "devDependencies": {
package/src/env.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { ICodenotchEnv } from "./models/Codenotch";
2
+
3
+ /**
4
+ * The Codenotch runtime environment, populated by `init()`.
5
+ * Prefer reading it through `useCodenotch().env`.
6
+ *
7
+ * Lives in its own module so that both the API (`index.ts`) and the ORM
8
+ * wrapper (`models/Codenotch.ts`) can read it without a circular import.
9
+ */
10
+ export const env: ICodenotchEnv = {};
11
+
12
+ export const MISSING_CLUSTER_URL_ERROR = "Codenotch cluster URL is not defined. Please set it in the Codenotch configuration.";
13
+ export const MISSING_SERVICE_NAME_ERROR = "Codenotch service name is not defined. Please set it in the Codenotch configuration.";
14
+ export const MISSING_TENANT_NAME_ERROR = "Codenotch tenant name is not defined. Please set it in the Codenotch configuration.";
package/src/index.ts CHANGED
@@ -2,19 +2,11 @@ import { createElement, useMemo, useSyncExternalStore, type ComponentType, type
2
2
  import { flushSync } from "react-dom";
3
3
  import { createRoot, Root } from "react-dom/client";
4
4
  import { IDisposable } from "./models/Misc";
5
- import { ClientTableQueryable, ClientTables, ICodenotchApi, ICodenotchDialog, ICodenotchEnv, IProcessResult, Process, WithCodenotchProps } from "./models/Codenotch";
5
+ import { ClientTableQueryable, ClientTables, ICodenotchApi, ICodenotchDialog, IProcessResult, Process, WithCodenotchProps } from "./models/Codenotch";
6
+ import { env, MISSING_CLUSTER_URL_ERROR, MISSING_SERVICE_NAME_ERROR, MISSING_TENANT_NAME_ERROR } from "./env";
6
7
  import { v4 } from "uuid";
7
8
  import CodeEditor from "./components/CodeEditor";
8
9
 
9
- /**
10
- * The Codenotch runtime environment, populated by {@link init}.
11
- * Prefer reading it through `useCodenotch().env`.
12
- */
13
- const env: ICodenotchEnv = {};
14
-
15
- const MISSING_CLUSTER_URL_ERROR = "Codenotch cluster URL is not defined. Please set it in the Codenotch configuration.";
16
- const MISSING_SERVICE_NAME_ERROR = "Codenotch service name is not defined. Please set it in the Codenotch configuration.";
17
- const MISSING_TENANT_NAME_ERROR = "Codenotch tenant name is not defined. Please set it in the Codenotch configuration.";
18
10
 
19
11
  // ---------------------------------------------------------------------------
20
12
  // Change tracking. `env` is a plain mutable object; every mutation done through
@@ -1,6 +1,7 @@
1
1
  import type { ReactNode } from "react";
2
2
  import { IAppManifest, ICodenotchProjectManifest } from "@codenotch/codenotch.core";
3
- import { EntityMetadata, Query, Row, Predicate, Scope, defineEntity, p, createReadContext, Instant} from "@codenotch/orm";
3
+ import { EntityMetadata, Query, Row, Predicate, Scope, defineEntity, p, createReadContext, Instant } from "@codenotch/orm";
4
+ import { env, MISSING_CLUSTER_URL_ERROR, MISSING_SERVICE_NAME_ERROR, MISSING_TENANT_NAME_ERROR } from "../env";
4
5
 
5
6
  /**
6
7
  * Runtime environment of a Codenotch application.
@@ -55,15 +56,20 @@ export interface IProcessResult<T = any> {
55
56
 
56
57
  export class ClientTableQueryable<T extends EntityMetadata> {
57
58
 
58
- private readonly _query: Query<T, Row<T>>;
59
+ private readonly _entity: T;
60
+ // Typed with `any` on purpose: a function-typed property is contravariant in
61
+ // its parameter, so keeping `Scope<T>` here would make ClientTableQueryable<Contact>
62
+ // unassignable to ClientTableQueryable<EntityMetadata>, i.e. to ClientTables.
63
+ // The public `filter()` signature stays fully typed.
64
+ private readonly _filters: ReadonlyArray<(scope: any) => Predicate>;
59
65
 
60
- constructor(entity: T, serviceName: string);
61
- /** Wrap an existing query; used internally by the builder methods. */
62
- constructor(query: Query<T, Row<T>>);
63
- constructor(entityOrQuery: T | Query<T, Row<T>>, serviceName?: string) {
64
- this._query = serviceName === undefined
65
- ? entityOrQuery as Query<T, Row<T>>
66
- : createReadContext({ source: serviceName, now: () => Instant.fromDate(new Date()) }).query(entityOrQuery as T);
66
+ /**
67
+ * @param entity The entity metadata, as returned by `defineEntity()`.
68
+ * @param filters Internal: predicates accumulated by {@link filter}. Leave empty.
69
+ */
70
+ constructor(entity: T, filters: ReadonlyArray<(scope: Scope<T>) => Predicate> = []) {
71
+ this._entity = entity;
72
+ this._filters = filters;
67
73
  }
68
74
 
69
75
  /**
@@ -72,21 +78,64 @@ export class ClientTableQueryable<T extends EntityMetadata> {
72
78
  * instance can be reused for independent queries.
73
79
  */
74
80
  filter(predicate: (scope: Scope<T>) => Predicate): ClientTableQueryable<T> {
75
- return new ClientTableQueryable<T>(this._query.filter(predicate));
81
+ return new ClientTableQueryable<T>(this._entity, [...this._filters, predicate]);
76
82
  }
77
83
 
78
- async run(): Promise<T[]>{
79
- const cnql = this._query.toXml();
84
+ /**
85
+ * Build the query against the current environment (`env.serviceName`).
86
+ * Done lazily, at run time rather than in the constructor, because the
87
+ * generated tables module is evaluated at import time, before `init()`
88
+ * has populated the environment.
89
+ */
90
+ private toQuery(): Query<T, Row<T>> {
91
+ if (env.serviceName === undefined) throw new Error(MISSING_SERVICE_NAME_ERROR);
92
+ const context = createReadContext({ source: env.serviceName, now: () => Instant.fromDate(new Date()) });
93
+ const initial: Query<T, Row<T>> = context.query(this._entity);
94
+ return this._filters.reduce((query, predicate) => query.filter(predicate), initial);
95
+ }
96
+
97
+ async run(): Promise<T[]> {
98
+ const cnql = this.toQuery().toXml();
80
99
  // TODO
81
100
  console.log('this._query.toXml():', cnql);
101
+
102
+ const obj = await this.fetchResults(cnql);
103
+
104
+ console.log('this.fetchResults(cnql):', obj);
105
+
82
106
  return [];
83
107
  }
84
108
 
85
109
  async first(): Promise<T | undefined> {
86
- const cnql = this._query.toXml();
87
- // TODO
88
- console.log('this._query.toXml():', cnql);
89
- return undefined;
110
+ // TODO: force pagesize to 1
111
+
112
+ const results = await this.run();
113
+
114
+ return results[0];
115
+ }
116
+
117
+ private async fetchResults(cnql: string) {
118
+ if (env.clusterUrl === undefined) throw new Error(MISSING_CLUSTER_URL_ERROR);
119
+ if (env.serviceName === undefined) throw new Error(MISSING_SERVICE_NAME_ERROR);
120
+ const request: RequestInit = {
121
+ method: 'POST',
122
+ mode: 'cors',
123
+ credentials: 'same-origin',
124
+ headers: { 'Content-Type': 'application/json' },
125
+ body: `"${cnql.replace(/\"/g, '\\\"')}"`
126
+ };
127
+ if (`${env.accessToken ?? ''}`.trim() !== "") {
128
+ if (env.tenantName === undefined) throw new Error(MISSING_TENANT_NAME_ERROR);
129
+ request.headers = {
130
+ ...request.headers, [`${env.tenantName}AccessToken`]: env.accessToken!
131
+ };
132
+ }
133
+ const response = await fetch(`${env.clusterUrl}/${env.serviceName}/cnql?v=true`, request);
134
+ if (!response.ok) {
135
+ const error = await response.text();
136
+ throw new Error(error);
137
+ }
138
+ return await response.json();
90
139
  }
91
140
  }
92
141