@dataverse-kit/export-engine 1.1.0 → 1.3.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.
package/dist/index.cjs CHANGED
@@ -12809,7 +12809,10 @@ function buildV8Body(args) {
12809
12809
  selectedIndicesState = "",
12810
12810
  handlerBlock = "",
12811
12811
  rowCommandsLiteral = "",
12812
- deleteDialogJsx = ""
12812
+ deleteDialogJsx = "",
12813
+ commandBarBlock = "",
12814
+ selectionModeAttr = "",
12815
+ onSelectionChangedAttr = ""
12813
12816
  } = args;
12814
12817
  const rowCommandsAttr = rowCommandsLiteral ? `
12815
12818
  rowCommands={[
@@ -12823,7 +12826,7 @@ const ${componentName}: React.FC<{ items: Record<string, unknown>[] }> = ({ item
12823
12826
  [items],
12824
12827
  );${selectedIndicesState}${handlerBlock}
12825
12828
  return (
12826
- <div>
12829
+ <div>${commandBarBlock}
12827
12830
  <DataGrid
12828
12831
  items={keyedItems}
12829
12832
  columns={[
@@ -12832,7 +12835,7 @@ const ${componentName}: React.FC<{ items: Record<string, unknown>[] }> = ({ item
12832
12835
  registry={registry}
12833
12836
  editable
12834
12837
  editTrigger="click"
12835
- getKey={(it) => String((it as { __rowIndex?: number }).__rowIndex ?? '')}${onValueChangeAttr}${rowCommandsAttr}
12838
+ getKey={(it) => String((it as { __rowIndex?: number }).__rowIndex ?? '')}${selectionModeAttr}${onSelectionChangedAttr}${onValueChangeAttr}${rowCommandsAttr}
12836
12839
  />${editableAggregate}${editablePagination}${saveStatusJsx}${deleteDialogJsx}
12837
12840
  </div>
12838
12841
  );
@@ -12885,7 +12888,8 @@ function buildLiveReadOnlyV8Body(args) {
12885
12888
  selectedIndicesState = "",
12886
12889
  handlerBlock = "",
12887
12890
  rowCommandsLiteral = "",
12888
- deleteDialogJsx = ""
12891
+ deleteDialogJsx = "",
12892
+ commandBarBlock = ""
12889
12893
  } = args;
12890
12894
  const rowCommandsAttr = rowCommandsLiteral ? `
