@operato/app 10.23.0 → 10.25.0

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.
@@ -1,4 +1,5 @@
1
1
  import { html } from 'lit-html';
2
+ import { entity360KindOf, openEntity360For } from '@operato/layout';
2
3
  export const OxGristRendererResourceObject = (value, column, record, rowIndex, field) => {
3
4
  if (!value) {
4
5
  return '';
@@ -17,6 +18,31 @@ export const OxGristRendererResourceObject = (value, column, record, rowIndex, f
17
18
  else {
18
19
  description = value[descriptionField] && `(${value[descriptionField]})`;
19
20
  }
20
- return html `<span>${name || ''}${description || ''}</span> `;
21
+ /*
22
+ * A value whose kind opens a 360 is a link to it (ADR-0067 decision 1, the person 360 ruling).
23
+ *
24
+ * Everything else - a type nobody registered, or a value without __typename because its call turned
25
+ * the cache off - returns exactly what it always did. dssp and fmsim render through here, and the
26
+ * architect's condition is that their screens do not change by a byte; a test compares both paths.
27
+ *
28
+ * The link is the body colour with an underline (ADR-0071's link rule) and does not let the click
29
+ * reach the row, which would start editing or select it.
30
+ */
31
+ if (!entity360KindOf(value)) {
32
+ return html `<span>${name || ''}${description || ''}</span> `;
33
+ }
34
+ return html `<span
35
+ ><a
36
+ href="#"
37
+ data-entity360
38
+ style="color: inherit; text-decoration: underline; cursor: pointer"
39
+ @click=${(event) => {
40
+ event.preventDefault();
41
+ event.stopPropagation();
42
+ openEntity360For(value);
43
+ }}
44
+ >${name || ''}</a
45
+ >${description || ''}</span
46
+ > `;
21
47
  };
22
48
  //# sourceMappingURL=ox-grist-renderer-resource-object.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ox-grist-renderer-resource-object.js","sourceRoot":"","sources":["../../../src/grist-editor/ox-grist-renderer-resource-object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAI/B,MAAM,CAAC,MAAM,6BAA6B,GAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;IACrG,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,EAAE,SAAS,GAAG,MAAM,EAAE,gBAAgB,GAAG,aAAa,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAA;IAC1F,IAAI,IAAI,EAAE,WAAW,CAAA;IAErB,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;QACpC,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAA;IACzB,CAAC;IAED,IAAI,OAAO,gBAAgB,KAAK,UAAU,EAAE,CAAC;QAC3C,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACvC,CAAC;SAAM,CAAC;QACN,WAAW,GAAG,KAAK,CAAC,gBAAgB,CAAC,IAAI,IAAI,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAA;IACzE,CAAC;IAED,OAAO,IAAI,CAAA,SAAS,IAAI,IAAI,EAAE,GAAG,WAAW,IAAI,EAAE,UAAU,CAAA;AAC9D,CAAC,CAAA","sourcesContent":["import { html } from 'lit-html'\n\nimport { FieldRenderer } from '@operato/data-grist'\n\nexport const OxGristRendererResourceObject: FieldRenderer = (value, column, record, rowIndex, field) => {\n if (!value) {\n return ''\n }\n\n var { nameField = 'name', descriptionField = 'description' } = column.record.options || {}\n var name, description\n\n if (typeof nameField === 'function') {\n name = nameField(value)\n } else {\n name = value[nameField]\n }\n\n if (typeof descriptionField === 'function') {\n description = descriptionField(value)\n } else {\n description = value[descriptionField] && `(${value[descriptionField]})`\n }\n\n return html`<span>${name || ''}${description || ''}</span> `\n}\n"]}
1
+ {"version":3,"file":"ox-grist-renderer-resource-object.js","sourceRoot":"","sources":["../../../src/grist-editor/ox-grist-renderer-resource-object.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAG/B,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEnE,MAAM,CAAC,MAAM,6BAA6B,GAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;IACrG,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,EAAE,SAAS,GAAG,MAAM,EAAE,gBAAgB,GAAG,aAAa,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAA;IAC1F,IAAI,IAAI,EAAE,WAAW,CAAA;IAErB,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;QACpC,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;SAAM,CAAC;QACN,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC,CAAA;IACzB,CAAC;IAED,IAAI,OAAO,gBAAgB,KAAK,UAAU,EAAE,CAAC;QAC3C,WAAW,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACvC,CAAC;SAAM,CAAC;QACN,WAAW,GAAG,KAAK,CAAC,gBAAgB,CAAC,IAAI,IAAI,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAA;IACzE,CAAC;IAED;;;;;;;;;OASG;IACH,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAA,SAAS,IAAI,IAAI,EAAE,GAAG,WAAW,IAAI,EAAE,UAAU,CAAA;IAC9D,CAAC;IAED,OAAO,IAAI,CAAA;;;;;iBAKI,CAAC,KAAY,EAAE,EAAE;QACxB,KAAK,CAAC,cAAc,EAAE,CAAA;QACtB,KAAK,CAAC,eAAe,EAAE,CAAA;QACvB,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;WACE,IAAI,IAAI,EAAE;SACZ,WAAW,IAAI,EAAE;OACnB,CAAA;AACP,CAAC,CAAA","sourcesContent":["import { html } from 'lit-html'\n\nimport { FieldRenderer } from '@operato/data-grist'\nimport { entity360KindOf, openEntity360For } from '@operato/layout'\n\nexport const OxGristRendererResourceObject: FieldRenderer = (value, column, record, rowIndex, field) => {\n if (!value) {\n return ''\n }\n\n var { nameField = 'name', descriptionField = 'description' } = column.record.options || {}\n var name, description\n\n if (typeof nameField === 'function') {\n name = nameField(value)\n } else {\n name = value[nameField]\n }\n\n if (typeof descriptionField === 'function') {\n description = descriptionField(value)\n } else {\n description = value[descriptionField] && `(${value[descriptionField]})`\n }\n\n /*\n * A value whose kind opens a 360 is a link to it (ADR-0067 decision 1, the person 360 ruling).\n *\n * Everything else - a type nobody registered, or a value without __typename because its call turned\n * the cache off - returns exactly what it always did. dssp and fmsim render through here, and the\n * architect's condition is that their screens do not change by a byte; a test compares both paths.\n *\n * The link is the body colour with an underline (ADR-0071's link rule) and does not let the click\n * reach the row, which would start editing or select it.\n */\n if (!entity360KindOf(value)) {\n return html`<span>${name || ''}${description || ''}</span> `\n }\n\n return html`<span\n ><a\n href=\"#\"\n data-entity360\n style=\"color: inherit; text-decoration: underline; cursor: pointer\"\n @click=${(event: Event) => {\n event.preventDefault()\n event.stopPropagation()\n openEntity360For(value)\n }}\n >${name || ''}</a\n >${description || ''}</span\n > `\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,66 @@
1
+ import { expect } from '@open-wc/testing';
2
+ import { html } from 'lit-html';
3
+ import { registerEntity360Kind } from '@operato/layout';
4
+ import { OxGristRendererResourceObject } from '../src/grist-editor/ox-grist-renderer-resource-object.js';
5
+ /**
6
+ * The resource-object cell links a value to its 360 only when its kind is registered - and otherwise
7
+ * returns exactly what it always did (architect ruling on the person 360: dssp and fmsim render
8
+ * through this cell, and their screens must not change by a byte).
9
+ *
10
+ * `original` is the renderer as it stood before, kept verbatim here as the reference.
11
+ */
12
+ function original(value, column) {
13
+ if (!value) {
14
+ return '';
15
+ }
16
+ var { nameField = 'name', descriptionField = 'description' } = column.record.options || {};
17
+ var name, description;
18
+ if (typeof nameField === 'function') {
19
+ name = nameField(value);
20
+ }
21
+ else {
22
+ name = value[nameField];
23
+ }
24
+ if (typeof descriptionField === 'function') {
25
+ description = descriptionField(value);
26
+ }
27
+ else {
28
+ description = value[descriptionField] && `(${value[descriptionField]})`;
29
+ }
30
+ return html `<span>${name || ''}${description || ''}</span> `;
31
+ }
32
+ const column = (options) => ({ record: { options } });
33
+ const render = (value, col = column()) => OxGristRendererResourceObject(value, col, {}, 0, {});
34
+ /** A template's identity: the same static strings and the same values. */
35
+ const same = (a, b) => {
36
+ if (typeof a === 'string' || typeof b === 'string')
37
+ return a === b;
38
+ return a.strings === b.strings || (a.strings.join('\u0000') === b.strings.join('\u0000') && JSON.stringify(a.values) === JSON.stringify(b.values));
39
+ };
40
+ describe('resource-object cell and the entity 360', () => {
41
+ before(() => {
42
+ registerEntity360Kind({ kind: 'cell-test-person', typenames: ['CellTestUser'], title: s => s.value.name });
43
+ });
44
+ const unchanged = [
45
+ ['an unregistered type', { __typename: 'SomethingElse', id: '1', name: 'Kim', description: 'QA' }],
46
+ ['a value without __typename', { id: '1', name: 'Kim', description: 'QA' }],
47
+ ['a value with a name only', { __typename: 'Nobody', id: '2', name: 'Lee' }],
48
+ ['no value at all', null]
49
+ ];
50
+ for (const [what, value] of unchanged) {
51
+ it(`★ ${what} renders exactly as before`, () => {
52
+ expect(same(render(value), original(value, column()))).to.equal(true);
53
+ });
54
+ }
55
+ it('★ and with custom name and description fields, still exactly as before', () => {
56
+ const col = column({ nameField: 'title', descriptionField: (v) => `[${v.code}]` });
57
+ const value = { __typename: 'Other', title: 'T', code: 'C' };
58
+ expect(same(render(value, col), original(value, col))).to.equal(true);
59
+ });
60
+ it('★ a registered type renders the name as a link to its 360', () => {
61
+ const result = render({ __typename: 'CellTestUser', id: '9', name: 'Park' });
62
+ expect(result.strings.join('')).to.contain('data-entity360');
63
+ expect(result.values).to.include('Park');
64
+ });
65
+ });
66
+ //# sourceMappingURL=resource-object-renderer-360.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-object-renderer-360.test.js","sourceRoot":"","sources":["../../test/resource-object-renderer-360.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect } from '@open-wc/testing'\nimport { html } from 'lit-html'\n\nimport { registerEntity360Kind } from '@operato/layout'\nimport { OxGristRendererResourceObject } from '../src/grist-editor/ox-grist-renderer-resource-object.js'\n\n/**\n * The resource-object cell links a value to its 360 only when its kind is registered - and otherwise\n * returns exactly what it always did (architect ruling on the person 360: dssp and fmsim render\n * through this cell, and their screens must not change by a byte).\n *\n * `original` is the renderer as it stood before, kept verbatim here as the reference.\n */\nfunction original(value: any, column: any) {\n if (!value) {\n return ''\n }\n\n var { nameField = 'name', descriptionField = 'description' } = column.record.options || {}\n var name, description\n\n if (typeof nameField === 'function') {\n name = nameField(value)\n } else {\n name = value[nameField]\n }\n\n if (typeof descriptionField === 'function') {\n description = descriptionField(value)\n } else {\n description = value[descriptionField] && `(${value[descriptionField]})`\n }\n\n return html`<span>${name || ''}${description || ''}</span> `\n}\n\nconst column = (options?: any) => ({ record: { options } }) as any\nconst render = (value: any, col = column()) => (OxGristRendererResourceObject as any)(value, col, {}, 0, {})\n\n/** A template's identity: the same static strings and the same values. */\nconst same = (a: any, b: any) => {\n if (typeof a === 'string' || typeof b === 'string') return a === b\n return a.strings === b.strings || (a.strings.join('\\u0000') === b.strings.join('\\u0000') && JSON.stringify(a.values) === JSON.stringify(b.values))\n}\n\ndescribe('resource-object cell and the entity 360', () => {\n before(() => {\n registerEntity360Kind({ kind: 'cell-test-person', typenames: ['CellTestUser'], title: s => s.value.name })\n })\n\n const unchanged = [\n ['an unregistered type', { __typename: 'SomethingElse', id: '1', name: 'Kim', description: 'QA' }],\n ['a value without __typename', { id: '1', name: 'Kim', description: 'QA' }],\n ['a value with a name only', { __typename: 'Nobody', id: '2', name: 'Lee' }],\n ['no value at all', null]\n ] as const\n\n for (const [what, value] of unchanged) {\n it(`★ ${what} renders exactly as before`, () => {\n expect(same(render(value), original(value, column()))).to.equal(true)\n })\n }\n\n it('★ and with custom name and description fields, still exactly as before', () => {\n const col = column({ nameField: 'title', descriptionField: (v: any) => `[${v.code}]` })\n const value = { __typename: 'Other', title: 'T', code: 'C' }\n expect(same(render(value, col), original(value, col))).to.equal(true)\n })\n\n it('★ a registered type renders the name as a link to its 360', () => {\n const result = render({ __typename: 'CellTestUser', id: '9', name: 'Park' })\n expect(result.strings.join('')).to.contain('data-entity360')\n expect(result.values).to.include('Park')\n })\n})\n"]}