From 1150a6f36540fbc991e83303f2e309f25d474752 Mon Sep 17 00:00:00 2001 From: Eugene Meidinger Date: Sun, 1 Feb 2026 14:19:53 -0500 Subject: [PATCH 1/3] fix: correct spelling errors across documentation Spelling corrections identified and validated through a multi-stage process: 1. Automated detection using pyspellchecker library 2. False positive filtering via fine-tuned LLM classifier (Gemma3:4b via Ollama, GEPA-optimized) 3. Automated fixes applied by Claude Opus 4.5 4. Final human review and approval --- content/features/CSharpScripts/csharp-script-library.md | 2 +- content/features/Command-line-Options.md | 6 +++--- content/features/Useful-script-snippets.md | 4 ++-- content/features/Workspace-Database.md | 2 +- content/features/csharp-scripts.md | 2 +- content/features/dax-editor.md | 2 +- content/features/dax-optimizer-integration.md | 2 +- content/features/dax-query.md | 2 +- content/features/dax-scripts.md | 2 +- content/features/import-tables.partial.md | 2 +- content/features/save-to-folder.md | 2 +- content/features/semantic-bridge.md | 4 ++-- content/features/views/tom-explorer-view.md | 8 ++++---- content/features/views/user-interface.md | 2 +- content/features/workspace-mode.partial.md | 2 +- content/getting-started/Getting-Started-te2.md | 6 +++--- content/getting-started/Power-BI-Desktop-Integration.md | 2 +- content/getting-started/boosting-productivity-te3.md | 2 +- content/getting-started/bpa.md | 2 +- content/getting-started/creating-and-testing-dax.md | 2 +- content/getting-started/cs-scripts-and-macros.md | 2 +- content/getting-started/dax-script-introduction.md | 2 +- content/getting-started/desktop-limitations.md | 4 ++-- content/getting-started/editions.md | 4 ++-- content/getting-started/general-introduction.md | 2 +- content/getting-started/getting-started.md | 6 +++--- content/getting-started/importing-tables-data-modeling.md | 2 +- content/getting-started/migrate-from-desktop.md | 2 +- content/getting-started/migrate-from-te2.md | 4 ++-- content/getting-started/migrate-from-vs.md | 4 ++-- content/getting-started/parallel-development.md | 8 ++++---- content/getting-started/personalizing-te3.md | 4 ++-- content/how-tos/Advanced-Scripting.md | 2 +- content/how-tos/folder-serialization.md | 2 +- content/how-tos/perspectives-translations.md | 4 ++-- content/how-tos/undo-redo.md | 2 +- content/index.md | 2 +- content/kb/bpa-format-string-measures.md | 2 +- content/kb/bpa-powerbi-latest-compatibility.md | 4 ++-- content/kb/bpa-trim-object-names.md | 4 ++-- content/kb/bpa-visible-objects-no-description.md | 2 +- content/references/Roadmap2-h.md | 4 ++-- content/references/TabularEditor.TOMWrapper-h.md | 4 ++-- content/references/application-language.md | 2 +- content/references/release-notes/3_12_0.md | 2 +- content/references/release-notes/3_12_1.md | 2 +- content/references/release-notes/3_22_0.md | 2 +- content/references/release-notes/3_22_1.md | 2 +- content/references/release-notes/3_23_0.md | 2 +- content/references/release-notes/3_2_1.md | 2 +- content/references/release-notes/3_4_0.md | 6 +++--- content/references/supported-files.md | 6 +++--- content/security/security-privacy.md | 2 +- content/troubleshooting/proxy-settings.md | 2 +- content/tutorials/data-security/data-security-about.md | 2 +- .../incremental-refresh/incremental-refresh-setup.md | 2 +- content/tutorials/new-as-model.md | 6 +++--- content/tutorials/udfs.md | 2 +- 58 files changed, 88 insertions(+), 88 deletions(-) diff --git a/content/features/CSharpScripts/csharp-script-library.md b/content/features/CSharpScripts/csharp-script-library.md index ca88089d..1db6065f 100644 --- a/content/features/CSharpScripts/csharp-script-library.md +++ b/content/features/CSharpScripts/csharp-script-library.md @@ -17,7 +17,7 @@ There are also other resources online with C# Scripts that are maintained by the ## Tabular Editor Versions -The top of each article denotes script compatability in TE2.x (Tabular Editor 2) and/or TE3.x (Tabular Editor 3) +The top of each article denotes script compatibility in TE2.x (Tabular Editor 2) and/or TE3.x (Tabular Editor 3) ### Scripting with Tabular Editor as a Power BI External Tool

diff --git a/content/features/Command-line-Options.md b/content/features/Command-line-Options.md index a9bafeb0..b4314315 100644 --- a/content/features/Command-line-Options.md +++ b/content/features/Command-line-Options.md @@ -304,8 +304,8 @@ The command line provides various details, depending on the switches used and an |Warning|-ANALYZE|... violates rule ...|Best Practice Analyzer results for rules of severity level 2.| |Error|-ANALYZE|... violates rule ...|Best Practice Analyzer results for rules of severity level 3 or higher.| |Error|-DEPLOY|Deployment failed! ...|Failure reason returned directly from Analysis Service instance (for example: Database not found, Database override not allowed, etc.)| -|Information|-DEPLOY|Unprocessed object: ...|Objects that are in state "NoData" or "CalculationNeeded" after succesful deployment. Use the -W switch to treat these as Level=Warning.| -|Warning|-DEPLOY|Object not in "Ready" state: ...|Objects that are in state "DependencyError", "EvaluationError" or "SemanticError" after succesful deployment. If using the -W switch, also includes objects in state "NoData" or "CalculationNeeded".| -|Warning|-DEPLOY|Error on X:...|Objects containing invalid DAX after succesful deployment (measures, calculated columns, calculated tables, roles). Use the -E switch to treat these as Level=Error.| +|Information|-DEPLOY|Unprocessed object: ...|Objects that are in state "NoData" or "CalculationNeeded" after successful deployment. Use the -W switch to treat these as Level=Warning.| +|Warning|-DEPLOY|Object not in "Ready" state: ...|Objects that are in state "DependencyError", "EvaluationError" or "SemanticError" after successful deployment. If using the -W switch, also includes objects in state "NoData" or "CalculationNeeded".| +|Warning|-DEPLOY|Error on X:...|Objects containing invalid DAX after successful deployment (measures, calculated columns, calculated tables, roles). Use the -E switch to treat these as Level=Error.| If any of the "Error" level outputs are encountered, Tabular Editor will return Exit Code = 1. Otherwise 0. diff --git a/content/features/Useful-script-snippets.md b/content/features/Useful-script-snippets.md index 49c3fa56..20f478c5 100644 --- a/content/features/Useful-script-snippets.md +++ b/content/features/Useful-script-snippets.md @@ -349,7 +349,7 @@ var tsv = ExportProperties(Model.AllMeasures, "Name,InPerspective[Inventory]"); SaveFile(@"c:\Project\MeasurePerspectiveInventory.tsv", tsv); ``` -Similarly, for translations, annotations, etc. For example, if you wanted to see all danish translations applied to tables, columns, hierarchies, levells and measures: +Similarly, for translations, annotations, etc. For example, if you wanted to see all danish translations applied to tables, columns, hierarchies, levels and measures: ```csharp // Construct a list of objects: @@ -856,7 +856,7 @@ If you are working with a Power BI-based model that uses Power Query (M) express To solve this issue, you can run the following script on your model, to replace the power query partitions with corresponding native SQL query partitions, and to create a legacy (provider) data source on the model, which will work with Tabular Editor 2's Import Data wizard: -There are two versions of the script: The first one uses the MSOLEDBSQL provider for the created legacy data source, and hardcoded credentials. This is useful for local development. The second one uses the SQLNCLI provider, which is available on Microsoft-hosted build agents on Azure DevOps, and reads credentials and server/database names from environment variables, making the script useful for integration in Azure Pipeliens. +There are two versions of the script: The first one uses the MSOLEDBSQL provider for the created legacy data source, and hardcoded credentials. This is useful for local development. The second one uses the SQLNCLI provider, which is available on Microsoft-hosted build agents on Azure DevOps, and reads credentials and server/database names from environment variables, making the script useful for integration in Azure Pipelines. MSOLEDBSQL version, which reads connection information from M partitions and prompts for user name and password through Azure AD: ```csharp diff --git a/content/features/Workspace-Database.md b/content/features/Workspace-Database.md index ea2c4d29..6e216958 100644 --- a/content/features/Workspace-Database.md +++ b/content/features/Workspace-Database.md @@ -39,7 +39,7 @@ If you want to use and existing database as your workspace database, simply sele To track the workspace settings for each model in your file system, Tabular Editor 3.0 introduces a new file of type .tmuo (short for Tabular Model User Options), which will be placed next to the Model.bim or Database.json file. -The .tmuo file is just a simple json document with the following content: +The .tmuo file is just a simple JSON document with the following content: ```json { diff --git a/content/features/csharp-scripts.md b/content/features/csharp-scripts.md index 29fa09bc..bc45ef22 100644 --- a/content/features/csharp-scripts.md +++ b/content/features/csharp-scripts.md @@ -116,7 +116,7 @@ Selected.Measures .Rename("Amount", "Value"); ``` -This would replace any occurence of the word "Amount" with the word "Value" in the names of all currently selected measures. +This would replace any occurrence of the word "Amount" with the word "Value" in the names of all currently selected measures. Alternatively, we may use the LINQ ForEach()-method, as described above, to include more advanced logic: ```csharp diff --git a/content/features/dax-editor.md b/content/features/dax-editor.md index 2d70107f..b078c22f 100644 --- a/content/features/dax-editor.md +++ b/content/features/dax-editor.md @@ -64,7 +64,7 @@ For DAX scripts and DAX queries, it is sometimes useful to include the definitio # Inline Measure -If you want to bring the definition of a measure into the current document, the **Inline Measure** feature lets you do just that. When a row context is surronding the original measure reference, Tabular Editor automatically surrounds the measure expression with [`CALCULATE`](https://dax.guide/calculate) (which is implicit in measure references). +If you want to bring the definition of a measure into the current document, the **Inline Measure** feature lets you do just that. When a row context is surrounding the original measure reference, Tabular Editor automatically surrounds the measure expression with [`CALCULATE`](https://dax.guide/calculate) (which is implicit in measure references). # Format DAX diff --git a/content/features/dax-optimizer-integration.md b/content/features/dax-optimizer-integration.md index ea6a7dcc..0775367c 100644 --- a/content/features/dax-optimizer-integration.md +++ b/content/features/dax-optimizer-integration.md @@ -101,7 +101,7 @@ Once you click the **OK** button, the VPAX file will be uploaded to DAX Optimize By default, VPAX files uploaded using Tabular Editor 3 will be obfuscated. In the **Upload Model** you may toggle obfuscation on/off for new model uploads. Subsequent model version uploads will be obfuscated or not depending on the first version upload. You can also export an obfuscated VPAX file locally without uploading to DAX Optimizer through the **VertiPaq Analyzer** view. In this case, a dictionary file is generated and stored on your local machine, next to the exported .ovpax file. This dictionary file is used to deobfuscate the contents of the .ovpax file. -When obfuscated VPAX data is uploaded to the DAX Optimizer service through the **DAX Optimizer** view, Tabular Editor automatically keeps track of obfuscation dictionaries by storing them in the `%LocalAppData%\TabularEditor3\DaxOptimizer` folder on your local machine. As such, when browsing models using the **DAX Optimizer** feature in Tabular Editor 3, models are automatically deobfuscated if a suitable dictionary is found in this folder, providing a more seemless experience when using obfuscation. +When obfuscated VPAX data is uploaded to the DAX Optimizer service through the **DAX Optimizer** view, Tabular Editor automatically keeps track of obfuscation dictionaries by storing them in the `%LocalAppData%\TabularEditor3\DaxOptimizer` folder on your local machine. As such, when browsing models using the **DAX Optimizer** feature in Tabular Editor 3, models are automatically deobfuscated if a suitable dictionary is found in this folder, providing a more seamless experience when using obfuscation. If the dictionary is not found, you will have an option to manually specify a dictionary file. diff --git a/content/features/dax-query.md b/content/features/dax-query.md index 07ec5bb0..edb1a9fe 100644 --- a/content/features/dax-query.md +++ b/content/features/dax-query.md @@ -67,7 +67,7 @@ Unlike the [DAX Script feature](xrefid:dax-scripts), only the expression propert The "Apply" option has also been added to the right-click context menu. -![Dax Query Apple Right Click](~/content/assets/images/features/dax_query_window/dax_query_apply_measure_right_click.png) +![Dax Query Apply Right Click](~/content/assets/images/features/dax_query_window/dax_query_apply_measure_right_click.png) The shortcuts for these commands are: diff --git a/content/features/dax-scripts.md b/content/features/dax-scripts.md index 0b863b0d..28651825 100644 --- a/content/features/dax-scripts.md +++ b/content/features/dax-scripts.md @@ -45,7 +45,7 @@ DAX scripts can be saved as text files, using the `.te3daxs` file extension. To The DAX script editor has all the capabilities of the DAX editor used elsewhere in Tabular Editor 3. Specifically, auto-complete, auto-formatting, calltips, etc. -In addition, to easily manage large DAX scripts, two dropdowns are displayed at the top of the DAX script view. The dropdown on the left allows you to jump between objects defined in the script, where as the dropdown on the right allows you to jump between properties on the current object. +In addition, to easily manage large DAX scripts, two dropdowns are displayed at the top of the DAX script view. The dropdown on the left allows you to jump between objects defined in the script, whereas the dropdown on the right allows you to jump between properties on the current object. ![Dax Script Navigation](~/content/assets/images/dax-script-navigation.png) diff --git a/content/features/import-tables.partial.md b/content/features/import-tables.partial.md index 6a573a65..046331c7 100644 --- a/content/features/import-tables.partial.md +++ b/content/features/import-tables.partial.md @@ -156,4 +156,4 @@ Using this technique, Tabular Editor 3 makes it possible to import and update ta ### Importing new tables through Analysis Services -In order to import a table from a data source otherwise not suported, you can simply copy an existing table from that data source, modify the M expression on the partition query of the copied table, then save your changes to the workspace database and update the table schema as described above. +In order to import a table from a data source otherwise not supported, you can simply copy an existing table from that data source, modify the M expression on the partition query of the copied table, then save your changes to the workspace database and update the table schema as described above. diff --git a/content/features/save-to-folder.md b/content/features/save-to-folder.md index cb0ff125..c3c88c17 100644 --- a/content/features/save-to-folder.md +++ b/content/features/save-to-folder.md @@ -52,7 +52,7 @@ The tabs General and Save-to-folder contains settings regarding the serializatio Tabular Editor 3 has a default setting for JSON serialization and you must actively choose a different setting in serialization mode, which is also where you change to the TMDL format. *** ### Serialization Model Annotation -Tabular Editor saves the serialization settings on your model so that they will always stay the same no matter who is working on the model. This ensures that a developer's local preferences do not overwrite model's setting and lead to a unmanageable merge in your source control. You can find these annotations in the TOM Explorer properties of the Model > Annotations > TabularEditor_SerializeOptions +Tabular Editor saves the serialization settings on your model so that they will always stay the same no matter who is working on the model. This ensures that a developer's local preferences do not overwrite model's setting and lead to an unmanageable merge in your source control. You can find these annotations in the TOM Explorer properties of the Model > Annotations > TabularEditor_SerializeOptions