12891
12895
  rowCommands={[
@@ -12905,7 +12909,7 @@ const ${helperName}: React.FC = () => {
12905
12909
  if (isLoading) return <div style={{ padding: 16, color: '#605e5c' }}>Loading records\u2026</div>;
12906
12910
  if (error) return <div style={{ padding: 16, color: '#a4262c' }}>{error.message}</div>;
12907
12911
  return (
12908
- <div>
12912
+ <div>${commandBarBlock}
12909
12913
  <ReadOnlyGrid
12910
12914
  items={rows}
12911
12915
  columns={[
@@ -12930,7 +12934,7 @@ const ${helperName}: React.FC = () => {
12930
12934
  if (error) return <div style={{ padding: 16, color: '#a4262c' }}>{error.message}</div>;
12931
12935
  const rows = (data ?? []).map((r, i) => ({ ...r, __rowIndex: i }));
12932
12936
  return (
12933
- <div>
12937
+ <div>${commandBarBlock}
12934
12938
  <ReadOnlyGrid
12935
12939
  items={rows}
12936
12940
  columns={[
@@ -12958,7 +12962,10 @@ function buildCardV8LiveBody(args) {
12958
12962
  selectedIndicesState = "",
12959
12963
  handlerBlock = "",
12960
12964
  rowCommandsLiteral = "",
12961
- deleteDialogJsx = ""
12965
+ deleteDialogJsx = "",
12966
+ commandBarBlock = "",
12967
+ selectionModeAttr = "",
12968
+ onSelectionChangedAttr = ""
12962
12969
  } = args;
12963
12970
  const rowCommandsAttr = rowCommandsLiteral ? `
12964
12971
  rowCommands={[
@@ -12978,14 +12985,14 @@ const ${helperName}: React.FC = () => {
12978
12985
  if (isLoading) return <div style={{ padding: 16, color: '#605e5c' }}>Loading records\u2026</div>;
12979
12986
  if (error) return <div style={{ padding: 16, color: '#a4262c' }}>{error.message}</div>;
12980
12987
  return (
12981
- <div>
12988
+ <div>${commandBarBlock}
12982
12989
  <CardGrid
12983
12990
  items={rows}
12984
12991
  columns={[
12985
12992
  ${colEntries}
12986
12993
  ] as ColumnDef[]}
12987
12994
  registry={registry}
12988
- getKey={(it) => String((it as { __rowIndex?: number }).__rowIndex ?? '')}
12995
+ getKey={(it) => String((it as { __rowIndex?: number }).__rowIndex ?? '')}${selectionModeAttr}${onSelectionChangedAttr}
12989
12996
  card={{ ${cardConfigLiteral} }}${rowCommandsAttr}
12990
12997
  />${flatAggregateInner}${flatPaginationInner}${deleteDialogJsx}
12991
12998
  </div>
@@ -15112,6 +15119,10 @@ ${childEntries.join(",\n")},
15112
15119
  const flatHasDelete = contextMenuItems.some(
15113
15120
  (ci) => ci.actionType === "delete"
15114
15121
  );
15122
+ const flatHasCommandBar = gridCommandBarBlock.trim().length > 0;
15123
+ const flatBarHasDelete = barItems.some((ci) => ci.actionType === "delete");
15124
+ const flatSelectionModeAttr = ` selectionMode="${gridDef.selectionMode === "single" ? "single" : "multiple"}"`;
15125
+ const flatOnSelectionChangedAttr = "\n onSelectionChanged={(rows) => setSelectedIndices(new Set(rows.map((r) => Number((r as { __rowIndex?: number }).__rowIndex ?? -1))))}";
15115
15126
  if (gridDef.cardView?.enabled === true && gridDef.gridType !== "focused-view" && !isV9 && !isEditable) {
15116
15127
  const cardIsLive = _includeDataAccessLayer && hasLiveDataSource;
15117
15128
  const helperName = `${toSafeVarName(gridDef.name || entityName)}CardGrid`;
@@ -15129,16 +15140,21 @@ ${childEntries.join(",\n")},
15129
15140
  gridDef.dataSource.fetchXml || `<fetch top="25"><entity name="${gridDef.dataSource.entityName}"><all-attributes /></entity></fetch>`
15130
15141
  ) : "[]";
15131
15142
  const cardEmitRowCommands = cardIsLive && _handlerAvailable && flatHasContextMenu;
15132
- const cardHandlerBlock = cardEmitRowCommands ? buildGridCommandHandlerBlock({
15143
+ const cardEmitToolbar = cardIsLive && _handlerAvailable && flatHasCommandBar;
15144
+ const cardEmitHandler = cardEmitRowCommands || cardEmitToolbar;
15145
+ const cardHandlerBlock = cardEmitHandler ? buildGridCommandHandlerBlock({
15133
15146
  entityName: gridDef.dataSource.entityName,
15134
15147
  entitySetName: gridDef.dataSource.entitySetName,
15135
15148
  primaryIdAttribute: resolvePrimaryIdAttribute(gridDef),
15136
15149
  itemsExpr: "rows",
15137
15150
  selectionExpr: "selectedIndices"
15138
15151
  }) : "";
15139
- const cardSelectedIndicesState = cardEmitRowCommands ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15152
+ const cardSelectedIndicesState = cardEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15140
15153
  const cardRowCommandsLiteral = cardEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
15141
- const cardDeleteDialogJsx = cardEmitRowCommands && flatHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15154
+ const cardDeleteDialogJsx = cardEmitRowCommands && flatHasDelete || cardEmitToolbar && flatBarHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15155
+ const cardCommandBarBlock = cardEmitToolbar ? gridCommandBarBlock : "";
15156
+ const cardSelectionModeAttr = cardEmitToolbar ? flatSelectionModeAttr : "";
15157
+ const cardOnSelectionChangedAttr = cardEmitToolbar ? flatOnSelectionChangedAttr : "";
15142
15158
  const helperComponents = [
15143
15159
  buildCardSubgridBody({
15144
15160
  helperName,
@@ -15153,11 +15169,14 @@ ${childEntries.join(",\n")},
15153
15169
  selectedIndicesState: cardSelectedIndicesState,
15154
15170
  handlerBlock: cardHandlerBlock,
15155
15171
  rowCommandsLiteral: cardRowCommandsLiteral,
15156
- deleteDialogJsx: cardDeleteDialogJsx
15172
+ deleteDialogJsx: cardDeleteDialogJsx,
15173
+ commandBarBlock: cardCommandBarBlock,
15174
+ selectionModeAttr: cardSelectionModeAttr,
15175
+ onSelectionChangedAttr: cardOnSelectionChangedAttr
15157
15176
  })
15158
15177
  ];
15159
15178
  _usesGridKit = true;
15160
- const cardDataverseImport = cardEmitRowCommands ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery } from '../lib/dataverse';`;
15179
+ const cardDataverseImport = cardEmitHandler ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery } from '../lib/dataverse';`;
15161
15180
  if (cardDeleteDialogJsx) {
15162
15181
  imports.add("Dialog");
15163
15182
  imports.add("DialogType");
@@ -15169,7 +15188,7 @@ ${childEntries.join(",\n")},
15169
15188
  imports,
15170
15189
  v9Imports,
15171
15190
  v9IconImports,
15172
- extraImports: cardIsLive ? cardEmitRowCommands ? [
15191
+ extraImports: cardIsLive ? cardEmitHandler ? [
15173
15192
  cardDataverseImport,
15174
15193
  `import { useQueryClient } from '@tanstack/react-query';`,
15175
15194
  `import { CardGrid, createCellRegistry, type ColumnDef } from '../lib/grid-kit';`
@@ -15203,16 +15222,19 @@ ${childEntries.join(",\n")},
15203
15222
  );
15204
15223
  const gridKitColEntries = generateGridKitColumnEntries(visibleCols);
15205
15224
  const roEmitRowCommands = !isV9 && _handlerAvailable && flatHasContextMenu;
15206
- const roHandlerBlock = roEmitRowCommands ? buildGridCommandHandlerBlock({
15225
+ const roEmitToolbar = !isV9 && _handlerAvailable && flatHasCommandBar;
15226
+ const roEmitHandler = roEmitRowCommands || roEmitToolbar;
15227
+ const roHandlerBlock = roEmitHandler ? buildGridCommandHandlerBlock({
15207
15228
  entityName: gridDef.dataSource.entityName,
15208
15229
  entitySetName: gridDef.dataSource.entitySetName,
15209
15230
  primaryIdAttribute: resolvePrimaryIdAttribute(gridDef),
15210
15231
  itemsExpr: "rows",
15211
15232
  selectionExpr: "selectedIndices"
15212
15233
  }) : "";
15213
- const roSelectedIndicesState = roEmitRowCommands ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15234
+ const roSelectedIndicesState = roEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15214
15235
  const roRowCommandsLiteral = roEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
15215
15236
  const roDeleteDialogJsx = roEmitRowCommands && flatHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15237
+ const roCommandBarBlock = roEmitToolbar ? gridCommandBarBlock : "";
15216
15238
  const helperComponents = [
15217
15239
  buildLiveReadOnlySubgridBody({
15218
15240
  library,
@@ -15229,11 +15251,12 @@ ${childEntries.join(",\n")},
15229
15251
  selectedIndicesState: roSelectedIndicesState,
15230
15252
  handlerBlock: roHandlerBlock,
15231
15253
  rowCommandsLiteral: roRowCommandsLiteral,
15232
- deleteDialogJsx: roDeleteDialogJsx
15254
+ deleteDialogJsx: roDeleteDialogJsx,
15255
+ commandBarBlock: roCommandBarBlock
15233
15256
  })
15234
15257
  ];
15235
15258
  if (!isV9) _usesGridKit = true;
15236
- const roDataverseImport = roEmitRowCommands ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery } from '../lib/dataverse';`;
15259
+ const roDataverseImport = roEmitHandler ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery } from '../lib/dataverse';`;
15237
15260
  if (roDeleteDialogJsx) {
15238
15261
  imports.add("Dialog");
15239
15262
  imports.add("DialogType");
@@ -15245,7 +15268,7 @@ ${childEntries.join(",\n")},
15245
15268
  imports,
15246
15269
  v9Imports,
15247
15270
  v9IconImports,
15248
- extraImports: isV9 ? [`import { useDataverseQuery } from '../lib/dataverse';`] : roEmitRowCommands ? [
15271
+ extraImports: isV9 ? [`import { useDataverseQuery } from '../lib/dataverse';`] : roEmitHandler ? [
15249
15272
  roDataverseImport,
15250
15273
  `import { useQueryClient } from '@tanstack/react-query';`,
15251
15274
  `import { ReadOnlyGrid, createCellRegistry, type ColumnDef } from '../lib/grid-kit';`
@@ -15301,16 +15324,21 @@ const ${liveWrapperName}: React.FC = () => {
15301
15324
  onValueChange={(rowKey, fieldName, value) => commitCellEdit(Number(rowKey), fieldName, value)}` : "";
15302
15325
  const saveStatusJsx2 = editableUsesLiveData ? buildEditableSaveStatusJsx("updateMutation", "saveError") : "";
15303
15326
  const edEmitRowCommands = _handlerAvailable && editableUsesLiveData && !isV9 && flatHasContextMenu;
15304
- const edHandlerBlock = edEmitRowCommands ? buildGridCommandHandlerBlock({
15327
+ const edEmitToolbar = _handlerAvailable && editableUsesLiveData && !isV9 && flatHasCommandBar;
15328
+ const edEmitHandler = edEmitRowCommands || edEmitToolbar;
15329
+ const edHandlerBlock = edEmitHandler ? buildGridCommandHandlerBlock({
15305
15330
  entityName: gridDef.dataSource.entityName,
15306
15331
  entitySetName: gridDef.dataSource.entitySetName,
15307
15332
  primaryIdAttribute: resolvePrimaryIdAttribute(gridDef),
15308
15333
  itemsExpr: "keyedItems",
15309
15334
  selectionExpr: "selectedIndices"
15310
15335
  }) : "";
15311
- const edSelectedIndicesState = edEmitRowCommands ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15336
+ const edSelectedIndicesState = edEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15312
15337
  const edRowCommandsLiteral = edEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
15313
- const edDeleteDialogJsx = edEmitRowCommands && flatHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15338
+ const edDeleteDialogJsx = edEmitRowCommands && flatHasDelete || edEmitToolbar && flatBarHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15339
+ const edCommandBarBlock = edEmitToolbar ? gridCommandBarBlock : "";
15340
+ const edSelectionModeAttr = edEmitToolbar ? flatSelectionModeAttr : "";
15341
+ const edOnSelectionChangedAttr = edEmitToolbar ? flatOnSelectionChangedAttr : "";
15314
15342
  const editableSubgridBody2 = buildEditableSubgridBody({
15315
15343
  library,
15316
15344
  componentName,
@@ -15323,7 +15351,10 @@ const ${liveWrapperName}: React.FC = () => {
15323
15351
  selectedIndicesState: edSelectedIndicesState,
15324
15352
  handlerBlock: edHandlerBlock,
15325
15353
  rowCommandsLiteral: edRowCommandsLiteral,
15326
- deleteDialogJsx: edDeleteDialogJsx
15354
+ deleteDialogJsx: edDeleteDialogJsx,
15355
+ commandBarBlock: edCommandBarBlock,
15356
+ selectionModeAttr: edSelectionModeAttr,
15357
+ onSelectionChangedAttr: edOnSelectionChangedAttr
15327
15358
  });
15328
15359
  const helperComponents2 = [
15329
15360
  editableSubgridBody2,
@@ -15332,7 +15363,7 @@ const ${liveWrapperName}: React.FC = () => {
15332
15363
  const jsx3 = editableUsesLiveData && liveWrapperName ? `{/* Subgrid: ${safeEntityName} \u2014 ${safeGridName} (editable, live) */}${todoComment}
15333
15364
  <${liveWrapperName} />` : `{/* Subgrid: ${safeEntityName} \u2014 ${safeGridName} (editable) */}${todoComment}
15334
15365
  <${componentName} items={${itemsLiteral}} />`;
15335
- const edDataverseImport = edEmitRowCommands ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery, useUpdateRecord } from '../lib/dataverse';`;
15366
+ const edDataverseImport = edEmitHandler ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery, useUpdateRecord } from '../lib/dataverse';`;
15336
15367
  if (edDeleteDialogJsx) {
15337
15368
  imports.add("Dialog");
15338
15369
  imports.add("DialogType");
@@ -15340,7 +15371,7 @@ const ${liveWrapperName}: React.FC = () => {
15340
15371
  imports.add("PrimaryButton");
15341
15372
  imports.add("DefaultButton");
15342
15373
  }
15343
- const extraImports2 = editableUsesLiveData ? edEmitRowCommands ? [
15374
+ const extraImports2 = editableUsesLiveData ? edEmitHandler ? [
15344
15375
  edDataverseImport,
15345
15376
  `import { useQueryClient } from '@tanstack/react-query';`,
15346
15377
  `import { DataGrid, createCellRegistry, type ColumnDef } from '../lib/grid-kit';`
@@ -22510,27 +22541,6 @@ function generatePcfProject(project, options) {
22510
22541
  2
22511
22542
  ) + "\n"
22512
22543
  });
22513
- const platformLibraries = isV9 ? ` <platform-library name="React" version="18.2.0" />
22514
- <platform-library name="Fluent" version="9.46.2" />` : ` <platform-library name="React" version="16.14.0" />
22515
- <platform-library name="Fluent" version="8.29.0" />`;
22516
- const nsAttr = escapeHtml(ns);
22517
- const controlNameAttr = escapeHtml(controlName);
22518
- files.push({
22519
- path: `${controlName}/ControlManifest.Input.xml`,
22520
- content: `<?xml version="1.0" encoding="utf-8" ?>
22521
- <manifest>
22522
- <control namespace="${nsAttr}" constructor="${controlNameAttr}" version="1.0.0" display-name-key="${controlNameAttr}" description-key="${controlNameAttr} PCF Control" control-type="virtual" >
22523
- <external-service-usage enabled="false">
22524
- </external-service-usage>
22525
- <property name="value" display-name-key="Value" description-key="Primary value" of-type="SingleLine.Text" usage="bound" required="false" />
22526
- <resources>
22527
- <code path="index.ts" order="1"/>
22528
- ${platformLibraries}
22529
- </resources>
22530
- </control>
22531
- </manifest>
22532
- `
22533
- });
22534
22544
  const mainForm = project.forms.find((f) => f.type === "main") ?? project.forms[0];
22535
22545
  const mainComponentName = mainForm ? toFormComponentName(mainForm.name) : "div";
22536
22546
  const pcfIndexContent = isV9 ? `import { IInputs, IOutputs } from './generated/ManifestTypes';
@@ -22538,7 +22548,7 @@ import * as React from 'react';
22538
22548
  import * as ReactDOM from 'react-dom';
22539
22549
  import { initializeIcons } from '@fluentui/react';
22540
22550
  import { FluentProvider, webLightTheme } from '@fluentui/react-components';
22541
- import { ${mainComponentName} } from './components/${mainComponentName}';
22551
+ import { ${mainComponentName} } from './src/components/${mainComponentName}';
22542
22552
 
22543
22553
  initializeIcons();
22544
22554
 
@@ -22578,7 +22588,7 @@ export class ${controlName} implements ComponentFramework.ReactControl<IInputs,
22578
22588
  import * as React from 'react';
22579
22589
  import * as ReactDOM from 'react-dom';
22580
22590
  import { initializeIcons, ThemeProvider } from '@fluentui/react';
22581
- import { ${mainComponentName} } from './components/${mainComponentName}';
22591
+ import { ${mainComponentName} } from './src/components/${mainComponentName}';
22582
22592
 
22583
22593
  initializeIcons();
22584
22594
 
@@ -22631,6 +22641,29 @@ export class ${controlName} implements ComponentFramework.ReactControl<IInputs,
22631
22641
  content: file.content
22632
22642
  });
22633
22643
  }
22644
+ const usesGridKit = formFiles.some((f) => f.path.startsWith("src/lib/grid-kit/"));
22645
+ const platformLibraries = isV9 ? ` <platform-library name="React" version="18.2.0" />
22646
+ <platform-library name="Fluent" version="9.46.2" />` : usesGridKit ? ` <platform-library name="React" version="18.2.0" />
22647
+ <platform-library name="Fluent" version="8.115.6" />` : ` <platform-library name="React" version="16.14.0" />
22648
+ <platform-library name="Fluent" version="8.29.0" />`;
22649
+ const nsAttr = escapeHtml(ns);
22650
+ const controlNameAttr = escapeHtml(controlName);
22651
+ files.push({
22652
+ path: `${controlName}/ControlManifest.Input.xml`,
22653
+ content: `<?xml version="1.0" encoding="utf-8" ?>
22654
+ <manifest>
22655
+ <control namespace="${nsAttr}" constructor="${controlNameAttr}" version="1.0.0" display-name-key="${controlNameAttr}" description-key="${controlNameAttr} PCF Control" control-type="virtual" >
22656
+ <external-service-usage enabled="false">
22657
+ </external-service-usage>
22658
+ <property name="value" display-name-key="Value" description-key="Primary value" of-type="SingleLine.Text" usage="bound" required="false" />
22659
+ <resources>
22660
+ <code path="index.ts" order="1"/>
22661
+ ${platformLibraries}
22662
+ </resources>
22663
+ </control>
22664
+ </manifest>
22665
+ `
22666
+ });
22634
22667
  if (includeDataAccessLayer) {
22635
22668
  const dalFiles = generateDataAccessLayer(
22636
22669
  project.forms,
package/dist/index.mjs CHANGED
@@ -12789,7 +12789,10 @@ function buildV8Body(args) {
12789
12789
  selectedIndicesState = "",
12790
12790
  handlerBlock = "",
12791
12791
  rowCommandsLiteral = "",
12792
- deleteDialogJsx = ""
12792
+ deleteDialogJsx = "",
12793
+ commandBarBlock = "",
12794
+ selectionModeAttr = "",
12795
+ onSelectionChangedAttr = ""
12793
12796
  } = args;
12794
12797
  const rowCommandsAttr = rowCommandsLiteral ? `
12795
12798
  rowCommands={[
@@ -12803,7 +12806,7 @@ const ${componentName}: React.FC<{ items: Record<string, unknown>[] }> = ({ item
12803
12806
  [items],
12804
12807
  );${selectedIndicesState}${handlerBlock}
12805
12808
  return (
12806
- <div>
12809
+ <div>${commandBarBlock}
12807
12810
  <DataGrid
12808
12811
  items={keyedItems}
12809
12812
  columns={[
@@ -12812,7 +12815,7 @@ const ${componentName}: React.FC<{ items: Record<string, unknown>[] }> = ({ item
12812
12815
  registry={registry}
12813
12816
  editable
12814
12817
  editTrigger="click"
12815
- getKey={(it) => String((it as { __rowIndex?: number }).__rowIndex ?? '')}${onValueChangeAttr}${rowCommandsAttr}
12818
+ getKey={(it) => String((it as { __rowIndex?: number }).__rowIndex ?? '')}${selectionModeAttr}${onSelectionChangedAttr}${onValueChangeAttr}${rowCommandsAttr}
12816
12819
  />${editableAggregate}${editablePagination}${saveStatusJsx}${deleteDialogJsx}
12817
12820
  </div>
12818
12821
  );
@@ -12865,7 +12868,8 @@ function buildLiveReadOnlyV8Body(args) {
12865
12868
  selectedIndicesState = "",
12866
12869
  handlerBlock = "",
12867
12870
  rowCommandsLiteral = "",
12868
- deleteDialogJsx = ""
12871
+ deleteDialogJsx = "",
12872
+ commandBarBlock = ""
12869
12873
  } = args;
12870
12874
  const rowCommandsAttr = rowCommandsLiteral ? `
12871
12875
  rowCommands={[
@@ -12885,7 +12889,7 @@ const ${helperName}: React.FC = () => {
12885
12889
  if (isLoading) return <div style={{ padding: 16, color: '#605e5c' }}>Loading records\u2026</div>;
12886
12890
  if (error) return <div style={{ padding: 16, color: '#a4262c' }}>{error.message}</div>;
12887
12891
  return (
12888
- <div>
12892
+ <div>${commandBarBlock}
12889
12893
  <ReadOnlyGrid
12890
12894
  items={rows}
12891
12895
  columns={[
@@ -12910,7 +12914,7 @@ const ${helperName}: React.FC = () => {
12910
12914
  if (error) return <div style={{ padding: 16, color: '#a4262c' }}>{error.message}</div>;
12911
12915
  const rows = (data ?? []).map((r, i) => ({ ...r, __rowIndex: i }));
12912
12916
  return (
12913
- <div>
12917
+ <div>${commandBarBlock}
12914
12918
  <ReadOnlyGrid
12915
12919
  items={rows}
12916
12920
  columns={[
@@ -12938,7 +12942,10 @@ function buildCardV8LiveBody(args) {
12938
12942
  selectedIndicesState = "",
12939
12943
  handlerBlock = "",
12940
12944
  rowCommandsLiteral = "",
12941
- deleteDialogJsx = ""
12945
+ deleteDialogJsx = "",
12946
+ commandBarBlock = "",
12947
+ selectionModeAttr = "",
12948
+ onSelectionChangedAttr = ""
12942
12949
  } = args;
12943
12950
  const rowCommandsAttr = rowCommandsLiteral ? `
12944
12951
  rowCommands={[
@@ -12958,14 +12965,14 @@ const ${helperName}: React.FC = () => {
12958
12965
  if (isLoading) return <div style={{ padding: 16, color: '#605e5c' }}>Loading records\u2026</div>;
12959
12966
  if (error) return <div style={{ padding: 16, color: '#a4262c' }}>{error.message}</div>;
12960
12967
  return (
12961
- <div>
12968
+ <div>${commandBarBlock}
12962
12969
  <CardGrid
12963
12970
  items={rows}
12964
12971
  columns={[
12965
12972
  ${colEntries}
12966
12973
  ] as ColumnDef[]}
12967
12974
  registry={registry}
12968
- getKey={(it) => String((it as { __rowIndex?: number }).__rowIndex ?? '')}
12975
+ getKey={(it) => String((it as { __rowIndex?: number }).__rowIndex ?? '')}${selectionModeAttr}${onSelectionChangedAttr}
12969
12976
  card={{ ${cardConfigLiteral} }}${rowCommandsAttr}
12970
12977
  />${flatAggregateInner}${flatPaginationInner}${deleteDialogJsx}
12971
12978
  </div>
@@ -15092,6 +15099,10 @@ ${childEntries.join(",\n")},
15092
15099
  const flatHasDelete = contextMenuItems.some(
15093
15100
  (ci) => ci.actionType === "delete"
15094
15101
  );
15102
+ const flatHasCommandBar = gridCommandBarBlock.trim().length > 0;
15103
+ const flatBarHasDelete = barItems.some((ci) => ci.actionType === "delete");
15104
+ const flatSelectionModeAttr = ` selectionMode="${gridDef.selectionMode === "single" ? "single" : "multiple"}"`;
15105
+ const flatOnSelectionChangedAttr = "\n onSelectionChanged={(rows) => setSelectedIndices(new Set(rows.map((r) => Number((r as { __rowIndex?: number }).__rowIndex ?? -1))))}";
15095
15106
  if (gridDef.cardView?.enabled === true && gridDef.gridType !== "focused-view" && !isV9 && !isEditable) {
15096
15107
  const cardIsLive = _includeDataAccessLayer && hasLiveDataSource;
15097
15108
  const helperName = `${toSafeVarName(gridDef.name || entityName)}CardGrid`;
@@ -15109,16 +15120,21 @@ ${childEntries.join(",\n")},
15109
15120
  gridDef.dataSource.fetchXml || `<fetch top="25"><entity name="${gridDef.dataSource.entityName}"><all-attributes /></entity></fetch>`
15110
15121
  ) : "[]";
15111
15122
  const cardEmitRowCommands = cardIsLive && _handlerAvailable && flatHasContextMenu;
15112
- const cardHandlerBlock = cardEmitRowCommands ? buildGridCommandHandlerBlock({
15123
+ const cardEmitToolbar = cardIsLive && _handlerAvailable && flatHasCommandBar;
15124
+ const cardEmitHandler = cardEmitRowCommands || cardEmitToolbar;
15125
+ const cardHandlerBlock = cardEmitHandler ? buildGridCommandHandlerBlock({
15113
15126
  entityName: gridDef.dataSource.entityName,
15114
15127
  entitySetName: gridDef.dataSource.entitySetName,
15115
15128
  primaryIdAttribute: resolvePrimaryIdAttribute(gridDef),
15116
15129
  itemsExpr: "rows",
15117
15130
  selectionExpr: "selectedIndices"
15118
15131
  }) : "";
15119
- const cardSelectedIndicesState = cardEmitRowCommands ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15132
+ const cardSelectedIndicesState = cardEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15120
15133
  const cardRowCommandsLiteral = cardEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
15121
- const cardDeleteDialogJsx = cardEmitRowCommands && flatHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15134
+ const cardDeleteDialogJsx = cardEmitRowCommands && flatHasDelete || cardEmitToolbar && flatBarHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15135
+ const cardCommandBarBlock = cardEmitToolbar ? gridCommandBarBlock : "";
15136
+ const cardSelectionModeAttr = cardEmitToolbar ? flatSelectionModeAttr : "";
15137
+ const cardOnSelectionChangedAttr = cardEmitToolbar ? flatOnSelectionChangedAttr : "";
15122
15138
  const helperComponents = [
15123
15139
  buildCardSubgridBody({
15124
15140
  helperName,
@@ -15133,11 +15149,14 @@ ${childEntries.join(",\n")},
15133
15149
  selectedIndicesState: cardSelectedIndicesState,
15134
15150
  handlerBlock: cardHandlerBlock,
15135
15151
  rowCommandsLiteral: cardRowCommandsLiteral,
15136
- deleteDialogJsx: cardDeleteDialogJsx
15152
+ deleteDialogJsx: cardDeleteDialogJsx,
15153
+ commandBarBlock: cardCommandBarBlock,
15154
+ selectionModeAttr: cardSelectionModeAttr,
15155
+ onSelectionChangedAttr: cardOnSelectionChangedAttr
15137
15156
  })
15138
15157
  ];
15139
15158
  _usesGridKit = true;
15140
- const cardDataverseImport = cardEmitRowCommands ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery } from '../lib/dataverse';`;
15159
+ const cardDataverseImport = cardEmitHandler ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery } from '../lib/dataverse';`;
15141
15160
  if (cardDeleteDialogJsx) {
15142
15161
  imports.add("Dialog");
15143
15162
  imports.add("DialogType");
@@ -15149,7 +15168,7 @@ ${childEntries.join(",\n")},
15149
15168
  imports,
15150
15169
  v9Imports,
15151
15170
  v9IconImports,
15152
- extraImports: cardIsLive ? cardEmitRowCommands ? [
15171
+ extraImports: cardIsLive ? cardEmitHandler ? [
15153
15172
  cardDataverseImport,
15154
15173
  `import { useQueryClient } from '@tanstack/react-query';`,
15155
15174
  `import { CardGrid, createCellRegistry, type ColumnDef } from '../lib/grid-kit';`
@@ -15183,16 +15202,19 @@ ${childEntries.join(",\n")},
15183
15202
  );
15184
15203
  const gridKitColEntries = generateGridKitColumnEntries(visibleCols);
15185
15204
  const roEmitRowCommands = !isV9 && _handlerAvailable && flatHasContextMenu;
15186
- const roHandlerBlock = roEmitRowCommands ? buildGridCommandHandlerBlock({
15205
+ const roEmitToolbar = !isV9 && _handlerAvailable && flatHasCommandBar;
15206
+ const roEmitHandler = roEmitRowCommands || roEmitToolbar;
15207
+ const roHandlerBlock = roEmitHandler ? buildGridCommandHandlerBlock({
15187
15208
  entityName: gridDef.dataSource.entityName,
15188
15209
  entitySetName: gridDef.dataSource.entitySetName,
15189
15210
  primaryIdAttribute: resolvePrimaryIdAttribute(gridDef),
15190
15211
  itemsExpr: "rows",
15191
15212
  selectionExpr: "selectedIndices"
15192
15213
  }) : "";
15193
- const roSelectedIndicesState = roEmitRowCommands ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15214
+ const roSelectedIndicesState = roEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15194
15215
  const roRowCommandsLiteral = roEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
15195
15216
  const roDeleteDialogJsx = roEmitRowCommands && flatHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15217
+ const roCommandBarBlock = roEmitToolbar ? gridCommandBarBlock : "";
15196
15218
  const helperComponents = [
15197
15219
  buildLiveReadOnlySubgridBody({
15198
15220
  library,
@@ -15209,11 +15231,12 @@ ${childEntries.join(",\n")},
15209
15231
  selectedIndicesState: roSelectedIndicesState,
15210
15232
  handlerBlock: roHandlerBlock,
15211
15233
  rowCommandsLiteral: roRowCommandsLiteral,
15212
- deleteDialogJsx: roDeleteDialogJsx
15234
+ deleteDialogJsx: roDeleteDialogJsx,
15235
+ commandBarBlock: roCommandBarBlock
15213
15236
  })
15214
15237
  ];
15215
15238
  if (!isV9) _usesGridKit = true;
15216
- const roDataverseImport = roEmitRowCommands ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery } from '../lib/dataverse';`;
15239
+ const roDataverseImport = roEmitHandler ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery } from '../lib/dataverse';`;
15217
15240
  if (roDeleteDialogJsx) {
15218
15241
  imports.add("Dialog");
15219
15242
  imports.add("DialogType");
@@ -15225,7 +15248,7 @@ ${childEntries.join(",\n")},
15225
15248
  imports,
15226
15249
  v9Imports,
15227
15250
  v9IconImports,
15228
- extraImports: isV9 ? [`import { useDataverseQuery } from '../lib/dataverse';`] : roEmitRowCommands ? [
15251
+ extraImports: isV9 ? [`import { useDataverseQuery } from '../lib/dataverse';`] : roEmitHandler ? [
15229
15252
  roDataverseImport,
15230
15253
  `import { useQueryClient } from '@tanstack/react-query';`,
15231
15254
  `import { ReadOnlyGrid, createCellRegistry, type ColumnDef } from '../lib/grid-kit';`
@@ -15281,16 +15304,21 @@ const ${liveWrapperName}: React.FC = () => {
15281
15304
  onValueChange={(rowKey, fieldName, value) => commitCellEdit(Number(rowKey), fieldName, value)}` : "";
15282
15305
  const saveStatusJsx2 = editableUsesLiveData ? buildEditableSaveStatusJsx("updateMutation", "saveError") : "";
15283
15306
  const edEmitRowCommands = _handlerAvailable && editableUsesLiveData && !isV9 && flatHasContextMenu;
15284
- const edHandlerBlock = edEmitRowCommands ? buildGridCommandHandlerBlock({
15307
+ const edEmitToolbar = _handlerAvailable && editableUsesLiveData && !isV9 && flatHasCommandBar;
15308
+ const edEmitHandler = edEmitRowCommands || edEmitToolbar;
15309
+ const edHandlerBlock = edEmitHandler ? buildGridCommandHandlerBlock({
15285
15310
  entityName: gridDef.dataSource.entityName,
15286
15311
  entitySetName: gridDef.dataSource.entitySetName,
15287
15312
  primaryIdAttribute: resolvePrimaryIdAttribute(gridDef),
15288
15313
  itemsExpr: "keyedItems",
15289
15314
  selectionExpr: "selectedIndices"
15290
15315
  }) : "";
15291
- const edSelectedIndicesState = edEmitRowCommands ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15316
+ const edSelectedIndicesState = edEmitHandler ? "\n const [selectedIndices, setSelectedIndices] = React.useState<Set<number>>(new Set());" : "";
15292
15317
  const edRowCommandsLiteral = edEmitRowCommands ? buildRowCommandsLiteral(contextMenuItems) : "";
15293
- const edDeleteDialogJsx = edEmitRowCommands && flatHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15318
+ const edDeleteDialogJsx = edEmitRowCommands && flatHasDelete || edEmitToolbar && flatBarHasDelete ? buildGridDeleteDialogJsx(gridDef.dataSource?.entityName ?? entityName) : "";
15319
+ const edCommandBarBlock = edEmitToolbar ? gridCommandBarBlock : "";
15320
+ const edSelectionModeAttr = edEmitToolbar ? flatSelectionModeAttr : "";
15321
+ const edOnSelectionChangedAttr = edEmitToolbar ? flatOnSelectionChangedAttr : "";
15294
15322
  const editableSubgridBody2 = buildEditableSubgridBody({
15295
15323
  library,
15296
15324
  componentName,
@@ -15303,7 +15331,10 @@ const ${liveWrapperName}: React.FC = () => {
15303
15331
  selectedIndicesState: edSelectedIndicesState,
15304
15332
  handlerBlock: edHandlerBlock,
15305
15333
  rowCommandsLiteral: edRowCommandsLiteral,
15306
- deleteDialogJsx: edDeleteDialogJsx
15334
+ deleteDialogJsx: edDeleteDialogJsx,
15335
+ commandBarBlock: edCommandBarBlock,
15336
+ selectionModeAttr: edSelectionModeAttr,
15337
+ onSelectionChangedAttr: edOnSelectionChangedAttr
15307
15338
  });
15308
15339
  const helperComponents2 = [
15309
15340
  editableSubgridBody2,
@@ -15312,7 +15343,7 @@ const ${liveWrapperName}: React.FC = () => {
15312
15343
  const jsx3 = editableUsesLiveData && liveWrapperName ? `{/* Subgrid: ${safeEntityName} \u2014 ${safeGridName} (editable, live) */}${todoComment}
15313
15344
  <${liveWrapperName} />` : `{/* Subgrid: ${safeEntityName} \u2014 ${safeGridName} (editable) */}${todoComment}
15314
15345
  <${componentName} items={${itemsLiteral}} />`;
15315
- const edDataverseImport = edEmitRowCommands ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery, useUpdateRecord } from '../lib/dataverse';`;
15346
+ const edDataverseImport = edEmitHandler ? `import { useDataverseQuery, useUpdateRecord, useDeleteRecord } from '../lib/dataverse';` : `import { useDataverseQuery, useUpdateRecord } from '../lib/dataverse';`;
15316
15347
  if (edDeleteDialogJsx) {
15317
15348
  imports.add("Dialog");
15318
15349
  imports.add("DialogType");
@@ -15320,7 +15351,7 @@ const ${liveWrapperName}: React.FC = () => {
15320
15351
  imports.add("PrimaryButton");
15321
15352
  imports.add("DefaultButton");
15322
15353
  }
15323
- const extraImports2 = editableUsesLiveData ? edEmitRowCommands ? [
15354
+ const extraImports2 = editableUsesLiveData ? edEmitHandler ? [
15324
15355
  edDataverseImport,
15325
15356
  `import { useQueryClient } from '@tanstack/react-query';`,
15326
15357
  `import { DataGrid, createCellRegistry, type ColumnDef } from '../lib/grid-kit';`
@@ -22490,27 +22521,6 @@ function generatePcfProject(project, options) {
22490
22521
  2
22491
22522
  ) + "\n"
22492
22523
  });
22493
- const platformLibraries = isV9 ? ` <platform-library name="React" version="18.2.0" />
22494
- <platform-library name="Fluent" version="9.46.2" />` : ` <platform-library name="React" version="16.14.0" />
22495
- <platform-library name="Fluent" version="8.29.0" />`;
22496
- const nsAttr = escapeHtml(ns);
22497
- const controlNameAttr = escapeHtml(controlName);
22498
- files.push({
22499
- path: `${controlName}/ControlManifest.Input.xml`,
22500
- content: `<?xml version="1.0" encoding="utf-8" ?>
22501
- <manifest>
22502
- <control namespace="${nsAttr}" constructor="${controlNameAttr}" version="1.0.0" display-name-key="${controlNameAttr}" description-key="${controlNameAttr} PCF Control" control-type="virtual" >
22503
- <external-service-usage enabled="false">
22504
- </external-service-usage>
22505
- <property name="value" display-name-key="Value" description-key="Primary value" of-type="SingleLine.Text" usage="bound" required="false" />
22506
- <resources>
22507
- <code path="index.ts" order="1"/>
22508
- ${platformLibraries}
22509
- </resources>
22510
- </control>
22511
- </manifest>
22512
- `
22513
- });
22514
22524
  const mainForm = project.forms.find((f) => f.type === "main") ?? project.forms[0];
22515
22525
  const mainComponentName = mainForm ? toFormComponentName(mainForm.name) : "div";
22516
22526
  const pcfIndexContent = isV9 ? `import { IInputs, IOutputs } from './generated/ManifestTypes';
@@ -22518,7 +22528,7 @@ import * as React from 'react';
22518
22528
  import * as ReactDOM from 'react-dom';
22519
22529
  import { initializeIcons } from '@fluentui/react';
22520
22530
  import { FluentProvider, webLightTheme } from '@fluentui/react-components';
22521
- import { ${mainComponentName} } from './components/${mainComponentName}';
22531
+ import { ${mainComponentName} } from './src/components/${mainComponentName}';
22522
22532
 
22523
22533
  initializeIcons();
22524
22534
 
@@ -22558,7 +22568,7 @@ export class ${controlName} implements ComponentFramework.ReactControl<IInputs,
22558
22568
  import * as React from 'react';
22559
22569
  import * as ReactDOM from 'react-dom';
22560
22570
  import { initializeIcons, ThemeProvider } from '@fluentui/react';
22561
- import { ${mainComponentName} } from './components/${mainComponentName}';
22571
+ import { ${mainComponentName} } from './src/components/${mainComponentName}';
22562
22572
 
22563
22573
  initializeIcons();
22564
22574
 
@@ -22611,6 +22621,29 @@ export class ${controlName} implements ComponentFramework.ReactControl<IInputs,
22611
22621
  content: file.content
22612
22622
  });
22613
22623
  }
22624
+ const usesGridKit = formFiles.some((f) => f.path.startsWith("src/lib/grid-kit/"));
22625
+ const platformLibraries = isV9 ? ` <platform-library name="React" version="18.2.0" />
22626
+ <platform-library name="Fluent" version="9.46.2" />` : usesGridKit ? ` <platform-library name="React" version="18.2.0" />
22627
+ <platform-library name="Fluent" version="8.115.6" />` : ` <platform-library name="React" version="16.14.0" />
22628
+ <platform-library name="Fluent" version="8.29.0" />`;
22629
+ const nsAttr = escapeHtml(ns);
22630
+ const controlNameAttr = escapeHtml(controlName);
22631
+ files.push({
22632
+ path: `${controlName}/ControlManifest.Input.xml`,
22633
+ content: `<?xml version="1.0" encoding="utf-8" ?>
22634
+ <manifest>
22635
+ <control namespace="${nsAttr}" constructor="${controlNameAttr}" version="1.0.0" display-name-key="${controlNameAttr}" description-key="${controlNameAttr} PCF Control" control-type="virtual" >
22636
+ <external-service-usage enabled="false">
22637
+ </external-service-usage>
22638
+ <property name="value" display-name-key="Value" description-key="Primary value" of-type="SingleLine.Text" usage="bound" required="false" />
22639
+ <resources>
22640
+ <code path="index.ts" order="1"/>
22641
+ ${platformLibraries}
22642
+ </resources>
22643
+ </control>
22644
+ </manifest>
22645
+ `
22646
+ });
22614
22647
  if (includeDataAccessLayer) {
22615
22648
  const dalFiles = generateDataAccessLayer(
22616
22649
  project.forms,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataverse-kit/export-engine",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",