Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev-loops/CFB-setup-project.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
"# Commands",
"# ──────────────────────────────────────────────────────────────────────────────────────────",
"# Step 1: Create the Dataverse package for deployment.",
"dotnet new pp-talxis-pdpackage `",
"dotnet new pp-package `",
"--output \"src/${1:Packages.Main}\" `",
"--allow-scripts yes",
"",
Expand Down
4 changes: 2 additions & 2 deletions dev-loops/CFF-implement-data-model.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"",
"# Step 3: Add the solution project to the Package Deployer project as a .NET ProjectReference item.",
"cd src/Packages.Main",
"pac package add-reference --path ../${2:Solutions.DataModel}/",
"dotnet add \"./Packages.Main.csproj\" reference \"../${2:Solutions.DataModel}/${2:Solutions.DataModel}.csproj\"",
"cd ../..",
"",
]
Expand Down Expand Up @@ -331,4 +331,4 @@
"# Continue with the module steps by typing CFG..."
]
},
}
}
10 changes: 5 additions & 5 deletions dev-loops/CFG-implement-backend-logic.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"",
"# Step 2: Add the solution project to the Package Deployer project as a .NET ProjectReference item.",
"cd src/Packages.Main",
"pac package add-reference --path ../Solutions.Logic/",
"dotnet add \"./Packages.Main.csproj\" reference \"../Solutions.Logic/Solutions.Logic.csproj\"",
"cd ../..",
]
},
Expand Down Expand Up @@ -296,20 +296,20 @@
"# so that any changes made to the plugin code can be included in the solution package.",
"#",
"# You can run this anytime you add, remove, or refactor plugin logic. It keeps the",
"# Dataverse solution (cdsproj) up-to-date with project references.",
"# Dataverse solution (csproj) up-to-date with project references.",
"#",
"# ──────────────────────────────────────────────────────────────────────────────────────────",
"# Commands",
"# ──────────────────────────────────────────────────────────────────────────────────────────",
"cd src/Solutions.Logic",
"",
"# Step 1: Sync the Dataverse solution project to ensure .cdsproj is ready",
"# Step 1: Sync the Dataverse solution project to ensure .csproj is ready",
"pac solution sync --solution-folder Declarations",
"",
"# Step 2: Add reference to the plugin project",
"pac solution add-reference --path ../Plugins.Warehouse/Plugins.Warehouse.csproj",
"dotnet add reference ../Plugins.Warehouse/Plugins.Warehouse.csproj",
"",
"cd ../..",
]
}
}
}
14 changes: 9 additions & 5 deletions dev-loops/CFI-implement-ui-layer.code-snippets
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"",
"# Step 2: Add the solution project to the Package Deployer project as a .NET ProjectReference item.",
"cd src/Packages.Main",
"pac package add-reference --path ../Solutions.UI/",
"dotnet add \"./Packages.Main.csproj\" reference \"../Solutions.UI/Solutions.UI.csproj\"",
"cd ../..",
"",
"# Step 3: Link existing entities from the data model.",
Expand Down Expand Up @@ -851,8 +851,7 @@
"# ──────────────────────────────────────────────────────────────────────────────────────────",
"# Step 1: Create the Script Library in the existing UI solution",
"dotnet new pp-script-library `",
"--output \"src/UI.Scripts\" `",
"--LibraryName \"main\" `",
"--output \"src/UI.Scripts\" ",
"",
"# Step 2: Create TypeScript files for warehouse transaction functionality",
"mkdir src/UI.Scripts/TS/scripts",
Expand All @@ -869,7 +868,12 @@
"",
"# Open files in VS Code for editing",
"code \"src/UI.Scripts/TS/scripts/OpenWarehouseTransactionDialog.ts\"",
"code \"src/UI.Scripts/TS/scripts/SaveWarehouseTransactionData.ts\""
"code \"src/UI.Scripts/TS/scripts/SaveWarehouseTransactionData.ts\"",
"",
"# Add references to the script libraries",
"cd src/Solutions.UI",
"dotnet add reference ../UI.Scripts/UI.Scripts.csproj",
"cd ../..",
]
},
"Open Warehouse Transaction Dialog Script": {
Expand Down Expand Up @@ -1035,4 +1039,4 @@
"--allow-scripts yes"
]
},
}
}
295 changes: 295 additions & 0 deletions dev-loops/CFJ-pcf.code-snippets
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
{
"Scaffold QuantityIndicator PCF": {
"scope": "powershell",
"prefix": "GFJ01-scaffold-quantity-indicator-pcf",
"body": [
"#",
"# ╔════════════════════════════════════════════════════════════════════════════════════════╗",
"# ║ GFJ01: Scaffold QuantityIndicator PCF control (field) ║",
"# ╚════════════════════════════════════════════════════════════════════════════════════════╝",
"# This snippet scaffolds a Dataverse field PCF control named QuantityIndicator.",
"# It runs `pac pcf init` under namespace UdppControls, seeds placeholders so",
"# and opens key files for editing.",
"# Finally, it links the .pcfproj into Solutions.UI so the control",
"# is packaged with the UI solution.",
"# ──────────────────────────────────────────────────────────────────────────────────────────",
"# Commands",
"# ──────────────────────────────────────────────────────────────────────────────────────────",
"# Step 1: Init PCF control structure",
"mkdir src/Controls.QuantityIndicator",
"cd src/Controls.QuantityIndicator",
"",
"pac pcf init --namespace UdppControls --name QuantityIndicator --template field",
"",
"# Step 2: Install npm dependencies",
"npm install",
"",
"# Step 3: Create css folder + placeholder files (for GFJ02–GFJ04 snippets)",
"mkdir QuantityIndicator/css",
"New-Item -Path . -Name \"QuantityIndicator/css/QuantityIndicator.css\" -ItemType \"File\" | Out-Null",
"",
"\"<!-- type GFJ02 and then press control+space to trigger suggestions of snippets -->\" | Out-File -FilePath \"QuantityIndicator/ControlManifest.Input.xml\" -Encoding UTF8",
"\"/* type GFJ03 and then press control+space to trigger suggestions of snippets */\" | Out-File -FilePath \"QuantityIndicator/css/QuantityIndicator.css\" -Encoding UTF8",
"\"// type GFJ04 and then press control+space to trigger suggestions of snippets \" | Out-File -FilePath \"QuantityIndicator/index.ts\" -Encoding UTF8",
"",
"# Step 4: Open key files in VS Code",
"code QuantityIndicator/ControlManifest.Input.xml",
"code QuantityIndicator/index.ts",
"",
"# Step 5: Link PCF project into Solutions.UI",
"cd ../..",
"cd src/Solutions.UI",
"dotnet add reference ../Controls.QuantityIndicator/Controls.QuantityIndicator.pcfproj",
"cd ../.."
]
},
"QuantityIndicator manifest.xml": {
"prefix": "GFJ02-quantity-indicator-manifest-xml",
"scope": "xml",
"body": [
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>",
"<manifest>",
" <control namespace=\"UdppControls\"",
" constructor=\"QuantityIndicator\"",
" version=\"0.0.2\"",
" display-name-key=\"Quantity Indicator\"",
" description-key=\"A colorful badge indicator for quantity fields\"",
" control-type=\"standard\">",
"",
" <external-service-usage enabled=\"false\">",
" </external-service-usage>",
"",
" <property name=\"quantity\"",
" display-name-key=\"Quantity\"",
" description-key=\"The quantity value to display\"",
" of-type=\"Whole.None\"",
" usage=\"bound\"",
" required=\"true\" />",
"",
" <resources>",
" <code path=\"index.ts\" order=\"1\" />",
" <css path=\"css/QuantityIndicator.css\" order=\"1\" />",
" </resources>",
" </control>",
"</manifest>"
]
},
"Quantity badge CSS": {
"prefix": "GFJ03-quantity-badge-css",
"scope": "css",
"body": [
".quantity-badge-wrapper {",
" display: inline-flex;",
" align-items: center;",
" gap: 8px;",
" width: 100%;",
" height: 100%;",
" min-height: 32px;",
" font-family: \"Segoe UI\", Tahoma, Geneva, Verdana, sans-serif;",
"}",
"",
".quantity-badge__input {",
" flex: 1;",
" height: 32px;",
" padding: 4px 8px;",
" font-size: 14px;",
" border: 1px solid #a0a0a0;",
" border-radius: 4px;",
" outline: none;",
" box-sizing: border-box;",
" -moz-appearance: textfield;",
"}",
"",
".quantity-badge__input::-webkit-inner-spin-button,",
".quantity-badge__input::-webkit-outer-spin-button {",
" -webkit-appearance: none;",
" margin: 0;",
"}",
"",
".quantity-badge__input:focus {",
" border-color: #2266e3;",
" box-shadow: 0 0 0 1px #2266e3;",
"}",
"",
".quantity-badge__input--disabled {",
" background-color: #f3f3f3;",
" color: #666;",
" cursor: not-allowed;",
"}",
"",
".quantity-badge {",
" display: inline-flex;",
" align-items: center;",
" justify-content: center;",
" width: 28px;",
" height: 28px;",
" border-radius: 50%;",
" font-size: 14px;",
" flex-shrink: 0;",
"}",
"",
".quantity-badge--red {",
" background-color: #fdecea;",
" color: #c0392b;",
" border: 2px solid #e74c3c;",
"}",
"",
".quantity-badge--yellow {",
" background-color: #fef9e7;",
" color: #b7791f;",
" border: 2px solid #f39c12;",
"}",
"",
".quantity-badge--green {",
" background-color: #eafaf1;",
" color: #1e8449;",
" border: 2px solid #2ecc71;",
"}"
]
},

"QuantityIndicator PCF TS": {
"prefix": "GFJ04-quantity-indicator-ts",
"scope": "typescript",
"body": [
"import { IInputs, IOutputs } from \"./generated/ManifestTypes\";",
"",
"export class QuantityIndicator",
" implements ComponentFramework.StandardControl<IInputs, IOutputs>",
"{",
" private _container: HTMLDivElement;",
" private _input: HTMLInputElement;",
" private _badge: HTMLSpanElement;",
" private _badgeIcon: HTMLSpanElement;",
" private _value: number | null;",
" private _notifyOutputChanged: () => void;",
"",
" constructor() {",
" // noop",
" }",
"",
" public init(",
" context: ComponentFramework.Context<IInputs>,",
" notifyOutputChanged: () => void,",
" _state: ComponentFramework.Dictionary,",
" container: HTMLDivElement",
" ): void {",
" this._notifyOutputChanged = notifyOutputChanged;",
" this._container = container;",
"",
" const wrapper = document.createElement(\"div\");",
" wrapper.classList.add(\"quantity-badge-wrapper\");",
"",
" // Editable input",
" this._input = document.createElement(\"input\");",
" this._input.type = \"number\";",
" this._input.classList.add(\"quantity-badge__input\");",
" this._input.addEventListener(\"change\", this._onInputChange.bind(this));",
" this._input.addEventListener(\"input\", this._onInputLive.bind(this));",
"",
" // Color badge icon",
" this._badgeIcon = document.createElement(\"span\");",
" this._badgeIcon.classList.add(\"quantity-badge__icon\");",
"",
" // Color badge",
" this._badge = document.createElement(\"span\");",
" this._badge.classList.add(\"quantity-badge\");",
"",
" wrapper.appendChild(this._input);",
" wrapper.appendChild(this._badge);",
" this._container.appendChild(wrapper);",
"",
" this._setValue(context.parameters.quantity.raw);",
" }",
"",
" public updateView(context: ComponentFramework.Context<IInputs>): void {",
" const incoming = context.parameters.quantity.raw;",
" if (incoming !== this._value) {",
" this._setValue(incoming);",
" }",
"",
" // Respect disabled state from the form",
" const isDisabled = context.mode.isControlDisabled;",
" this._input.disabled = isDisabled;",
" if (isDisabled) {",
" this._input.classList.add(\"quantity-badge__input--disabled\");",
" } else {",
" this._input.classList.remove(\"quantity-badge__input--disabled\");",
" }",
" }",
"",
" public getOutputs(): IOutputs {",
" return { quantity: this._value ?? undefined };",
" }",
"",
" public destroy(): void {",
" // noop",
" }",
"",
" private _onInputChange(): void {",
" const parsed = parseInt(this._input.value, 10);",
" this._value = isNaN(parsed) ? null : parsed;",
" this._updateBadge(this._value);",
" this._notifyOutputChanged();",
" }",
"",
" private _onInputLive(): void {",
" const parsed = parseInt(this._input.value, 10);",
" this._updateBadge(isNaN(parsed) ? null : parsed);",
" }",
"",
" private _setValue(raw: number | null): void {",
" this._value = raw;",
" this._input.value = raw != null ? raw.toString() : \"\";",
" this._updateBadge(raw);",
" }",
"",
" private _updateBadge(val: number | null): void {",
" const tier = this._getTier(val);",
" this._badge.className = \"quantity-badge\";",
" this._badge.classList.add(`quantity-badge--${tier.color}`);",
" this._badge.textContent = tier.icon;",
" }",
"",
" private _getTier(val: number | null): { color: string; icon: string } {",
" if (val == null || val <= 0) return { color: \"red\", icon: \"\\u26A0\" };",
" if (val <= 2) return { color: \"yellow\", icon: \"\\u25CF\" };",
" return { color: \"green\", icon: \"\\u2714\" };",
" }",
"}"
]
},
"Attach PCF Control to Form (Generic)": {
"scope": "powershell",
"prefix": "GFJ05-attach-pcf-to-form",
"body": [
"#",
"# ╔════════════════════════════════════════════════════════════════════════════════════════╗",
"# ║ GFJ05: Attach a PCF Custom Control to an Entity Form (Generic Template) ║",
"# ╚════════════════════════════════════════════════════════════════════════════════════════╝",
"#",
"# This snippet uses the universal pp-customcontrol-generic template to attach any PCF",
"# control to a Dataverse form. It adds the controlDescriptions block with a default",
"# fallback and a formFactor-specific customControl entry. Run once per formFactor",
"# (0 = Web, 1 = Tablet, 2 = Phone) to cover all form factors.",
"#",
"# ──────────────────────────────────────────────────────────────────────────────────────────",
"# Commands",
"# ──────────────────────────────────────────────────────────────────────────────────────────",
"# Step 1: Attach PCF control for Web (formFactor 0)",
"dotnet new pp-customcontrol-generic `",
"--output \"src/Solutions.UI\" `",
"--CustomControlName \"${1:UdppControls.QuantityIndicator}\" `",
"--CustomControlParameters \"[{name:quantity }, {type:Whole.None},{value:udpp_availablequantity}]\" `",
"--PublisherPrefix \"$${publisherPrefix}\" `",
"--CustomControlFormFactor \"0\" `",
"--FieldLogicalName \"${3:udpp_availablequantity}\" `",
"--SolutionRootPath \"Declarations\" `",
"--EntitySchemaName \"${4:udpp_warehouseitem}\" `",
"--FormType \"${5:main}\" `",
"--FormId $$warehouseitemFormGuid `",
"--allow-scripts yes",
"",
]
},
}
Loading