![TE3 Preferences](~/content/assets/images/common/SaveToFolderModelAnnotation.png) diff --git a/content/features/semantic-bridge.md b/content/features/semantic-bridge.md index e74bb2af..1c5ff4ea 100644 --- a/content/features/semantic-bridge.md +++ b/content/features/semantic-bridge.md @@ -194,7 +194,7 @@ Because of this, we have adopted the following definitions and standards in our ### General dimensional modeling terminology There are many terms that exist generally in discussion of a dimensional model or semantic model and also in a specific platform's object model and serialization formats. -For example, the term "measure" refers generically to a quantitative value that is aggregated in a dimensional model to represent a business metric of interest, but it also refers to a specific kind of object in both Databricks Metric Views and Tabular models; in a Metric View, a measure is a named SQL expression that defines an aggregation in the Metric View, and in a Tabular model a measure is a named DAX expression tat defines an aggregation in the Tabular model. +For example, the term "measure" refers generically to a quantitative value that is aggregated in a dimensional model to represent a business metric of interest, but it also refers to a specific kind of object in both Databricks Metric Views and Tabular models; in a Metric View, a measure is a named SQL expression that defines an aggregation in the Metric View, and in a Tabular model a measure is a named DAX expression that defines an aggregation in the Tabular model. It is impossible to discuss the work of the Semantic Bridge without talking about multiple meanings of such words at once. For example, we talk about translating a Metric View measure to a Tabular measure. As such, **we always refer to an object in a specific platform's model by saying the platform and the object, e.g. "Metric View measure" or "Tabular measure"**. @@ -209,7 +209,7 @@ We refer to the names of Metric View objects based on their representation in YA |----------------------|-----------------|-----------------------|------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | fact | table | source | A table holding foreign keys to dimensions and quantitative values to be aggregated | a Metric View has a single fact which is unnamed and captured as the root-level `source` attribute in YAML. Tabular models do not differentiate between types of tables: whether a table is a fact can only be inferred | | dimension | table | join | A table holding descriptive attributes and one primary key to which the fact is related | Tabular models do not differentiate, so the role of "dimension" is inferred only, as with a fact. | -| partition | parition | source (join only) | An object for data management, holding a subset of data in a table | Tabular model tables can have many partitions and must have at least one. The Metric View fact, as mentioned above is defined purely as a source, but Metric View joins also have a `source` property, which acts roughly like a partition | +| partition | partition | source (join only) | An object for data management, holding a subset of data in a table | Tabular model tables can have many partitions and must have at least one. The Metric View fact, as mentioned above is defined purely as a source, but Metric View joins also have a `source` property, which acts roughly like a partition | | field | column | dimension | A column in a table | | | measure | measure | measure | A quantitative value that is aggregated according to business logic in the model | Measures in a Tabular model are written in DAX, and in a Metric View in SQL | | join or relationship | relationship | join.on or join.using | A correspondence between key fields in two tables, a foreign key in one and primary key in the other | Relationships are explicit objects in a Tabular model, and implicitly defined as a property of the `join` object in Metric View YAML | diff --git a/content/features/views/tom-explorer-view.md b/content/features/views/tom-explorer-view.md index 2d037ed8..17e5b981 100644 --- a/content/features/views/tom-explorer-view.md +++ b/content/features/views/tom-explorer-view.md @@ -147,12 +147,12 @@ The toolbar allow you to show and hide different types of objects, toggling pers 11. **Language Selector** Allows switching between different languages for model metadata localization. -12. **Colapse All** - Collaps all nodes in the TOM Explorer tree view. +12. **Collapse All** + Collapses all nodes in the TOM Explorer tree view. 13. **Search Bar** -12. **Colapse All** - Collaps all nodes in the TOM Explorer tree view. +12. **Collapse All** + Collapses all nodes in the TOM Explorer tree view. 13. **Search Bar** Provides real-time filtering and navigation within the TOM Explorer. Type to search across all visible model objects. \ No newline at end of file diff --git a/content/features/views/user-interface.md b/content/features/views/user-interface.md index 22a48e4d..d7fc1c35 100644 --- a/content/features/views/user-interface.md +++ b/content/features/views/user-interface.md @@ -82,7 +82,7 @@ The **File** menu primarily contains menu items for dealing with loading and sav ![File Menu New](~/content/assets/images/file-menu-new.png) > [!IMPORTANT] -> The **New > Model...** option is not available in Tabular Editor 3 Desktop Edition, as this edition may only be used as an External Tool for Poewr BI Desktop. [More information](xref:editions). +> The **New > Model...** option is not available in Tabular Editor 3 Desktop Edition, as this edition may only be used as an External Tool for Power BI Desktop. [More information](xref:editions). - **Open**: Opens a submenu with options for loading a data model from various sources, as well as on option for loading any other type of file. The submenu items are: diff --git a/content/features/workspace-mode.partial.md b/content/features/workspace-mode.partial.md index f2ef2823..8095a05d 100644 --- a/content/features/workspace-mode.partial.md +++ b/content/features/workspace-mode.partial.md @@ -38,7 +38,7 @@ Leaving this checked, you will be prompted to connect to an instance of Analysis > [!IMPORTANT] > If you plan to deploy your workspace database to the Power BI Service XMLA endpoint, make sure you choose Compatibility Level 1609 (Power BI / Fabric) in the dialog above. -After entering the Analysis Services server details and (optional) credentials, you are shown a list of all databases currently reciding on the server (or for a Power BI workspace, the list of datasets deployed to the workspace): +After entering the Analysis Services server details and (optional) credentials, you are shown a list of all databases currently residing on the server (or for a Power BI workspace, the list of datasets deployed to the workspace): ![Select Workspace Database](~/content/assets/images/select-workspace-database.png) diff --git a/content/getting-started/Getting-Started-te2.md b/content/getting-started/Getting-Started-te2.md index a8da12d3..b825ab8e 100644 --- a/content/getting-started/Getting-Started-te2.md +++ b/content/getting-started/Getting-Started-te2.md @@ -50,9 +50,9 @@ On the top right side of the main UI, you see the DAX Editor, which may be used Use the property grid in the lower right corner, to examine and set properties of objects, such as Format String, Description along with translations and perspective memberships. You can also set the Display Folder property here, but it's easier to simply drag and drop objects within the tree to update their Display Folder (try selecting multiple objects using CTRL or SHIFT). -To edit perspectives or translations (cultures), select the "Model" object in the tree, and locate the "Model Perspectives" or "Model Cultures" properties, in the property grid. Click the small elipsis button to open a collection editor for adding/removing/editing perspectives/cultures. +To edit perspectives or translations (cultures), select the "Model" object in the tree, and locate the "Model Perspectives" or "Model Cultures" properties, in the property grid. Click the small ellipsis button to open a collection editor for adding/removing/editing perspectives/cultures. -![Editing perspectives - click the elipsis button to the right](https://raw.githubusercontent.com/TabularEditor/TabularEditor/master/Documentation/Edit%20Perspectives.png) +![Editing perspectives - click the ellipsis button to the right](https://raw.githubusercontent.com/TabularEditor/TabularEditor/master/Documentation/Edit%20Perspectives.png) To save your changes back to the Model.bim file, click the save button or hit CTRL+S. If you opened an existing Tabular Database, the changes are saved directly back to the database. You will be prompted if the database was changed since you loaded it into Tabular Editor. You can always undo your changes by pressing CTRL+Z. @@ -92,7 +92,7 @@ By default, partitions, data sources and roles will not be overwritten in the ta More information on command-line options can be found [here](../features/Command-line-Options.md). > [!NOTE] -> Since TabularEditor.exe is a Windows Forms application, running it from the command line will execute the application in a different thread, returning control to the caller immediately. This may cause issues when running deployments as part of a batch job where you need to await succesful deployment before proceeding with the job. If you experience these issues, use `start /wait` to let TabularEditor finish its job before returning control to the caller: +> Since TabularEditor.exe is a Windows Forms application, running it from the command line will execute the application in a different thread, returning control to the caller immediately. This may cause issues when running deployments as part of a batch job where you need to await successful deployment before proceeding with the job. If you experience these issues, use `start /wait` to let TabularEditor finish its job before returning control to the caller: > > `start /wait TabularEditor.exe c:\Projects\Model.bim -deploy localhost AdventureWorks` diff --git a/content/getting-started/Power-BI-Desktop-Integration.md b/content/getting-started/Power-BI-Desktop-Integration.md index 8dc82f29..e645e4a7 100644 --- a/content/getting-started/Power-BI-Desktop-Integration.md +++ b/content/getting-started/Power-BI-Desktop-Integration.md @@ -32,7 +32,7 @@ Also, it is highly recommended that [automatic date/time](https://docs.microsoft When a Power BI Desktop report contains a data model (that is, one or more tables have been added in Import or DirectQuery mode), that data model is hosted inside an instance of Analysis Services managed by Power BI Desktop. External Tools may connect to this instance of Analysis Services for different purposes. > [!IMPORTANT] -> Power BI Desktop reports that use a **Live Connection** to SSAS, Azure AS or a dataset in a Power BI workspace do not contain a data model. As such, these reports **can not** be used with external tools such as Tabular Editor. +> Power BI Desktop reports that use a **Live Connection** to SSAS, Azure AS or a dataset in a Power BI workspace do not contain a data model. As such, these reports **cannot** be used with external tools such as Tabular Editor. > [!IMPORTANT] > Power BI Desktop reports that directly edits a **Direct Lake** or other model Fabric do not contain a data model. Instead, Tabular Editor will open the model directly from the service which is essentially what Power BI Desktop also does. diff --git a/content/getting-started/boosting-productivity-te3.md b/content/getting-started/boosting-productivity-te3.md index 01306b73..ff0edf61 100644 --- a/content/getting-started/boosting-productivity-te3.md +++ b/content/getting-started/boosting-productivity-te3.md @@ -25,7 +25,7 @@ This section contains a number of articles that will let you quickly become fami Below is an overview of the articles and what you will learn in each: -- @importing-tables-data-modeling: This article describes how to import tables, upate table schemas and visualize and edit relationships. +- @importing-tables-data-modeling: This article describes how to import tables, update table schemas and visualize and edit relationships. - @refresh-preview-query: This article describes how to schedule refresh operations, how to preview table data, how to view summarized data using Pivot Grids, how to create and execute DAX queries and how to use Tabular Editor 3's integrated version of [VertiPaq Analyzer](https://www.sqlbi.com/tools/vertipaq-analyzer/). - @creating-and-testing-dax: This article introduces Tabular Editor 3's powerful DAX editor and demonstrates how to quickly add and edit DAX calculations to your model such as measures, calculated columns and calculated tables. - @dax-script-introduction: This article demonstrates how to use the DAX scripting feature, to write, maintain and test complex business logic across multiple measures, by combining their definition in a single DAX script. diff --git a/content/getting-started/bpa.md b/content/getting-started/bpa.md index 575040d3..d76f9a07 100644 --- a/content/getting-started/bpa.md +++ b/content/getting-started/bpa.md @@ -92,7 +92,7 @@ When a rule is saved to a rule collection on disk, all of the above properties a # Using the Best Practice Analyzer view -Tabular Editor displays the best practice rule violations within the **Best Practice Analyzer view**. You can also see the number of rule violations in the status bar at the bottom of the main window. To bring the view into focus, use the **View > Best Practice Analyzer** menu option or blick on the "# BP issues" button in the status bar. +Tabular Editor displays the best practice rule violations within the **Best Practice Analyzer view**. You can also see the number of rule violations in the status bar at the bottom of the main window. To bring the view into focus, use the **View > Best Practice Analyzer** menu option or click on the "# BP issues" button in the status bar. ![Best Practice Analyzer View](~/content/assets/images/best-practice-analyzer-view.png) diff --git a/content/getting-started/creating-and-testing-dax.md b/content/getting-started/creating-and-testing-dax.md index 4f4a2e46..b9862508 100644 --- a/content/getting-started/creating-and-testing-dax.md +++ b/content/getting-started/creating-and-testing-dax.md @@ -34,7 +34,7 @@ The remainder of this article describes how to create measures and other calcula Once you have [imported some tables](xref:importing-tables-data-modeling#importing-new-tables) to your model and [created relationships between them](xref:importing-tables-data-modeling#modifying-relationships-using-the-diagram), it is time to add some explicit measures containing your business logic. > [!TIP] -> Technically, you are not required to add explicit measures to your model before visualizing data in a Power BI report. However, it is a best practice to always do so, as MDX-based client tools (such as Excel and Tabular Editor 3's Pivot Grid) requires explicit measures. In addition, [Calculation Groups](https://docs.microsoft.com/en-us/analysis-services/tabular-models/calculation-groups?view=asallproducts-allversions) only apply to explicit measures. +> Technically, you are not required to add explicit measures to your model before visualizing data in a Power BI report. However, it is a best practice to always do so, as MDX-based client tools (such as Excel and Tabular Editor 3's Pivot Grid) require explicit measures. In addition, [Calculation Groups](https://docs.microsoft.com/en-us/analysis-services/tabular-models/calculation-groups?view=asallproducts-allversions) only apply to explicit measures. To add a new measure using Tabular Editor, right-click on the table in which you want to add the measure, then choose **Create > Measure** (ALT+1). diff --git a/content/getting-started/cs-scripts-and-macros.md b/content/getting-started/cs-scripts-and-macros.md index 192171e0..6c0137d3 100644 --- a/content/getting-started/cs-scripts-and-macros.md +++ b/content/getting-started/cs-scripts-and-macros.md @@ -84,7 +84,7 @@ To make scripts reusable, it is rarely enough to be able to reference objects in Info("You have currently selected: " + Selected.Measures.Count + " measure(s)."); ``` -The `Selected` object by itself is a collection of all objects currently selected, including objects within selected display folders. In addition, the `Selected` object contains multiple properties that makes it easy to refer to specific object types, such as the `.Measures` property shown in the example above. In general, these properties exist in both a plural (`.Measures`) and a singular (`.Measure`) form. The former is a collection that you can iterate through, and which will be empty if the current selection does not contain any objects of that type, where as the latter is a reference to the currently selected object, if and only if exactly one of that type of object is selected. +The `Selected` object by itself is a collection of all objects currently selected, including objects within selected display folders. In addition, the `Selected` object contains multiple properties that makes it easy to refer to specific object types, such as the `.Measures` property shown in the example above. In general, these properties exist in both a plural (`.Measures`) and a singular (`.Measure`) form. The former is a collection that you can iterate through, and which will be empty if the current selection does not contain any objects of that type, whereas the latter is a reference to the currently selected object, if and only if exactly one of that type of object is selected. The @useful-script-snippets article contains many examples of scripts that use the `Selected` object to perform various tasks. diff --git a/content/getting-started/dax-script-introduction.md b/content/getting-started/dax-script-introduction.md index 16bb426c..9afd9164 100644 --- a/content/getting-started/dax-script-introduction.md +++ b/content/getting-started/dax-script-introduction.md @@ -41,7 +41,7 @@ DAX scripts can be saved as text files, using the `.te3daxs` file extension. To The DAX script editor has all the capabilities of the DAX editor used elsewhere in Tabular Editor 3. Specifically, auto-complete, auto-formatting, calltips, etc. -In addition, to easily manage large DAX scripts, two dropdowns are displayed at the top of the DAX script view. The dropdown on the left allows you to jump between objects defined in the script, where as the dropdown on the right allows you to jump between properties on the current object. +In addition, to easily manage large DAX scripts, two dropdowns are displayed at the top of the DAX script view. The dropdown on the left allows you to jump between objects defined in the script, whereas the dropdown on the right allows you to jump between properties on the current object. ![Dax Script Navigation](~/content/assets/images/dax-script-navigation.png) diff --git a/content/getting-started/desktop-limitations.md b/content/getting-started/desktop-limitations.md index 50f936c3..1b9504d5 100644 --- a/content/getting-started/desktop-limitations.md +++ b/content/getting-started/desktop-limitations.md @@ -39,7 +39,7 @@ When using Power BI, you will encounter three different file types commonly used Both these files can be opened in Power BI Desktop and essentially defines everything related to a Power BI report: Data sources, Power Query transformations, the tabular data model, report pages, visuals, bookmarks, etc. -The main difference between, is that the **.pbix and .pbip file contains model data**, where as the **.pbit file contains no data**. In addition, a **.pbix** file does not contain the model metadata in this format, and therefore, **a .pbix file cannot be loaded directly in Tabular Editor** in any way. Instead, you will have to rely on the External Tools integration, which requires you to load the .pbix file in Power BI Desktop, as described below. +The main difference between, is that the **.pbix and .pbip file contains model data**, whereas the **.pbit file contains no data**. In addition, a **.pbix** file does not contain the model metadata in this format, and therefore, **a .pbix file cannot be loaded directly in Tabular Editor** in any way. Instead, you will have to rely on the External Tools integration, which requires you to load the .pbix file in Power BI Desktop, as described below. > [!WARNING] > Even though it is technically possible to load and save model metadata to and from a .pbit file, this approach is unsupported by Power BI Desktop. As such, there is always a risk of making changes to the .pbit file which would cause the file to become unloadable in Power BI Desktop, or cause stability issues once loaded. In this case, Microsoft support will be unable to assist you. @@ -52,7 +52,7 @@ The main difference between, is that the **.pbix and .pbip file contains model d When a Power BI Desktop report (.pbix or .pbit file) contains a data model (that is, one or more tables have been added in Import or DirectQuery mode), that data model is hosted inside an instance of Analysis Services managed by Power BI Desktop. External Tools may connect to this instance of Analysis Services for different purposes. > [!IMPORTANT] -> Power BI Desktop reports that use a **Live Connection** to SSAS, Azure AS or a dataset in a Power BI workspace do not contain a data model. As such, these reports **can not** be used with external tools such as Tabular Editor. +> Power BI Desktop reports that use a **Live Connection** to SSAS, Azure AS or a dataset in a Power BI workspace do not contain a data model. As such, these reports **cannot** be used with external tools such as Tabular Editor. External tools may connect to the instance of Analysis Services managed by Power BI Desktop through a specific port number assigned by Power BI Desktop. When a tool is launched directly from the "External Tools" ribbon in Power BI Desktop, this port number is passed to the external tool as a command line argument. In Tabular Editor's case, this causes the data model to be loaded in Tabular Editor. diff --git a/content/getting-started/editions.md b/content/getting-started/editions.md index c0e268a6..f267cc1f 100644 --- a/content/getting-started/editions.md +++ b/content/getting-started/editions.md @@ -21,7 +21,7 @@ This document provides an overview and comparison of the different editions of T The main difference between the various editions of Tabular Editor 3, is which types of tabular data modeling scenarios they support. To understand this difference, consider that Analysis Services (Tabular) exists in a number of different "flavors": -- Power BI Desktop (make sure you you understand the [limitations](xref:desktop-limitations)) +- Power BI Desktop (make sure you understand the [limitations](xref:desktop-limitations)) - Power BI Premium through the XMLA Endpoint (Premium Per User, **Premium Capacity [A, EM or P SKUs]**, **Fabric Capacity [F SKUs]**) - SQL Server (2016+) Analysis Services (Editions: Developer, Standard, **Enterprise**) - Azure Analysis Services (Tiers: Developer, Basic, **Standard**) @@ -124,7 +124,7 @@ Our Enterprise Edition is priced in tiers, according to the following table (sim |Next 21-50 seats|$800.00 USD| |Seats 51 and above|$750.00 USD| -As an example, if you need 12 seats, the price breaks down as follow: +As an example, if you need 12 seats, the price breaks down as follows: ```text Seats 1-5: 5 x 950.00 = $ 4,750.00 diff --git a/content/getting-started/general-introduction.md b/content/getting-started/general-introduction.md index bee4249a..29f25a2d 100644 --- a/content/getting-started/general-introduction.md +++ b/content/getting-started/general-introduction.md @@ -76,7 +76,7 @@ Examples of TOM **object properties**: Most properties are simple values (text, true/false, one-of-selections aka. enums), but properties can also reference other objects (for example, the `Sort By Column` property should reference a column). Properties can also be arrays of objects, such as the `Members` property on the Model Role object. -Tabular Editor generally uses the same name for objects and properties as those defind in the [Microsoft.AnalysisServices.Tabular namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular?view=analysisservices-dotnet). If you want to learn more about specific TOM objects or properties, always consult the namespace documentation. For example, to learn what the "Summarize By" column property does, first locate the "Column" class in Microsoft's documentation, then expand "Properties" and scroll to "SummarizeBy". You should then get to [this article](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular.column.summarizeby?view=analysisservices-dotnet). +Tabular Editor generally uses the same name for objects and properties as those defined in the [Microsoft.AnalysisServices.Tabular namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular?view=analysisservices-dotnet). If you want to learn more about specific TOM objects or properties, always consult the namespace documentation. For example, to learn what the "Summarize By" column property does, first locate the "Column" class in Microsoft's documentation, then expand "Properties" and scroll to "SummarizeBy". You should then get to [this article](https://docs.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular.column.summarizeby?view=analysisservices-dotnet). ![SummarizeBy on Microsoft's docs](~/content/assets/images/asdocs-summarizyby.png) diff --git a/content/getting-started/getting-started.md b/content/getting-started/getting-started.md index 664ec18a..1df45bf8 100644 --- a/content/getting-started/getting-started.md +++ b/content/getting-started/getting-started.md @@ -36,7 +36,7 @@ See the .NET supported OS policy for current Windows versions supported by each ## Activating your installation -Tabular Editor 3 is commercial software. Visit our [home page](https://tabulareditor.com) for pricing details and purchase options. If you haven't previously used Tabular Editor 3 you are eligible to a free 30-day trial. +Tabular Editor 3 is commercial software. Visit our [home page](https://tabulareditor.com) for pricing details and purchase options. If you haven't previously used Tabular Editor 3 you are eligible for a free 30-day trial. The first time you launch Tabular Editor 3 on a new machine, you are prompted to activate the product. @@ -55,10 +55,10 @@ Note that Tabular Editor 3 installations are activated **per user**. In other wo ### Requesting a trial license -If you haven't used Tabular Editor 3 before, you are eligible to a free 30-day trial. When choosing this option, you will be prompted for an e-mail address. We use the e-mail address to validate whether or not you have an existing activation of Tabular Editor 3. +If you haven't used Tabular Editor 3 before, you are eligible for a free 30-day trial. When choosing this option, you will be prompted for an e-mail address. We use the e-mail address to validate whether or not you have an existing activation of Tabular Editor 3. > [!NOTE] -> Tabular Editor ApS will not sent unsolicited e-mails or forward your e-mail address to third parties, when signing up for a 30-day trial license. View our @privacy-policy for more information. +> Tabular Editor ApS will not send unsolicited e-mails or forward your e-mail address to third parties, when signing up for a 30-day trial license. View our @privacy-policy for more information. ### Changing a license key diff --git a/content/getting-started/importing-tables-data-modeling.md b/content/getting-started/importing-tables-data-modeling.md index ff7e3d33..372d6d5f 100644 --- a/content/getting-started/importing-tables-data-modeling.md +++ b/content/getting-started/importing-tables-data-modeling.md @@ -26,7 +26,7 @@ This article describes how to use the [Table Import Wizard](#table-import-wizard # Working with diagrams -In Tabular Editor 3, **diagrams** are documents that can be used to visualize and edit the relationships between tables in the model. You can create as many diagrams as you want to visualize certain areas of your model. A diagram can be saved as a stand alone file. See for more information. +In Tabular Editor 3, **diagrams** are documents that can be used to visualize and edit the relationships between tables in the model. You can create as many diagrams as you want to visualize certain areas of your model. A diagram can be saved as a standalone file. See for more information. > [!NOTE] > We recommend creating multiple smaller diagrams over few large diagrams. When a diagram contains more than 20 or so tables, it quickly becomes overwhelming and difficult to understand. diff --git a/content/getting-started/migrate-from-desktop.md b/content/getting-started/migrate-from-desktop.md index c3aec21d..32442daa 100644 --- a/content/getting-started/migrate-from-desktop.md +++ b/content/getting-started/migrate-from-desktop.md @@ -107,7 +107,7 @@ If you need to edit the name of the measure (or any other object), simply select ![Batch Rename](~/content/assets/images/batch-rename.png) > [!WARNING] -> Changing object names in the data model may cause report visuals to stop working, if the visuals relies on one or more of the objects being renamed. External tools cannot access information about Power BI visuals, so Tabular Editor is not able to warn you before an object that is used in a visual is renamed or deleted. +> Changing object names in the data model may cause report visuals to stop working, if the visuals rely on one or more of the objects being renamed. External tools cannot access information about Power BI visuals, so Tabular Editor is not able to warn you before an object that is used in a visual is renamed or deleted. ### How to create a copy of a measure diff --git a/content/getting-started/migrate-from-te2.md b/content/getting-started/migrate-from-te2.md index be9e7d8f..d1e6fec5 100644 --- a/content/getting-started/migrate-from-te2.md +++ b/content/getting-started/migrate-from-te2.md @@ -74,7 +74,7 @@ In general, though, interface elements that exist in Tabular Editor 2.x have the - The **Advanced Scripting** tab in Tabular Editor 2.x is gone. In Tabular Editor 3, you instead create *C# Scripts** using the **File > New** menu. You are not limited to working on a single script at a time. In addition, **Custom actions** have been renamed to **Macros**. - **Dynamic LINQ filtering** is not currently available within the TOM Explorer. Instead, if you want to find objects using [Dynamic LINQ](https://dynamic-linq.net/expression-language) you have to bring up the **Find and replace** dialog by pressing CTRL+F. - If you close the **Expression Editor** you can bring it back by doubleclicking on the icon of an object in the **TOM Explorer**, or by choosing the **View > Expression Editor** menu option. -- When using the default layout in Tabular Editor 3, the **Best Practice Analyzer** will be located as a tab next to the **TOM Explorer**. Here, you will also find the new **Data Refresh** view (which lets you view the queue of background refresh operations) and the **Macros** view (which lets you manage any macros that was previously saved from C# scripts). +- When using the default layout in Tabular Editor 3, the **Best Practice Analyzer** will be located as a tab next to the **TOM Explorer**. Here, you will also find the new **Data Refresh** view (which lets you view the queue of background refresh operations) and the **Macros** view (which lets you manage any macros that were previously saved from C# scripts). - Tabular Editor 3 displays all DAX syntax and semantic errors in the new **Messages View**. In the default layout, this is located at the bottom left of the interface. - In addition, Tabular Editor 3 includes **VertiPaq Analyzer** (which you may be familiar with from [DAX Studio](https://daxstudio.org/)). - As a final note, Tabular Editor 3 introduces the concept of **documents**, which is just a generic term for C# scripts, DAX scripts, DAX Queries, Diagrams, Data Previews and Pivot Grids. @@ -83,7 +83,7 @@ For more information, see . ### New DAX editor and semantic capabilities -Tabular Editor 3 features its very own DAX parsing engine (aka. the "semantic analyzer"), which means that the tool now understands the semantics of any DAX code in your model. This engine is also used to power our DAX editor (codename "Daxscilla"), to enable features such as syntax highligting, automatic formatting, code completion, calltips, refactoring and much more. Of course the editor is highly configurable, allowing you to tweak it to match your preferred DAX coding style. +Tabular Editor 3 features its very own DAX parsing engine (aka. the "semantic analyzer"), which means that the tool now understands the semantics of any DAX code in your model. This engine is also used to power our DAX editor (codename "Daxscilla"), to enable features such as syntax highlighting, automatic formatting, code completion, calltips, refactoring and much more. Of course the editor is highly configurable, allowing you to tweak it to match your preferred DAX coding style. To learn more about the new DAX editor, see . diff --git a/content/getting-started/migrate-from-vs.md b/content/getting-started/migrate-from-vs.md index e3bc0fd1..25202c30 100644 --- a/content/getting-started/migrate-from-vs.md +++ b/content/getting-started/migrate-from-vs.md @@ -67,7 +67,7 @@ Below is the dialog box shown when creating a new model in Tabular Editor 3: ![New model dialog](~/content/assets/images/new-model.png) -If you enable the **Use workspace database** option, Tabular Editor will prompt you for an Analysis Services instance and database name that will be used as as workspace database while working on the model. If you do not enable this option, you will be able to create and work on your model in "offline" mode, which still allows you to add tables, relationships, author DAX expressions, etc. However, you will have to deploy your offline model to an instance of Analysis Services before you can refresh, preview and query the data in the model. +If you enable the **Use workspace database** option, Tabular Editor will prompt you for an Analysis Services instance and database name that will be used as workspace database while working on the model. If you do not enable this option, you will be able to create and work on your model in "offline" mode, which still allows you to add tables, relationships, author DAX expressions, etc. However, you will have to deploy your offline model to an instance of Analysis Services before you can refresh, preview and query the data in the model. > [!IMPORTANT] > Tabular Editor 3 does not provide a feature equivalent to the **Integrated workspace** option of Visual Studio. Essentially, the integrated workspace is an Analysis Services instance managed by Visual Studio. Since Analysis Services is proprietary software from Microsoft, we cannot ship it alongside Tabular Editor 3. Instead, if you would like to run a local instance of Analysis Services for use with Tabular Editor, we recommend that you install [SQL Server Developer Edition](https://www.microsoft.com/en-us/sql-server/sql-server-downloads). @@ -172,7 +172,7 @@ In the screenshot above, notice how there are three different message-posting so ### Previewing table data -In Visual Studio, tables and their content are displayed in a tabbed view once you load the Model.bim file. In Tabular Editor 3, you can preview table data by right-clicking on a table in the TOM Explorer, and chooseing **Preview Data**. This opens a new document tab that lets you scroll through all rows of the table, as well as filter and sort the columns. It even works for model using DirectQuery! +In Visual Studio, tables and their content are displayed in a tabbed view once you load the Model.bim file. In Tabular Editor 3, you can preview table data by right-clicking on a table in the TOM Explorer, and choosing **Preview Data**. This opens a new document tab that lets you scroll through all rows of the table, as well as filter and sort the columns. It even works for model using DirectQuery! Also, you can freely rearrange the documents, to view the content of several tables at once (see screenshot below). diff --git a/content/getting-started/parallel-development.md b/content/getting-started/parallel-development.md index 0171b848..b2a06374 100644 --- a/content/getting-started/parallel-development.md +++ b/content/getting-started/parallel-development.md @@ -49,7 +49,7 @@ Tabular Editor aims to simplify this process by providing an easy way to extract ## What is Save to Folder? -As mentioned above, the model metadata for a tabular model is traditionally stored in a single, monolithic JSON file, typically named **Model.bim**, which is not well suited for version control integration. Since the JSON in this file represents the [Tabular Object Model (TOM)](https://docs.microsoft.com/en-us/analysis-services/tom/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo?view=asallproducts-allversions), it turns out that there is a straight forward way to break the file down into smaller pieces: The TOM contains arrays of objects at almost all levels, such as the list of tables within a model, the list of measures within a table, the list of annotations within a measure, etc. When using Tabular Editor's **Save to Folder** feature, these arrays are simply removed from the JSON, and instead, a subfolder is generated containing one file for each object in the original array. This process can be nested. The result is a folder structure, where each folder contains a set of smaller JSON files and subfolders, which semantically contains exactly the same information as the original Model.bim file: +As mentioned above, the model metadata for a tabular model is traditionally stored in a single, monolithic JSON file, typically named **Model.bim**, which is not well suited for version control integration. Since the JSON in this file represents the [Tabular Object Model (TOM)](https://docs.microsoft.com/en-us/analysis-services/tom/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo?view=asallproducts-allversions), it turns out that there is a straightforward way to break the file down into smaller pieces: The TOM contains arrays of objects at almost all levels, such as the list of tables within a model, the list of measures within a table, the list of annotations within a measure, etc. When using Tabular Editor's **Save to Folder** feature, these arrays are simply removed from the JSON, and instead, a subfolder is generated containing one file for each object in the original array. This process can be nested. The result is a folder structure, where each folder contains a set of smaller JSON files and subfolders, which semantically contains exactly the same information as the original Model.bim file: ![Save To Folder](~/content/assets/images/save-to-folder.png) @@ -135,14 +135,14 @@ Determining a suitable branching strategy depends on many different factors. In However, such a strategy might not be feasible in a Business Intelligence development teams, for a number of reasons: -- New features often require prolonged testing and validation by business users, which may take several weeks to complete. As such, you will likely need a user-faced test environment. +- New features often require prolonged testing and validation by business users, which may take several weeks to complete. As such, you will likely need a user-facing test environment. - BI solutions are multi-tiered, typically consisting of a Data Warehouse tier with ETL, a Master Data Management tier, a semantic layer and reports. Dependencies exist between these layers, that further complicate testing and deployment. - The BI team may be responsible for developing and maintaining several different semantic models, serving different areas of business (Sales, Inventory, Logistics, Finance, HR, etc.), at different maturity stages and at varying development pace. -- The most important aspect of a BI solution is the data! As a BI developer, you don not have the luxury of simply checking out the code from source control, hitting F5 and having a full solution up and running in the few minutes it takes to compile the code. Your solution needs data, and that data has to be loaded, ETL'ed or processed across several layers to make it to the end user. Including data in your DevOps workflows could blow up build and deployment times from minutes to hours or even days. In some scenarios, it might not even be possible, due to ressource or economy constraints. +- The most important aspect of a BI solution is the data! As a BI developer, you do not have the luxury of simply checking out the code from source control, hitting F5 and having a full solution up and running in the few minutes it takes to compile the code. Your solution needs data, and that data has to be loaded, ETL'ed or processed across several layers to make it to the end user. Including data in your DevOps workflows could blow up build and deployment times from minutes to hours or even days. In some scenarios, it might not even be possible, due to resource or economy constraints. There is no doubt that a BI team would benefit from a branching strategy that supports parallel development on any of the layers in the full BI solution, in a way that lets them mix and match features that are ready for testing. But especially due to the last bullet point above, we need to think carefully about how we are going to handle the data. If we add a new attribute to a dimension, for example, do we want to automatically load the dimension as part of our build and deployment pipelines? If it only takes a few minutes to load such a dimension, that would probably be fine, but what if we are adding a new column to a multi-billion row fact table? And if developers are working on new features in parallel, should each developer have their own development database, or how do we otherwise prevent them from stepping on each others toes in a shared database? -There is no easy answer to the questions above - especially when considering all the tiers of a BI solution, and the different constellations and prefered workflows of BI teams across the planet. Also, when we dive into actual build, deployment and test automation, we are going to focus mostly on Analysis Services. The ETL- and database tiers have their own challenges from a DevOps perspective, which are outside the scope of this article. But before we move on, let us take a look at another branching strategy, and how it could potentially be adopted to BI workflows. +There is no easy answer to the questions above - especially when considering all the tiers of a BI solution, and the different constellations and preferred workflows of BI teams across the planet. Also, when we dive into actual build, deployment and test automation, we are going to focus mostly on Analysis Services. The ETL- and database tiers have their own challenges from a DevOps perspective, which are outside the scope of this article. But before we move on, let us take a look at another branching strategy, and how it could potentially be adopted to BI workflows. ### GitFlow branching and deployment environments diff --git a/content/getting-started/personalizing-te3.md b/content/getting-started/personalizing-te3.md index d566eec8..2c6c3048 100644 --- a/content/getting-started/personalizing-te3.md +++ b/content/getting-started/personalizing-te3.md @@ -64,7 +64,7 @@ This option is only relevant for local instances of Analysis Services (i.e. msmd ##### *Refresh local Tabular Object Model metadata automatically* (enabled) -When the tracing mechanism as described above is enabled, this option allows Tabular Editor to automatically refresh the model metadata when an external change is detected. This is useful if you often switch back and forth between Power BI Desktop and Tabular Editor 3, as this ensures that changes made in Power BI Desktop are automatically sync'ed to Tabular Editor. +When the tracing mechanism as described above is enabled, this option allows Tabular Editor to automatically refresh the model metadata when an external change is detected. This is useful if you often switch back and forth between Power BI Desktop and Tabular Editor 3, as this ensures that changes made in Power BI Desktop are automatically synced to Tabular Editor. ##### *Cleanup orphaned Tabular Editor traces* @@ -244,7 +244,7 @@ This setting allows you to change the casing used for keywords, such as `ORDER B ##### *Preferred function casing* (default = UPPER) -This setting allows oyu to change the casing used for functions, such as `CALCULATE(...)`, `SUM(...)`, etc. This also applies when a function is inserted through the auto-complete feature. +This setting allows you to change the casing used for functions, such as `CALCULATE(...)`, `SUM(...)`, etc. This also applies when a function is inserted through the auto-complete feature. ##### *Fix keyword/function casing* (enabled) diff --git a/content/how-tos/Advanced-Scripting.md b/content/how-tos/Advanced-Scripting.md index 1b6a5c34..30c30f39 100644 --- a/content/how-tos/Advanced-Scripting.md +++ b/content/how-tos/Advanced-Scripting.md @@ -106,7 +106,7 @@ Selected.Measures .Rename("Amount", "Value"); ``` -This would replace any occurence of the word "Amount" with the word "Value" in the names of all currently selected measures. +This would replace any occurrence of the word "Amount" with the word "Value" in the names of all currently selected measures. Alternatively, we may use the LINQ ForEach()-method, as described above, to include more advanced logic: ```csharp diff --git a/content/how-tos/folder-serialization.md b/content/how-tos/folder-serialization.md index b0501caf..abfc3c4a 100644 --- a/content/how-tos/folder-serialization.md +++ b/content/how-tos/folder-serialization.md @@ -17,7 +17,7 @@ By default, objects are serialized down to the lowest object level (meaning meas Additionally, Tabular Editor's [command-line syntax](xref:command-line-options) supports loading a model from this folder structure and deploying it directly to a database, making it easy for you to automate builds for continuous integration workflows. -If you want to customize the granularity at which metadata is saved to individual files, go to File > Preferences and click the "Save to folder"-tab. Here, it's possible to toggle some serialization options which are passed to the TOM when serializing into JSON. Furthermore, you can check/uncheck the types of objects for which individual files will be generated. In some Version Control scenarios, you might want to store everything related to one table in a file on its own, where as in other scenarios you may need individual files for columns and measures. +If you want to customize the granularity at which metadata is saved to individual files, go to File > Preferences and click the "Save to folder"-tab. Here, it's possible to toggle some serialization options which are passed to the TOM when serializing into JSON. Furthermore, you can check/uncheck the types of objects for which individual files will be generated. In some Version Control scenarios, you might want to store everything related to one table in a file on its own, whereas in other scenarios you may need individual files for columns and measures. These settings are saved in an annotation on the model, the first time you use the Save to Folder function, so that the settings are reused when the model is loaded and the "Save"-button is subsequently clicked. If you want to apply new settings, use "File > Save to Folder..." again. diff --git a/content/how-tos/perspectives-translations.md b/content/how-tos/perspectives-translations.md index a76bf67b..de735fdc 100644 --- a/content/how-tos/perspectives-translations.md +++ b/content/how-tos/perspectives-translations.md @@ -22,7 +22,7 @@ To view perspectives and/or translations "in action", use the two dropdown lists ## Perspectives/Translations within object context When one or more objects are selected in the tree, you will find 4 special property collections within the Property Grid: -* **Captions**, **Descriptions** and **Display Folders** shows a list of all cultures in the model, with the translated names, descripions and display folders respectively of the selected objects for each culture. +* **Captions**, **Descriptions** and **Display Folders** shows a list of all cultures in the model, with the translated names, descriptions and display folders respectively of the selected objects for each culture. * **Perspectives** shows a list of all perspectives in the model, with an indication of whether or nor the selected objects belong to each perspective. -You can use these collections in the Property Grid to change the translations and perspective inclusions for one or more objects at at time. \ No newline at end of file +You can use these collections in the Property Grid to change the translations and perspective inclusions for one or more objects at a time. \ No newline at end of file diff --git a/content/how-tos/undo-redo.md b/content/how-tos/undo-redo.md index dd5824bb..927c64cf 100644 --- a/content/how-tos/undo-redo.md +++ b/content/how-tos/undo-redo.md @@ -11,4 +11,4 @@ applies_to: ## Undo/Redo support Any change you make in Tabular Editor can be undone using CTRL+Z and subsequently redone using CTRL+Y. There is no limit to the number of operations that can be undone, but the stack is reset when you open a Model.bim file or load a model from a database. -When deleting objects from the model, all translations, perspectives and relationships that reference the deleted objects are also automatically deleted (where as Visual Studio normally shows an error message that the object cannot be deleted). If you make a mistake, you can use the Undo functionality to restore the deleted object, which will also restore any translations, perspectives or relationships that were deleted. Note that even though Tabular Editor can detect [DAX formula dependencies](), Tabular Editor will not warn you in case you delete a measure or column which is used in the DAX expression of another measure or calculated column. \ No newline at end of file +When deleting objects from the model, all translations, perspectives and relationships that reference the deleted objects are also automatically deleted (whereas Visual Studio normally shows an error message that the object cannot be deleted). If you make a mistake, you can use the Undo functionality to restore the deleted object, which will also restore any translations, perspectives or relationships that were deleted. Note that even though Tabular Editor can detect [DAX formula dependencies](), Tabular Editor will not warn you in case you delete a measure or column which is used in the DAX expression of another measure or calculated column. \ No newline at end of file diff --git a/content/index.md b/content/index.md index 88f7525a..04b8f71e 100644 --- a/content/index.md +++ b/content/index.md @@ -118,7 +118,7 @@ The table below lists all the main features of both tools. ### Common features -Both tools provide the same features in terms of which data modeling options are available, by basically exposing every object and property of the [Tabular Object Model](https://docs.microsoft.com/en-us/analysis-services/tom/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo?view=asallproducts-allversions), in an intuitive and responsive user interface. You can edit advanced object properties that are not available through the standard tools. The tools can load model metadata from files or from any instance of Analysis Services. Changes are only synchronized when you hit Ctrl+S (save) thus providing an "offline" editing experience which most people consider to be superior to the "always synchronized"-mode of the standard tools. This is especially noticable when working on large and complex data models. +Both tools provide the same features in terms of which data modeling options are available, by basically exposing every object and property of the [Tabular Object Model](https://docs.microsoft.com/en-us/analysis-services/tom/introduction-to-the-tabular-object-model-tom-in-analysis-services-amo?view=asallproducts-allversions), in an intuitive and responsive user interface. You can edit advanced object properties that are not available through the standard tools. The tools can load model metadata from files or from any instance of Analysis Services. Changes are only synchronized when you hit Ctrl+S (save) thus providing an "offline" editing experience which most people consider to be superior to the "always synchronized"-mode of the standard tools. This is especially noticeable when working on large and complex data models. In addition, both tools enables making multiple model metadata changes in batches, renaming objects in batches, copy/pasting objects, dragging/dropping objects across tables and display folders, etc. The tools even have undo/redo support. diff --git a/content/kb/bpa-format-string-measures.md b/content/kb/bpa-format-string-measures.md index 7b4cf80f..898dab23 100644 --- a/content/kb/bpa-format-string-measures.md +++ b/content/kb/bpa-format-string-measures.md @@ -70,7 +70,7 @@ COUNTROWS('Orders') ### Cause 1: Missing Format Definition -When creating a new measure the defualt state is to not have any format string set. +When creating a new measure the default state is to not have any format string set. ### Cause 2: Copy/Paste from Calculated Columns diff --git a/content/kb/bpa-powerbi-latest-compatibility.md b/content/kb/bpa-powerbi-latest-compatibility.md index bb97ccb7..c4b448d8 100644 --- a/content/kb/bpa-powerbi-latest-compatibility.md +++ b/content/kb/bpa-powerbi-latest-compatibility.md @@ -37,7 +37,7 @@ and Model.Database.CompatibilityLevel<>[CurrentMaxLevel] ### Automatic Fix -The best practice rule includes an automatic fix that sets the Compatability Level to the highest avaliable that exist on the current installation of Tabular Editor 3. If you have an older version of Tabular Editor 3 installed you should update your installation. +The best practice rule includes an automatic fix that sets the Compatibility Level to the highest available that exists on the current installation of Tabular Editor 3. If you have an older version of Tabular Editor 3 installed you should update your installation. ```csharp Model.Database.CompatibilityLevel = [PowerBIMaxCompatibilityLevel] @@ -54,7 +54,7 @@ Model.Database.CompatibilityLevel = [PowerBIMaxCompatibilityLevel] ### Cause 1: Model Created in Power BI Desktop -Model created with in Power BI Desktop does not necesarily have the latest Compatability Level. +Model created with in Power BI Desktop does not necessarily have the latest Compatibility Level. ### Cause 2: Model Created at Lower Level diff --git a/content/kb/bpa-trim-object-names.md b/content/kb/bpa-trim-object-names.md index 9318b2e1..ecfd33eb 100644 --- a/content/kb/bpa-trim-object-names.md +++ b/content/kb/bpa-trim-object-names.md @@ -69,9 +69,9 @@ Accidental spacebar presses during naming. Copy/paste from documents with formatting. -### Cause 3: Dublicating objects +### Cause 3: Duplicating objects -When dublicating objects the name with have an added " copy" post-fixed. It is easy to miss deleting the space before "copy" +When duplicating objects the name will have an added " copy" post-fixed. It is easy to miss deleting the space before "copy" ## Example diff --git a/content/kb/bpa-visible-objects-no-description.md b/content/kb/bpa-visible-objects-no-description.md index 7685d2b2..975aaa16 100644 --- a/content/kb/bpa-visible-objects-no-description.md +++ b/content/kb/bpa-visible-objects-no-description.md @@ -37,7 +37,7 @@ Descriptions provide critical context for model users: - **Enhanced tooltips**: Power BI and Excel show descriptions in hover tooltips - **Documentation foundation**: Descriptions form the basis for automated documentation - **Governance and compliance**: Descriptions can include data lineage and business definitions -- **Useage by AI**: AI Agents can better infer the purpose of an object if it has a description. +- **Usage by AI**: AI Agents can better infer the purpose of an object if it has a description. Without descriptions, users guess at field meanings, leading to incorrect analysis and increased support requests. ## When This Rule Triggers diff --git a/content/references/Roadmap2-h.md b/content/references/Roadmap2-h.md index efb8a757..3fe1f070 100644 --- a/content/references/Roadmap2-h.md +++ b/content/references/Roadmap2-h.md @@ -47,7 +47,7 @@ DevOps using VSTS and general clean-up of Tabular Editor source code. ## Formula fix-up -When any model object is renamed, all DAX expressions refering that object should be updated to reflect the changed name. +When any model object is renamed, all DAX expressions referring to that object should be updated to reflect the changed name. **Update**: As of 2.2, this feature can now be toggled on under "File" > "Preferences". @@ -69,7 +69,7 @@ Tabular Editor currently only lets end-users read and edit a subset of the objec **Update**: As of 2.1, many new object types are now visible directly in the Tree Explorer. Using the right-click menu, you can create, duplicate and delete many of these objects (roles, perspectives, translations). We're still lacking support for creating/deleting relationships and data sources, but this will come in a future release. -**Update**: As of 2.2, we can now create and delete relationships. More object types comming later. +**Update**: As of 2.2, we can now create and delete relationships. More object types coming later. **Update**: As of 2.3, tables, partitions and data columns can now be edited. Visual Studio is now only needed to create the blank model itself - everything else can be done in Tabular Editor. diff --git a/content/references/TabularEditor.TOMWrapper-h.md b/content/references/TabularEditor.TOMWrapper-h.md index 7972f2cf..d394d081 100644 --- a/content/references/TabularEditor.TOMWrapper-h.md +++ b/content/references/TabularEditor.TOMWrapper-h.md @@ -2092,8 +2092,8 @@ Static Methods | Type | Name | Summary | | --- | --- | --- | -| `void` | Deploy(`Database` db, `String` targetConnectionString, `String` targetDatabaseName) | Deploys the specified database to the specified target server and database ID, using the specified options. Returns a list of DAX errors (if any) on objects inside the database, in case the deployment was succesful. | -| `DeploymentResult` | Deploy(`Database` db, `String` targetConnectionString, `String` targetDatabaseID, `DeploymentOptions` options) | Deploys the specified database to the specified target server and database ID, using the specified options. Returns a list of DAX errors (if any) on objects inside the database, in case the deployment was succesful. | +| `void` | Deploy(`Database` db, `String` targetConnectionString, `String` targetDatabaseName) | Deploys the specified database to the specified target server and database ID, using the specified options. Returns a list of DAX errors (if any) on objects inside the database, in case the deployment was successful. | +| `DeploymentResult` | Deploy(`Database` db, `String` targetConnectionString, `String` targetDatabaseID, `DeploymentOptions` options) | Deploys the specified database to the specified target server and database ID, using the specified options. Returns a list of DAX errors (if any) on objects inside the database, in case the deployment was successful. | | `String` | GetTMSL(`Database` db, `Server` server, `String` targetDatabaseID, `DeploymentOptions` options) | | | `void` | SaveModelMetadataBackup(`String` connectionString, `String` targetDatabaseID, `String` backupFilePath) | | | `void` | WriteZip(`String` fileName, `String` content) | | diff --git a/content/references/application-language.md b/content/references/application-language.md index 60cd8756..c676538e 100644 --- a/content/references/application-language.md +++ b/content/references/application-language.md @@ -44,7 +44,7 @@ Tabular Editor 3 is still not fully localized. Specifically we have so far not l The languages under Beta support means that they have been verified by an human translator, but that Tabular Editor 3 may still not be fully localized. Specifically we have so far not localized the individual TOM properties. ### Beta Languages -Beta languages are have been translated exclusively through AI and as not been verified by human translators. We plan to bring beta languages into Preview in Q2 2026. +Beta languages have been translated exclusively through AI and have not been verified by human translators. We plan to bring beta languages into Preview in Q2 2026. ## Changing the Language diff --git a/content/references/release-notes/3_12_0.md b/content/references/release-notes/3_12_0.md index a937ac48..cdb6b3c2 100644 --- a/content/references/release-notes/3_12_0.md +++ b/content/references/release-notes/3_12_0.md @@ -40,7 +40,7 @@ Check out our [release blog](https://blog.tabulareditor.com/2023/11/27/tabular-e - Tabular Editor now displays a "What's New" page when the application is updated. The page informs you of new Tabular Editor features, along with community updates and other relevant news for Tabular Editor users. If the page is hidden, you can access it from the **Help > What's New**. You can disable this feature by unchecking **Tools > Preferences > Updates and Feedback > Show "What's New" page on startup**. - When prototyping new measures, it is quite common to specify them within the `DEFINE` block of a DAX query. In this update, we've added an easy way to create/update model measures based on measures defined within the DAX query. On the toolbar, through the **Query** menu, and through the right-click context menu of the DAX query editor, you will see 4 new options light up, which work very similarly to the "Apply" actions in [DAX Scripts](https://docs.tabulareditor.com/features/dax-scripts.html#shortcuts), with the exception that only a measures' name and expression is applied (since it's not possible to specify other properties like Description, Display Folder, etc. through a DAX query). More details in the [blog post](https://blog.tabulareditor.com). -- Please be aware that we're now using a new certificate to sign the binaries, in case your IT organization needs to expclitly approve 3rd party code certificates. The new certificate is issued by [GlobalSign GCC](https://www.globalsign.com/en) and the certificate is issued directly to [Tabular Editor ApS](https://tabulareditor.com/contact). +- Please be aware that we're now using a new certificate to sign the binaries, in case your IT organization needs to explicitly approve 3rd party code certificates. The new certificate is issued by [GlobalSign GCC](https://www.globalsign.com/en) and the certificate is issued directly to [Tabular Editor ApS](https://tabulareditor.com/contact). ## Improvements in 3.12.0 diff --git a/content/references/release-notes/3_12_1.md b/content/references/release-notes/3_12_1.md index 5815f8e6..be5152a4 100644 --- a/content/references/release-notes/3_12_1.md +++ b/content/references/release-notes/3_12_1.md @@ -46,7 +46,7 @@ Check out our [release blog](https://blog.tabulareditor.com/) to get a brief ove - Tabular Editor now displays a "What's New" page when the application is updated. The page informs you of new Tabular Editor features, along with community updates and other relevant news for Tabular Editor users. If the page is hidden, you can access it from the **Help > What's New**. You can disable this feature by unchecking **Tools > Preferences > Updates and Feedback > Show "What's New" page on startup**. - When prototyping new measures, it is quite common to specify them within the `DEFINE` block of a DAX query. In this update, we've added an easy way to create/update model measures based on measures defined within the DAX query. On the toolbar, through the **Query** menu, and through the right-click context menu of the DAX query editor, you will see 4 new options light up, which work very similarly to the "Apply" actions in [DAX Scripts](https://docs.tabulareditor.com/te3/features/dax-scripts.html#shortcuts), with the exception that only a measures' name and expression is applied (since it's not possible to specify other properties like Description, Display Folder, etc. through a DAX query). More details in the [blog post](https://blog.tabulareditor.com). -- Please be aware that we're now using a new certificate to sign the binaries, in case your IT organization needs to expclitly approve 3rd party code certificates. The new certificate is issued by [GlobalSign GCC](https://www.globalsign.com/en) and the certificate is issued directly to [Tabular Editor ApS](https://tabulareditor.com/contact). +- Please be aware that we're now using a new certificate to sign the binaries, in case your IT organization needs to explicitly approve 3rd party code certificates. The new certificate is issued by [GlobalSign GCC](https://www.globalsign.com/en) and the certificate is issued directly to [Tabular Editor ApS](https://tabulareditor.com/contact). ## Improvements in 3.12.0 diff --git a/content/references/release-notes/3_22_0.md b/content/references/release-notes/3_22_0.md index d749b527..a60ffdea 100644 --- a/content/references/release-notes/3_22_0.md +++ b/content/references/release-notes/3_22_0.md @@ -49,7 +49,7 @@ For more information, view our [Direct Lake Guidance article](xref:direct-lake-g ## Improvements in 3.22.0 - When saving a model as a single file, the **Save file** dialog now suggests "model.bim" as the default file name. -- Updated various dependencies to their latest versions, including [AMO/TOM to 19.98.0.3](https://www.nuget.org/packages/Microsoft.AnalysisServices/). This update fixes longstanding authentication issues with Work or School accounts and repeated sign in promts. +- Updated various dependencies to their latest versions, including [AMO/TOM to 19.98.0.3](https://www.nuget.org/packages/Microsoft.AnalysisServices/). This update fixes longstanding authentication issues with Work or School accounts and repeated sign in prompts. - Changed the default Compatibility Level for new Power BI / Fabric semantic models to **1609**, which allows you to control how [Selection Expressions](https://powerbi.microsoft.com/en-us/blog/deep-dive-into-selection-expressions-for-calculation-groups/) on your Calculation Groups behave by default, through the Model [SelectionExpressionBehavior](https://learn.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.tabular.model.selectionexpressionbehavior?view=analysisservices-dotnet) property. - DAX query editor support for the [`MPARAMETER`](https://dax.guide/st/mparameter/) keyword, see [#1467](https://github.com/TabularEditor/TabularEditor3/issues/1467). - Our DAX editors now support **word based** auto complete search terms. In other words, if you type `sales ytd` in the editor, the auto complete will now suggest measures such as `[Sales Margin YTD]`, `[Sales Revenue YTD]`, etc. diff --git a/content/references/release-notes/3_22_1.md b/content/references/release-notes/3_22_1.md index de5aee18..311e34b2 100644 --- a/content/references/release-notes/3_22_1.md +++ b/content/references/release-notes/3_22_1.md @@ -50,7 +50,7 @@ Check out our [release blog](https://blog.tabulareditor.com/) to get a brief ove ## Improvements in 3.22.0 - When saving a model as a single file, the **Save file** dialog now suggests "model.bim" as the default file name. -- Updated various dependencies to their latest versions, including [AMO/TOM to 19.98.0.3](https://www.nuget.org/packages/Microsoft.AnalysisServices/). This update fixes longstanding authentication issues with Work or School accounts and repeated sign in promts. +- Updated various dependencies to their latest versions, including [AMO/TOM to 19.98.0.3](https://www.nuget.org/packages/Microsoft.AnalysisServices/). This update fixes longstanding authentication issues with Work or School accounts and repeated sign in prompts. - DAX query editor support for the [`MPARAMETER`](https://dax.guide/st/mparameter/) keyword, see [#1467](https://github.com/TabularEditor/TabularEditor3/issues/1467). - Our DAX editors now support **word based** auto complete search terms. In other words, if you type `sales ytd` in the editor, the auto complete will now suggest measures such as `[Sales Margin YTD]`, `[Sales Revenue YTD]`, etc. - With the June 2025 update of Power BI Desktop, [external tools can now perform any write operation on the semantic model](https://powerbi.microsoft.com/en-us/blog/power-bi-june-2025-feature-summary/#post-30307-_Toc269410729). As such, we no longer restrict the modeling operations available in Tabular Editor, when connecting to a model in this or newer versions of Power BI Desktop. diff --git a/content/references/release-notes/3_23_0.md b/content/references/release-notes/3_23_0.md index 3c3f3d32..b9930200 100644 --- a/content/references/release-notes/3_23_0.md +++ b/content/references/release-notes/3_23_0.md @@ -65,7 +65,7 @@ Check out our [release blog](https://blog.tabulareditor.com/) to get a brief ove - Fixed a bug where main window exceeds screen dimensions depending on resolution and DPI scaling. - Fixed toolbar customization settings such as "Large icons", "Show ScreenTips on toolbars" etc. not persisting after restarting TE3. - Fixed a visual glitch where TOM Explorer's Perspective and Language drop-down controls have duplicate buttons. -- Fixed a bunch of issues with "Peek definiton" feature: +- Fixed a bunch of issues with "Peek definition" feature: - Peek definition is closed on undo/redo operations - Peek definition is invisible when used on the last line of DAX editor - Peek definition turns invisible when the line ending of the peeked reference is deleted diff --git a/content/references/release-notes/3_2_1.md b/content/references/release-notes/3_2_1.md index 061be1cb..c2517496 100644 --- a/content/references/release-notes/3_2_1.md +++ b/content/references/release-notes/3_2_1.md @@ -39,7 +39,7 @@ - Fix BPA not running until BPA view is first shown, see issue [#367](https://github.com/TabularEditor/TabularEditor3/issues/367). - Use a single partition for AS change detection when connected to AS standard tier (which doesn't allow tables with multiple partitions). See [#336](https://github.com/TabularEditor/TabularEditor3/discussions/336). - Inherit perspective membership for columns added through schema compare. See issue [#342](https://github.com/TabularEditor/TabularEditor3/discussions/342). -- Use default network credentils for web proxy (should solve issue with 407-errors when connecting to AS behind proxy). +- Use default network credentials for web proxy (should solve issue with 407-errors when connecting to AS behind proxy). - Semantic analyzer should no longer report an error when variable references are quoted, see issue [#302](https://github.com/TabularEditor/TabularEditor3/discussions/302). - Improved display of error messages from Pivot Grids (they now appear in the **Messages view**). diff --git a/content/references/release-notes/3_4_0.md b/content/references/release-notes/3_4_0.md index ba8aec46..2199967e 100644 --- a/content/references/release-notes/3_4_0.md +++ b/content/references/release-notes/3_4_0.md @@ -68,13 +68,13 @@ Tabular Editor 3.4.0 downloads: - Fixed an issue which would sometimes cause the debugger windows to crash (showing red crosses on a white background). - Fixed an issue where the Import Table Wizard would sometimes show Dataflows with no names. - "Revert" button should always be enabled now. Moreover, a confirmation prompt is only shown when changes have been made. See [#729](https://github.com/TabularEditor/TabularEditor3/issues/729). -- Showing the field list no longer clears the Pivot Gird, see [#741](https://github.com/TabularEditor/TabularEditor3/issues/741). -- Fixed an issue where columns in the TOM Explorer would sometims be "cut off" when the application is launched. +- Showing the field list no longer clears the Pivot Grid, see [#741](https://github.com/TabularEditor/TabularEditor3/issues/741). +- Fixed an issue where columns in the TOM Explorer would sometimes be "cut off" when the application is launched. - TOM Explorer now only allows adding EntityPartitions on Power BI datasets - Fix dependency view crash issue, see [#758](https://github.com/TabularEditor/TabularEditor3/issues/758) - Fixed an issue where floating windows could spawn outside the visible screen area when the application is restarted, see [#652](https://github.com/TabularEditor/TabularEditor3/issues/652). - Fix issue with recent server not being persisted. -- Fixed a few bugs related to how actions appear in the "Model" and/or "Context" menu. For example, "Script DAX" in the Model menu, only scripted objects within the current selection, where as it was intended to script all objects in the model. +- Fixed a few bugs related to how actions appear in the "Model" and/or "Context" menu. For example, "Script DAX" in the Model menu, only scripted objects within the current selection, whereas it was intended to script all objects in the model. - Fix horizontal scrollbar behavior of text editors. - SQL Connection Dialog should now persist its changes to the connection string, see [#755](https://github.com/TabularEditor/TabularEditor3/issues/755). - Selecting a database after filtering the list in the "Choose database" dialog, now ensures that the correct database is actually loaded. See [#761](https://github.com/TabularEditor/TabularEditor3/issues/761). diff --git a/content/references/supported-files.md b/content/references/supported-files.md index 39c890a9..2e08bcd1 100644 --- a/content/references/supported-files.md +++ b/content/references/supported-files.md @@ -96,7 +96,7 @@ This format preserves the structure and properties of your objects, such as tabl This format has been supported in Tabular Editor from the early days and is a proven, though by Microsoft unsupported, method for storing your dataset objects as individual files. Thereby enabling developers to track changes in source control and collaborate on building semantic models. -There is full compatibility between Tabular Editor 2 and 3 with regards to the the JSON file structure. +There is full compatibility between Tabular Editor 2 and 3 with regards to the JSON file structure. In order to save a semantic model to JSON you must use the 'Save to Folder' option when saving the first time. Subsequent saves to a model loaded from a JSON structured model maintains the setting. it's always possible to convert a model that is in JSON to a .bim file using 'File > Save As' @@ -104,7 +104,7 @@ In order to save a semantic model to JSON you must use the 'Save to Folder' opti ![Supported File Types JSON](~/content/assets/images/file-types/te3-supported-file-json.png) 1. The overall model has a database json and each TOM headline has its own folder -2. In tables, each table exist in its own folder +2. In tables, each table exists in its own folder 3. An individual table as a TableName json file with folders for measures, columns and partitions 4. The measures on the table each have their own json file. @@ -189,7 +189,7 @@ All supporting files can be saved individually using either Ctrl+S or 'File > Sa A .te3diag file is a file format that stores the diagram of a model created with TE3. -These file can be useful for documenting the model structure and logic for other developers who work on the same project. A .te3diag file can be saved in the same folder as the model file for easy access and reference. +These files can be useful for documenting the model structure and logic for other developers who work on the same project. A .te3diag file can be saved in the same folder as the model file for easy access and reference. Diagram files are actually JSON that is stored in a Tabular Editor 3 extension. diff --git a/content/security/security-privacy.md b/content/security/security-privacy.md index 33589d35..4ae1ff99 100644 --- a/content/security/security-privacy.md +++ b/content/security/security-privacy.md @@ -59,7 +59,7 @@ Tabular Editor may perform requests to online resources (web URLs) only in the f - **License activation\*.** When Tabular Editor 3 is first launched, and at periodic intervals thereafter, the tool may perform a request to our licensing service. This request contains encrypted information about the license key entered by the user, the e-mail address of the user (if provided), the local machine name and a one-way encoded hash identifying the current installation. No other data is transmitted in this request. The purpose of this request, is to activate and validate the license key used by the installation, enforce trial limitations, as well as allowing the user to manage their installations of Tabular Editor 3 through our licensing service. - **Upgrade checks\*.** Each time Tabular Editor 3 is launched, it may perform a request to our application service, in order to determine if a newer version of Tabular Editor 3 is available. This request does not contain any data. -- **Usage telemetry\*.** By default, Tabular Editor 3 collects and transmits anonymous usage data as users interact with the tool. This data includes information about which UI objects a user interacts with and the timing of each. It also contains high-level information about the Tabular data model being edited through the tool. This information only relates to high-level properties like compatibility level and mode, number of tables, type of server (Analysis Services vs. Power BI vs. Power BI Desktop), etc. **No personally identifyable data is collected this way**, neither do we collect any information about names of objects or DAX expressions in the Tabular Object Model itself. A user may opt out of sending telemetry data to us at any point. +- **Usage telemetry\*.** By default, Tabular Editor 3 collects and transmits anonymous usage data as users interact with the tool. This data includes information about which UI objects a user interacts with and the timing of each. It also contains high-level information about the Tabular data model being edited through the tool. This information only relates to high-level properties like compatibility level and mode, number of tables, type of server (Analysis Services vs. Power BI vs. Power BI Desktop), etc. **No personally identifiable data is collected this way**, neither do we collect any information about names of objects or DAX expressions in the Tabular Object Model itself. A user may opt out of sending telemetry data to us at any point. - **Error reports\*.** When an unexpected error occurs, we transmit the stack trace and (anonymized) error message, along with an optional description provided by the user. If a user opts out of sending telemetry data, error reports will also not be sent. - **Using the DAX formatter.** (Tabular Editor 2.x only) A DAX expression may be formatted by clicking a button in Tabular Editor. In this case, the DAX expression (and nothing else) is sent to the www.daxformatter.com webservice. The first time a user clicks this button, an explicit warning message is shown, asking them to confirm their intent. Tabular Editor 3 does not perform web requests when formatting DAX code. - **DAX Optimizer**. If a user has a [Tabular Tools account](https://tabulartools.com) with a [DAX Optimizer](https://daxoptimizer.com) subscription, they will be able to browse their DAX Optimizer workspace, view issues and suggestions, and upload new VPAX files directly from within Tabular Editor 3. VPAX files contains model metadata and statistics, but no actual model *data*. The DAX Optimizer Integration feature in Tabular Editor 3 causes various requests to one or more of the below endpoints (depending on authentication type and region specified when the Tabular Tools account was created).
diff --git a/content/troubleshooting/proxy-settings.md b/content/troubleshooting/proxy-settings.md index 3699cbf1..a3a5d486 100644 --- a/content/troubleshooting/proxy-settings.md +++ b/content/troubleshooting/proxy-settings.md @@ -100,7 +100,7 @@ or if using Environment Variables, by setting the following: `` must point to a file in a directory that exists. I.e. if you want the file to be written to `c:\temp\logs\as-auth.log`, you must ensure that the directory `c:\temp\logs` exists. -The contents of this trace file is useful when contacting Microsoft support. +The contents of this trace file are useful when contacting Microsoft support. > [!IMPORTANT] > You must restart Tabular Editor 3 after making changes to the **AnalysisServices.AppSettings.json** file, or after modifying environment variables. \ No newline at end of file diff --git a/content/tutorials/data-security/data-security-about.md b/content/tutorials/data-security/data-security-about.md index 47316057..322d4d88 100644 --- a/content/tutorials/data-security/data-security-about.md +++ b/content/tutorials/data-security/data-security-about.md @@ -37,7 +37,7 @@ _Both RLS & OLS can be easily configured, modified and tested from within Tabula
WHY CONFIGURE ROW- OR OBJECT-LEVEL SECURITY?
- Configuring RLS or OLS can be benificial for your model & reporting: + Configuring RLS or OLS can be beneficial for your model & reporting:
  • Reduce risk and improve governance by ensuring users only see data they have access to.
  • Configure dynamic RLS with central role tables for consistency and lightweight maintenance.
  • Have granular control over what data and objects can be queried. diff --git a/content/tutorials/incremental-refresh/incremental-refresh-setup.md b/content/tutorials/incremental-refresh/incremental-refresh-setup.md index f6d85719..7f3a6687 100644 --- a/content/tutorials/incremental-refresh/incremental-refresh-setup.md +++ b/content/tutorials/incremental-refresh/incremental-refresh-setup.md @@ -217,7 +217,7 @@ If you have configured a native query, it may still be possible to configure and Refresh All Partitionsincremental-refresh-native-query-formatted.png -2. __Replace the Native Query String in the Source Expression:__ Copy the query and replace the existing query, which will be full of characters like (lf) (line feed), (cr) (carraige return) and (n) (new line). Doing this makes the query actually readable and editable without resorting to the Native Query user interface of Power BI Desktop. +2. __Replace the Native Query String in the Source Expression:__ Copy the query and replace the existing query, which will be full of characters like (lf) (line feed), (cr) (carriage return) and (n) (new line). Doing this makes the query actually readable and editable without resorting to the Native Query user interface of Power BI Desktop. Refresh All Partitions diff --git a/content/tutorials/new-as-model.md b/content/tutorials/new-as-model.md index 6de11a03..fce1929a 100644 --- a/content/tutorials/new-as-model.md +++ b/content/tutorials/new-as-model.md @@ -30,7 +30,7 @@ This page walks you through the process of creating a new Analysis Services tabu ![New model](https://user-images.githubusercontent.com/8976200/116813646-02a6fc80-ab55-11eb-89b0-8909b768ce7e.png) -- Provide a name for your model or use the default value. Then, choose the compatibility level depending on which version of Analysis Services you are targetting. Your options are the following: +- Provide a name for your model or use the default value. Then, choose the compatibility level depending on which version of Analysis Services you are targeting. Your options are the following: - 1200 (Works with SQL Server 2016 or newer, and Azure Analysis Services) - 1400 (Works with SQL Server 2017 or newer, and Azure Analysis Services) - 1500 (Works with SQL Server 2019 or Azure Analysis Services) @@ -48,11 +48,11 @@ Once your model is created, the next step is to add a data source and some table #### Adding a data source and tables -Before you can import data to your tabular model, you have to set up one or more data sources. Locate the TOM Explorer, right-click on the "Data Sources" folder and choose "Create". For a model that uses compatibility level 1400 or higher, we have two options: Legacy and Power Query data sources. To learn more about th differences between these two types of data sources, [consult the Microsoft Analysis Services blog](https://docs.microsoft.com/en-us/archive/blogs/analysisservices/using-legacy-data-sources-in-tabular-1400). +Before you can import data to your tabular model, you have to set up one or more data sources. Locate the TOM Explorer, right-click on the "Data Sources" folder and choose "Create". For a model that uses compatibility level 1400 or higher, we have two options: Legacy and Power Query data sources. To learn more about the differences between these two types of data sources, [consult the Microsoft Analysis Services blog](https://docs.microsoft.com/en-us/archive/blogs/analysisservices/using-legacy-data-sources-in-tabular-1400). ![Add data source](https://user-images.githubusercontent.com/8976200/124598010-72db4280-de64-11eb-818a-e5793f061185.png) -In this example, we will create a Power Query data source, which we will use to import a few tables from a SQL Server relational database. Once the data source is created, hit F2 to rename it and configure the data source using the Propery Grid as seen in the screenshot below: +In this example, we will create a Power Query data source, which we will use to import a few tables from a SQL Server relational database. Once the data source is created, hit F2 to rename it and configure the data source using the Property Grid as seen in the screenshot below: ![Set data source properties](https://user-images.githubusercontent.com/8976200/124599856-71ab1500-de66-11eb-8ede-3a6272872734.png) diff --git a/content/tutorials/udfs.md b/content/tutorials/udfs.md index 1f1002c0..3b3f4433 100644 --- a/content/tutorials/udfs.md +++ b/content/tutorials/udfs.md @@ -202,7 +202,7 @@ When you select multiple UDFs in the TOM Explorer, you can use the **Batch Renam ### Namespaces -The concept of "namespace" doesn't exist in DAX, yet the recommendation is to name UDFs in such a way that ambiguities are avoided and that the origin of the UDF is clear. For example `DaxLib.Convert.CelsiusToFahrenheit` (using '.' as namespace separators). When a UDF is named this way, the TOM Explorer will display the UDF in a hierarchy based on the names. You can toggle the display of UDFs by namespace using the **Group User-Defined Functions by namespace** tuggle button in the toolbar above the TOM Explorer (note, this button is only visible when working with a model using Compatibility Level 1702 or higher). +The concept of "namespace" doesn't exist in DAX, yet the recommendation is to name UDFs in such a way that ambiguities are avoided and that the origin of the UDF is clear. For example `DaxLib.Convert.CelsiusToFahrenheit` (using '.' as namespace separators). When a UDF is named this way, the TOM Explorer will display the UDF in a hierarchy based on the names. You can toggle the display of UDFs by namespace using the **Group User-Defined Functions by namespace** toggle button in the toolbar above the TOM Explorer (note, this button is only visible when working with a model using Compatibility Level 1702 or higher). ![DAX UDFs grouped by namespace](~/content/assets/images/udf-namespaces-tom-explorer.png) From d2f71099e3b099fb32b6fe88a566dcc1a8f15ce3 Mon Sep 17 00:00:00 2001 From: Eugene Meidinger Date: Sun, 1 Feb 2026 09:05:47 -0500 Subject: [PATCH 2/3] feat: add CI spellcheck workflow for known typos Adds a Python-based spellcheck CI that blocks PRs with 100% reliable typos. Features: - Precompiled regex patterns for performance - Skips code blocks, inline code, and YAML frontmatter - Directory pruning (os.walk) for efficiency - Excludes localizedContent (English-only check) - GitHub Actions annotations for inline PR feedback - Symlink escape protection - JSON schema validation Files: - scripts/ci_spellcheck.py: Main detection script - data/common_typos.json: 32 typo patterns - .github/workflows/spellcheck.yml: CI workflow Co-Authored-By: Claude Opus 4.5 --- .github/workflows/spellcheck.yml | 37 +++ data/common_typos.json | 44 ++++ scripts/ci_spellcheck.py | 380 +++++++++++++++++++++++++++++++ 3 files changed, 461 insertions(+) create mode 100644 .github/workflows/spellcheck.yml create mode 100644 data/common_typos.json create mode 100644 scripts/ci_spellcheck.py diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml new file mode 100644 index 00000000..1bd359a4 --- /dev/null +++ b/.github/workflows/spellcheck.yml @@ -0,0 +1,37 @@ +name: Typo Check + +on: + push: + paths: + - '**/*.md' + - 'data/common_typos.json' + - 'scripts/ci_spellcheck.py' + pull_request: + paths: + - '**/*.md' + - 'data/common_typos.json' + - 'scripts/ci_spellcheck.py' + workflow_dispatch: + +# Security: Minimal permissions +permissions: + contents: read + +jobs: + typocheck: + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Check for common typos + run: python scripts/ci_spellcheck.py diff --git a/data/common_typos.json b/data/common_typos.json new file mode 100644 index 00000000..2e6b8441 --- /dev/null +++ b/data/common_typos.json @@ -0,0 +1,44 @@ +{ + "description": "Common typos found in technical documentation. Use for simple pattern-based spellcheck.", + "version": "1.0.0", + "last_updated": "2026-02-01", + "typos": [ + {"wrong": "noticable", "correct": "noticeable", "category": "common"}, + {"wrong": "succesful", "correct": "successful", "category": "common"}, + {"wrong": "occurence", "correct": "occurrence", "category": "common"}, + {"wrong": "occured", "correct": "occurred", "category": "common"}, + {"wrong": "surronding", "correct": "surrounding", "category": "common"}, + {"wrong": "seemless", "correct": "seamless", "category": "common"}, + {"wrong": "suported", "correct": "supported", "category": "common"}, + {"wrong": "reciding", "correct": "residing", "category": "common"}, + {"wrong": "elipsis", "correct": "ellipsis", "category": "common"}, + {"wrong": "defind", "correct": "defined", "category": "common"}, + {"wrong": "chooseing", "correct": "choosing", "category": "common"}, + {"wrong": "ressource", "correct": "resource", "category": "common"}, + {"wrong": "prefered", "correct": "preferred", "category": "common"}, + {"wrong": "Pipeliens", "correct": "Pipelines", "category": "transposed"}, + {"wrong": "upate", "correct": "update", "category": "missing_letter"}, + {"wrong": "wheras", "correct": "whereas", "category": "common"}, + {"wrong": "seperate", "correct": "separate", "category": "common"}, + {"wrong": "definately", "correct": "definitely", "category": "common"}, + {"wrong": "occurance", "correct": "occurrence", "category": "common"}, + {"wrong": "accomodate", "correct": "accommodate", "category": "common"}, + {"wrong": "blick", "correct": "click", "category": "adjacent_key"}, + {"wrong": "levells", "correct": "levels", "category": "double_letter"}, + {"wrong": "colapse", "correct": "collapse", "category": "missing_letter"}, + {"wrong": "collaps", "correct": "collapse", "category": "missing_letter"}, + {"wrong": "defualt", "correct": "default", "category": "transposed"}, + {"wrong": "compatability", "correct": "compatibility", "category": "common"}, + {"wrong": "avaliable", "correct": "available", "category": "transposed"}, + {"wrong": "necesarily", "correct": "necessarily", "category": "missing_letter"}, + {"wrong": "highligting", "correct": "highlighting", "category": "missing_letter"}, + {"wrong": "descripions", "correct": "descriptions", "category": "missing_letter"}, + {"wrong": "parition", "correct": "partition", "category": "missing_letter"}, + {"wrong": "oyu", "correct": "you", "category": "transposed"} + ], + "false_positives": [ + "table-bordered", + "table-striped", + "table-condensed" + ] +} diff --git a/scripts/ci_spellcheck.py b/scripts/ci_spellcheck.py new file mode 100644 index 00000000..6f590256 --- /dev/null +++ b/scripts/ci_spellcheck.py @@ -0,0 +1,380 @@ +#!/usr/bin/env python3 +""" +CI Typo Check - Detect known typos in English markdown files. + +This script provides a reliable, fast check for 100% confirmed typos. +It scans English markdown files in the content/ directory while skipping +code blocks, inline code, YAML frontmatter, and localized content. + +For more nuanced checks, use cspell or LLM-based spellcheck. +""" + +import json +import os +import re +import sys +from pathlib import Path +from typing import NamedTuple, TypedDict + + +class TypoEntry(TypedDict): + """A typo pattern entry.""" + wrong: str + correct: str + category: str + + +class TypoData(TypedDict, total=False): + """Typo data file structure.""" + description: str + version: str + typos: list[TypoEntry] + false_positives: list[str] + + +class TypoMatch(NamedTuple): + """A typo match found in a file.""" + file: Path + line_num: int + line_text: str + typo: str + correction: str + + +class CompiledTypo(NamedTuple): + """A precompiled typo pattern.""" + pattern: re.Pattern[str] + wrong: str + correct: str + + +# Directories to skip (pruned before traversal for performance) +EXCLUDED_DIRS = { + ".git", ".github", ".vscode", ".idea", + "node_modules", "venv", ".venv", "__pycache__", + "site-packages", "dist", "build", ".cache", + "_site", "public", "output", # Generated site output + "localizedContent", # Skip non-English localized content +} + + +def load_and_validate_typo_data(data_path: Path) -> TypoData: + """Load and validate typo patterns from JSON file.""" + try: + with open(data_path, "r", encoding="utf-8") as f: + data = json.load(f) + except json.JSONDecodeError as e: + raise ValueError(f"Invalid JSON in {data_path}: {e}") from e + + # Validate structure + if "typos" not in data: + raise ValueError(f"Missing 'typos' key in {data_path}") + if not isinstance(data["typos"], list): + raise TypeError(f"'typos' must be a list in {data_path}") + + for i, entry in enumerate(data["typos"]): + if not isinstance(entry, dict): + raise TypeError(f"Typo entry {i} must be a dict") + if "wrong" not in entry or "correct" not in entry: + raise ValueError(f"Typo entry {i} missing 'wrong' or 'correct' key") + # Validate string types and non-empty values + if not isinstance(entry["wrong"], str) or not isinstance(entry["correct"], str): + raise TypeError(f"Typo entry {i} 'wrong' and 'correct' must be strings") + if not entry["wrong"].strip() or not entry["correct"].strip(): + raise ValueError(f"Typo entry {i} 'wrong' and 'correct' must be non-empty") + + return data + + +def compile_typo_patterns(typos: list[TypoEntry]) -> list[CompiledTypo]: + """Precompile regex patterns for all typos (done once, not per file).""" + compiled: list[CompiledTypo] = [] + for typo in typos: + pattern = re.compile(rf"\b{re.escape(typo['wrong'])}\b", re.IGNORECASE) + compiled.append(CompiledTypo( + pattern=pattern, + wrong=typo["wrong"], + correct=typo["correct"], + )) + return compiled + + +def compile_false_positive_patterns(false_positives: list[str]) -> list[re.Pattern[str]]: + """Precompile regex patterns for false positives with word boundaries.""" + return [ + re.compile(rf"\b{re.escape(fp)}\b", re.IGNORECASE) + for fp in false_positives + ] + + +def strip_code_blocks(content: str) -> list[tuple[int, str]]: + """ + Return lines with code blocks removed. + + Returns list of (original_line_num, line_text) tuples, + skipping lines inside fenced code blocks, indented code blocks, + and YAML frontmatter. + """ + # Strip UTF-8 BOM if present (appears at start of some files) + if content.startswith("\ufeff"): + content = content[1:] + + lines = content.splitlines() + result: list[tuple[int, str]] = [] + in_fenced_block = False + in_frontmatter = False + prev_blank = True # Track if previous line was blank (for indented code detection) + + for line_num, line in enumerate(lines, start=1): + stripped = line.strip() + + # Handle YAML frontmatter (must start at line 1, allow leading whitespace) + if line_num == 1 and stripped == "---": + in_frontmatter = True + continue + if in_frontmatter: + if stripped == "---" or stripped == "...": + in_frontmatter = False + continue + + # Check for fenced code block markers (``` or ~~~) + if stripped.startswith("```") or stripped.startswith("~~~"): + in_fenced_block = not in_fenced_block + prev_blank = False + continue + + if in_fenced_block: + prev_blank = False + continue + + # Skip indented code blocks (4+ spaces or tab after blank line) + # Per CommonMark: indented code requires preceding blank line + is_indented_code = ( + prev_blank and + len(line) > 0 and + (line.startswith(" ") or line.startswith("\t")) + ) + if is_indented_code: + # Don't update prev_blank - stay in indented code mode + continue + + # Track blank lines for indented code detection + prev_blank = len(stripped) == 0 + + if stripped: # Non-empty, non-code line + # Strip inline code: handle both `code` and ``code with `backticks` inside`` + # First handle double-backtick spans, then single-backtick spans + line_no_inline = re.sub(r"``[^`]+``", "", line) + line_no_inline = re.sub(r"`[^`]+`", "", line_no_inline) + result.append((line_num, line_no_inline)) + + return result + + +def find_typos_in_lines( + file_path: Path, + lines: list[tuple[int, str]], + compiled_typos: list[CompiledTypo], + fp_patterns: list[re.Pattern[str]], +) -> list[TypoMatch]: + """Search lines for known typos.""" + matches: list[TypoMatch] = [] + + for line_num, line in lines: + for compiled in compiled_typos: + if compiled.pattern.search(line): + # Check if this line matches a false positive pattern + if any(fp_pat.search(line) for fp_pat in fp_patterns): + continue + + matches.append(TypoMatch( + file=file_path, + line_num=line_num, + line_text=line.strip(), + typo=compiled.wrong, + correction=compiled.correct, + )) + + return matches + + +def find_repeated_words( + file_path: Path, + lines: list[tuple[int, str]], +) -> list[TypoMatch]: + """Find repeated words like 'the the' or 'is is'.""" + matches: list[TypoMatch] = [] + + # Catch any repeated word of 2+ chars (more comprehensive) + repeated_pattern = re.compile(r"\b(\w{2,})\s+\1\b", re.IGNORECASE) + + for line_num, line in lines: + # Use finditer to catch ALL repeated words on a line + for match in repeated_pattern.finditer(line): + matches.append(TypoMatch( + file=file_path, + line_num=line_num, + line_text=line.strip(), + typo=match.group(0), + correction=f"{match.group(1)} (remove duplicate)", + )) + + return matches + + +def is_safe_path(file_path: Path, project_root: Path) -> bool: + """Check if path is safely within project root (no symlink escapes).""" + try: + resolved = file_path.resolve() + root_resolved = project_root.resolve() + return resolved.is_relative_to(root_resolved) + except (OSError, ValueError): + return False + + +def escape_gha_annotation(text: str) -> str: + """Escape GitHub Actions workflow command control characters. + + GHA uses %, :, and newlines as control characters in annotations. + Escaping prevents malicious input from injecting extra annotations. + """ + return ( + text + .replace("%", "%25") + .replace("\r", "%0D") + .replace("\n", "%0A") + .replace(":", "%3A") + ) + + +def find_markdown_files(project_root: Path) -> list[Path]: + """ + Find markdown files using os.walk with directory pruning. + + Scans the entire project root while excluding build artifacts, + version control directories, and non-English localized content. + + This is more efficient than rglob() because it prunes excluded + directories BEFORE traversing into them. + """ + md_files: list[Path] = [] + + for dirpath, dirnames, filenames in os.walk(project_root): + # Prune excluded directories IN PLACE (modifies dirnames) + # This prevents os.walk from descending into them + dirnames[:] = [ + d for d in dirnames + if d not in EXCLUDED_DIRS and not d.startswith(".") + ] + + # Collect markdown files + for filename in filenames: + if filename.endswith(".md"): + file_path = Path(dirpath) / filename + # Safety check for symlinks + if is_safe_path(file_path, project_root): + md_files.append(file_path) + + return md_files + + +def main() -> int: + """Run spellcheck and return exit code.""" + # Find project root (where data/common_typos.json lives) + script_dir = Path(__file__).parent + project_root = script_dir.parent + + data_path = project_root / "data" / "common_typos.json" + if not data_path.exists(): + print(f"::error::Typo data not found at {data_path}", file=sys.stderr) + return 1 + + # Load and validate typo data + try: + typo_data = load_and_validate_typo_data(data_path) + except (ValueError, TypeError) as e: + print(f"::error::Invalid typo data file: {e}", file=sys.stderr) + return 1 + + typos = typo_data.get("typos", []) + false_positives = typo_data.get("false_positives", []) + + # Precompile all patterns ONCE (not per file) + compiled_typos = compile_typo_patterns(typos) + fp_patterns = compile_false_positive_patterns(false_positives) + + print(f"Loaded {len(typos)} typo patterns") + print(f"Loaded {len(false_positives)} false positive exclusions") + print() + + # Find markdown files with directory pruning + md_files = find_markdown_files(project_root) + + print(f"Scanning {len(md_files)} markdown files...") + print() + + # Search for typos + all_matches: list[TypoMatch] = [] + + for md_file in md_files: + try: + # Read file ONCE + content = md_file.read_text(encoding="utf-8") + except (OSError, UnicodeDecodeError) as e: + print(f"Warning: Could not read {md_file}: {e}", file=sys.stderr) + continue + + # Strip code blocks and inline code + lines = strip_code_blocks(content) + + # Find typos (pass preprocessed lines) + matches = find_typos_in_lines(md_file, lines, compiled_typos, fp_patterns) + all_matches.extend(matches) + + # Find repeated words (pass same preprocessed lines) + repeated = find_repeated_words(md_file, lines) + all_matches.extend(repeated) + + # Report results + if all_matches: + print("=" * 60) + print("TYPOS FOUND") + print("=" * 60) + print() + + # Group by file + by_file: dict[Path, list[TypoMatch]] = {} + for match in all_matches: + by_file.setdefault(match.file, []).append(match) + + for file_path, matches in sorted(by_file.items()): + rel_path = file_path.relative_to(project_root) + print(f"File: {rel_path}") + for match in matches: + # GitHub Actions annotation format for inline PR comments + # Escape control characters to prevent annotation injection + safe_typo = escape_gha_annotation(match.typo) + safe_correction = escape_gha_annotation(match.correction) + print(f"::error file={rel_path},line={match.line_num}::" + f"Typo: '{safe_typo}' should be '{safe_correction}'") + print(f" Line {match.line_num}: '{match.typo}' -> '{match.correction}'") + # Truncate long lines + line_preview = match.line_text[:80] + if len(match.line_text) > 80: + line_preview += "..." + print(f" {line_preview}") + print() + + print("=" * 60) + print(f"Total: {len(all_matches)} typo(s) found in {len(by_file)} file(s)") + print() + print("These are 100% reliable typo patterns.") + print("If a match is a false positive, add it to data/common_typos.json false_positives list.") + return 1 + else: + print(f"Typo check passed: {len(md_files)} files checked, no typos found.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 68d9a9b63e0459acdf3edf6c26ca4d48093f65c7 Mon Sep 17 00:00:00 2001 From: Eugene Meidinger Date: Mon, 2 Feb 2026 13:30:54 -0500 Subject: [PATCH 3/3] Fixed more typos and false positives --- content/how-tos/update-compatibility-level.md | 2 +- content/references/release-notes/3_10_0.md | 2 +- content/references/release-notes/3_10_1.md | 2 +- content/references/release-notes/3_11_0.md | 4 +- content/references/release-notes/3_18_1.md | 2 +- content/references/release-notes/3_18_2.md | 2 +- data/common_typos.json | 5 ++- scripts/ci_spellcheck.py | 40 +++++++++++++------ 8 files changed, 39 insertions(+), 20 deletions(-) diff --git a/content/how-tos/update-compatibility-level.md b/content/how-tos/update-compatibility-level.md index dc57dc93..64cd53b0 100644 --- a/content/how-tos/update-compatibility-level.md +++ b/content/how-tos/update-compatibility-level.md @@ -47,7 +47,7 @@ Compatibility level support differs by platform (SSAS, Azure Analysis Services, ## Update the compatibility level -![Update Compatability Level](~/content/assets/images/how-to/updatecompatabilitylevel.gif) +![Update Compatibility Level](~/content/assets/images/how-to/updatecompatabilitylevel.gif) ### Open your model diff --git a/content/references/release-notes/3_10_0.md b/content/references/release-notes/3_10_0.md index 49f7e93e..5ed8e34b 100644 --- a/content/references/release-notes/3_10_0.md +++ b/content/references/release-notes/3_10_0.md @@ -50,7 +50,7 @@ Check out our [release blog](https://blog.tabulareditor.com/2023/08/23/tabular-e ## Improvements in 3.10.0 -- We're now using using the latest version of [AMO/TOM](https://www.nuget.org/packages/Microsoft.AnalysisServices.NetCore.retail.amd64/). This update adds support for Binary XML, which should help speed up XMLA operations. More details in this [Microsoft blog post](https://powerbi.microsoft.com/en-us/blog/improving-the-communication-performance-of-xmla-based-tools/). +- We're now using the latest version of [AMO/TOM](https://www.nuget.org/packages/Microsoft.AnalysisServices.NetCore.retail.amd64/). This update adds support for Binary XML, which should help speed up XMLA operations. More details in this [Microsoft blog post](https://powerbi.microsoft.com/en-us/blog/improving-the-communication-performance-of-xmla-based-tools/). - We also updated [TMDL to preview-3](https://www.nuget.org/packages/Microsoft.AnalysisServices.Tabular.Tmdl.NetCore.retail.amd64/19.65.12.3-TmdlPreview), which includes a number of bugfixes. > [!NOTE] diff --git a/content/references/release-notes/3_10_1.md b/content/references/release-notes/3_10_1.md index 84dbd6b8..52b9d415 100644 --- a/content/references/release-notes/3_10_1.md +++ b/content/references/release-notes/3_10_1.md @@ -54,7 +54,7 @@ Check out our [release blog](https://blog.tabulareditor.com/2023/08/23/tabular-e ## Improvements in 3.10.0 -- We're now using using the latest version of [AMO/TOM](https://www.nuget.org/packages/Microsoft.AnalysisServices.NetCore.retail.amd64/). This update adds support for Binary XML, which should help speed up XMLA operations. More details in this [Microsoft blog post](https://powerbi.microsoft.com/en-us/blog/improving-the-communication-performance-of-xmla-based-tools/). +- We're now using the latest version of [AMO/TOM](https://www.nuget.org/packages/Microsoft.AnalysisServices.NetCore.retail.amd64/). This update adds support for Binary XML, which should help speed up XMLA operations. More details in this [Microsoft blog post](https://powerbi.microsoft.com/en-us/blog/improving-the-communication-performance-of-xmla-based-tools/). - We also updated [TMDL to preview-3](https://www.nuget.org/packages/Microsoft.AnalysisServices.Tabular.Tmdl.NetCore.retail.amd64/19.65.12.3-TmdlPreview), which includes a number of bugfixes. > [!NOTE] diff --git a/content/references/release-notes/3_11_0.md b/content/references/release-notes/3_11_0.md index ef56a0c2..79d8d945 100644 --- a/content/references/release-notes/3_11_0.md +++ b/content/references/release-notes/3_11_0.md @@ -45,7 +45,7 @@ Check out our [release blog](https://blog.tabulareditor.com/2023/09/25/september ## Improvements in 3.11.0 -- We're now using using the latest version of [AMO/TOM](https://www.nuget.org/packages/Microsoft.AnalysisServices.NetCore.retail.amd64/) and [TMDL](https://www.nuget.org/packages/Microsoft.AnalysisServices.Tabular.Tmdl.NetCore.retail.amd64), which includes a number of bugfixes and stability improvements. +- We're now using the latest version of [AMO/TOM](https://www.nuget.org/packages/Microsoft.AnalysisServices.NetCore.retail.amd64/) and [TMDL](https://www.nuget.org/packages/Microsoft.AnalysisServices.Tabular.Tmdl.NetCore.retail.amd64), which includes a number of bugfixes and stability improvements. > [!NOTE] > TMDL is still in preview, and as such, this feature must also be considered a preview feature of Tabular Editor 3. Make sure to keep a Model.bim / Database.json backup of your model metadata to avoid losing work. @@ -59,7 +59,7 @@ Check out our [release blog](https://blog.tabulareditor.com/2023/09/25/september - Autocomplete now suggests proper keywords for the *<Skip>* parameter of DAX window functions such as [`RANK`](https://dax.guide), etc. - Batch Rename now works for folders, see [#797](https://github.com/TabularEditor/TabularEditor3/issues/797). - Fixed some issues regarding custom layouts, see [#711](https://github.com/TabularEditor/TabularEditor3/issues/711). Also fixed an issue where customizations to the built-in menus, were not properly persisted. -- Fixed a bug in the Deployment Wizard, when the model contains an incremental refresh table with no partitions. In this case, the deployment wizard UI did not allow the user to skip partition deployment of this table which would cause an invalid TMSL to be generated generated (one with no partitions for the table in question). +- Fixed a bug in the Deployment Wizard, when the model contains an incremental refresh table with no partitions. In this case, the deployment wizard UI did not allow the user to skip partition deployment of this table which would cause an invalid TMSL to be generated (one with no partitions for the table in question). - Fixed a bug, where running a DAX query with no whitespace between [`EVALUATE`](https://dax.guide) and the following expression would cause an error. - Fixed numerous issues with the DAX debugger. See [#954](https://github.com/TabularEditor/TabularEditor3/issues/954), [#971](https://github.com/TabularEditor/TabularEditor3/issues/971) and [#984](https://github.com/TabularEditor/TabularEditor3/issues/984). diff --git a/content/references/release-notes/3_18_1.md b/content/references/release-notes/3_18_1.md index fb97deb2..2bc71e1f 100644 --- a/content/references/release-notes/3_18_1.md +++ b/content/references/release-notes/3_18_1.md @@ -48,7 +48,7 @@ Tabular Editor 3.18.1 **.NET 6** downloads: ## Improvements in 3.18.1 -- The Semantic Analyzer no longer displays an error when using a table table name as the name of a variable. **Note:** as of this writing, the ability to use table names for variables is supported in Power BI Desktop (October 2024) and in the Power BI Service. You can control the error behavior under **Tools > Preferences > DAX Editor > DAX Settings > Table-named variables**. +- The Semantic Analyzer no longer displays an error when using a table name as the name of a variable. **Note:** as of this writing, the ability to use table names for variables is supported in Power BI Desktop (October 2024) and in the Power BI Service. You can control the error behavior under **Tools > Preferences > DAX Editor > DAX Settings > Table-named variables**. - We've updated the AMO/TOM client libraries to the latest version [19.86.6](https://www.nuget.org/packages/Microsoft.AnalysisServices/19.86.6). This should fix the **Can't obtain account information for '(e-mail)' while trying to refresh the token.** issue that some users have experienced while connected to the Power BI XMLA endpoint, see [#1387](https://github.com/TabularEditor/TabularEditor3/issues/1387). - A new option under **Tools > Preferences > Power BI** let you specify the default authentication mode to use when connecting to Power BI / Fabric workspaces or Azure Analysis Services. This lets you, for example, specify `Microsoft Entra MFA` by default, forcing the account selector/MFA popup to show up when connecting. - For multi-user licenses, we now show an option to change the license key, if the number of users on the license has been exceeded. This way, you no longer have to manually reset the license key [through the Windows registry](https://docs.tabulareditor.com/te3/getting-started.html#changing-a-license-key-through-the-registry). diff --git a/content/references/release-notes/3_18_2.md b/content/references/release-notes/3_18_2.md index 818fb3b5..9b95477e 100644 --- a/content/references/release-notes/3_18_2.md +++ b/content/references/release-notes/3_18_2.md @@ -53,7 +53,7 @@ Tabular Editor 3.18.2 **.NET 6** downloads: ## Improvements in 3.18.1 -- The Semantic Analyzer no longer displays an error when using a table table name as the name of a variable. **Note:** as of this writing, the ability to use table names for variables is supported in Power BI Desktop (October 2024) and in the Power BI Service. You can control the error behavior under **Tools > Preferences > DAX Editor > DAX Settings > Table-named variables**. +- The Semantic Analyzer no longer displays an error when using a table name as the name of a variable. **Note:** as of this writing, the ability to use table names for variables is supported in Power BI Desktop (October 2024) and in the Power BI Service. You can control the error behavior under **Tools > Preferences > DAX Editor > DAX Settings > Table-named variables**. - We've updated the AMO/TOM client libraries to the latest version [19.86.6](https://www.nuget.org/packages/Microsoft.AnalysisServices/19.86.6). This should fix the **Can't obtain account information for '(e-mail)' while trying to refresh the token.** issue that some users have experienced while connected to the Power BI XMLA endpoint, see [#1387](https://github.com/TabularEditor/TabularEditor3/issues/1387). - A new option under **Tools > Preferences > Power BI** let you specify the default authentication mode to use when connecting to Power BI / Fabric workspaces or Azure Analysis Services. This lets you, for example, specify `Microsoft Entra MFA` by default, forcing the account selector/MFA popup to show up when connecting. - For multi-user licenses, we now show an option to change the license key, if the number of users on the license has been exceeded. This way, you no longer have to manually reset the license key [through the Windows registry](https://docs.tabulareditor.com/te3/getting-started.html#changing-a-license-key-through-the-registry). diff --git a/data/common_typos.json b/data/common_typos.json index 2e6b8441..6ceb1c02 100644 --- a/data/common_typos.json +++ b/data/common_typos.json @@ -39,6 +39,9 @@ "false_positives": [ "table-bordered", "table-striped", - "table-condensed" + "table-condensed", + "Power Query query", + "Column column", + "Table table" ] } diff --git a/scripts/ci_spellcheck.py b/scripts/ci_spellcheck.py index 6f590256..8f5af401 100644 --- a/scripts/ci_spellcheck.py +++ b/scripts/ci_spellcheck.py @@ -107,13 +107,19 @@ def compile_false_positive_patterns(false_positives: list[str]) -> list[re.Patte ] -def strip_code_blocks(content: str) -> list[tuple[int, str]]: +def strip_code_blocks(content: str, strip_inline: bool = True) -> list[tuple[int, str]]: """ Return lines with code blocks removed. Returns list of (original_line_num, line_text) tuples, skipping lines inside fenced code blocks, indented code blocks, and YAML frontmatter. + + Args: + content: The markdown content to process. + strip_inline: If True, also strip inline code (`code`). Set to False + for repeated word detection to avoid false positives + like "as `code` as" being detected as "as as". """ # Strip UTF-8 BOM if present (appears at start of some files) if content.startswith("\ufeff"): @@ -162,11 +168,14 @@ def strip_code_blocks(content: str) -> list[tuple[int, str]]: prev_blank = len(stripped) == 0 if stripped: # Non-empty, non-code line - # Strip inline code: handle both `code` and ``code with `backticks` inside`` - # First handle double-backtick spans, then single-backtick spans - line_no_inline = re.sub(r"``[^`]+``", "", line) - line_no_inline = re.sub(r"`[^`]+`", "", line_no_inline) - result.append((line_num, line_no_inline)) + if strip_inline: + # Strip inline code: handle both `code` and ``code with `backticks` inside`` + # First handle double-backtick spans, then single-backtick spans + line_no_inline = re.sub(r"``[^`]+``", "", line) + line_no_inline = re.sub(r"`[^`]+`", "", line_no_inline) + result.append((line_num, line_no_inline)) + else: + result.append((line_num, line)) return result @@ -201,6 +210,7 @@ def find_typos_in_lines( def find_repeated_words( file_path: Path, lines: list[tuple[int, str]], + fp_patterns: list[re.Pattern[str]], ) -> list[TypoMatch]: """Find repeated words like 'the the' or 'is is'.""" matches: list[TypoMatch] = [] @@ -209,6 +219,10 @@ def find_repeated_words( repeated_pattern = re.compile(r"\b(\w{2,})\s+\1\b", re.IGNORECASE) for line_num, line in lines: + # Skip lines that match false positive patterns + if any(fp_pat.search(line) for fp_pat in fp_patterns): + continue + # Use finditer to catch ALL repeated words on a line for match in repeated_pattern.finditer(line): matches.append(TypoMatch( @@ -324,15 +338,17 @@ def main() -> int: print(f"Warning: Could not read {md_file}: {e}", file=sys.stderr) continue - # Strip code blocks and inline code - lines = strip_code_blocks(content) + # Strip code blocks and inline code for typo detection + lines_stripped = strip_code_blocks(content, strip_inline=True) - # Find typos (pass preprocessed lines) - matches = find_typos_in_lines(md_file, lines, compiled_typos, fp_patterns) + # Find typos (pass preprocessed lines with inline code stripped) + matches = find_typos_in_lines(md_file, lines_stripped, compiled_typos, fp_patterns) all_matches.extend(matches) - # Find repeated words (pass same preprocessed lines) - repeated = find_repeated_words(md_file, lines) + # For repeated words, keep inline code to avoid false positives + # like "as `code` as" being detected as "as as" + lines_with_inline = strip_code_blocks(content, strip_inline=False) + repeated = find_repeated_words(md_file, lines_with_inline, fp_patterns) all_matches.extend(repeated) # Report results