Blog

PowerApps Functions

On 30/09/2022

PowerApps functions

Parse text to number

    Filter('Workflow Tasks'; ID = Value(txtId.Text))

Add datas (listItem)

    Patch(NewVoie;Defaults(NewVoie);{Num_x00e9_rovoie:"0"&LookUp(NewVoie;ID=1).Num_x00e9_rovoie}))

Update context, and forms datas

    SubmitForm(FormBeneficiaires);;ResetForm(FormBeneficiaires);; NewForm(FormBeneficiaires);; UpdateContext({showPopup:false});

        If(IsBlankOrError(SubmitForm(Form1)), Set(saveStatus, "An error occured" & Form1.Error), Set(saveStatus, "Operation succeded"))

Navigate to another form

    Navigate(Page_infos_enregistrements)

Get query string parameter and set a variable

    Set(InitiativeId; Param("ID"))

Getquerystringparam

 

Get a field from your datasource by ID

    First(Filter(Initiatives; ID=1)).Nom

 

And Or Not

Or(And(Radio1.Selected.Value=4; !IsBlank(txtComment.Text));Radio1.Selected.Value<4)

 

Update Lookup Field

Patch(
        ResultatAnalyses;
        First(//here item to update
            Filter(
                ResultatAnalyses;
                Affaire.Id = currentAffaire.ID And Analyse.Id = ThisItem.ID
            )
        );
        {
            Title: "notused";
            Commentaires: txtGalComment.Text;
            Gravite: Rating1.Value;
            Affaire: {//lookup field name
                Id: currentAffaire.ID;//id of lookup
                Value: LookUp(
                    Affaires;//list who contains lookup value
                    ID = currentAffaire.ID;//id of lookup
                    currentAffaire.Title//title of lookup value
                )
            }
        }
    )

Patch Choice

TypeIntervention: {Value: dtvTypeIntervention.Selected.Value}

Execute automate with json

'My workflow'.Run(
	JSON(
		{
			SolutionId: selectedSolution.ID,
			ImageContent: UploadedImage14.Image
		},
		JSONFormat.IncludeBinaryData
	)
);

Reg ex to get cleaned string

Clear(AttachmentsCollection);
ForAll(
      RenameColumns(DataCardValue91.Attachments, "Name", "Name1"),
      Collect(
             AttachmentsCollection,
             Name1
      )
);Set(Title1, First(AttachmentsCollection).Value);Set(FileName1, Concat( Split(First(AttachmentsCollection).Value, "" ), If( IsMatch(Result, "([^A-Za-z0-9\.\-])" ), "",Result ) ))

Save Form

SubmitForm(Form1);;If(!IsBlankOrError( Form1.Error); Notify("Une erreur est survenue lors de la sauvegarde " & Form1.Error; NotificationType.Error);Notify("La savegarde a réussi";NotificationType.Information);;Set(currentElement; Form1.LastSubmit))

 

Sort columns


Set(Month, Distinct(SortByColumns(CurrentMonthMails, "Year", Ascending, "Month", Ascending), Month))

Set date


Set(StartDate, DateAdd(DateTimeValue( Day(Today) &"/"& Month(Today) &"/"& Year(Today) &" 00:00:00"), -30));

Sum


Sum(Filter(CurrentMonthMails, Month = ThisItem.Result ), uniqMails)

 

REGexFrancais

On 04/02/2025

Les RegEx de définir des motifs de recherche complexes et de les appliquer à des chaînes de texte. Voici une explication détaillée de leur fonctionnement :

1. Création d'une Expression Régulière

En JavaScript, vous pouvez créer une expression régulière de deux manières :

- Littérale : En utilisant des barres obliques `/`.
- Objet `RegExp` : En utilisant le constructeur `RegExp`.

Exemple Littéral :
javascript
let regex = /motif/;


Exemple avec `RegExp` :
javascript
let regex = new RegExp("motif");


2. Utilisation des Expressions Régulières

Les expressions régulières peuvent être utilisées avec plusieurs méthodes de chaînes de caractères et d'objets `RegExp`.

Méthodes de Chaînes de Caractères :

- `search()` : Recherche une correspondance et retourne l'index de la première occurrence.
- `match()` : Recherche toutes les correspondances et retourne un tableau des résultats.
- `replace()` : Remplace les correspondances par une autre chaîne.
- `split()` : Divise une chaîne en un tableau basé sur les correspondances.

Méthodes de l'Objet `RegExp` :

- `test()` : Vérifie si une chaîne contient une correspondance.
- `exec()` : Recherche une correspondance et retourne un tableau d'informations sur la correspondance.

3. Exemples Pratiques

Rechercher une Correspondance :
javascript
let str = "Bonjour, monde!";
let regex = /monde/;
let result = str.search(regex); // Retourne 9


Trouver Toutes les Correspondances :
javascript
let str = "Bonjour, monde! Bonjour, tout le monde!";
let regex = /Bonjour/g; // Le flag 'g' signifie global, pour trouver toutes les occurrences
let result = str.match(regex); // Retourne ["Bonjour", "Bonjour"]


Remplacer des Correspondances :
javascript
let str = "Bonjour, monde!";
let regex = /monde/;
let result = str.replace(regex, "univers"); // Retourne "Bonjour, univers!"


Diviser une Chaîne :
javascript
let str = "un,deux,trois";
let regex = /,/;
let result = str.split(regex); // Retourne ["un", "deux", "trois"]


Tester une Correspondance :
javascript
let str = "Bonjour, monde!";
let regex = /monde/;
let result = regex.test(str); // Retourne true


Utiliser `exec()` :
javascript
let str = "Bonjour, monde!";
let regex = /monde/;
let result = regex.exec(str); // Retourne ["monde", index: 9, input: "Bonjour, monde!", groups: undefined]


4. Flags (Drapeaux)

Les expressions régulières peuvent inclure des flags pour modifier leur comportement :

- `i` : Ignore la casse (case-insensitive).
- `g` : Recherche globalement (trouve toutes les occurrences).
- `m` : Mode multi-ligne (traiter chaque ligne séparément).
- `s` : Mode dotAll (le point `.` correspond aussi aux sauts de ligne).
- `u` : Mode Unicode.
- `y` : Mode sticky (recherche à partir de la position `lastIndex`).

Exemple avec Flags :
javascript
let regex = /bonjour/i; // Ignore la casse
let result = regex.test("Bonjour"); // Retourne true


5. Motifs de Recherche

Les expressions régulières permettent de définir des motifs complexes :

- `^` : Début de la chaîne.
- `$` : Fin de la chaîne.
- `.` : N'importe quel caractère sauf un saut de ligne.
- `\d` : Un chiffre.
- `\w` : Un caractère alphanumérique.
- `\s` : Un espace blanc.
- `*` : Zéro ou plusieurs occurrences du motif précédent.
- `+` : Une ou plusieurs occurrences du motif précédent.
- `?` : Zéro ou une occurrence du motif précédent.
- `{n}` : Exactement `n` occurrences du motif précédent.
- `{n,m}` : Entre `n` et `m` occurrences du motif précédent.

Exemple de Motif Complexe :
javascript
let regex = /^\d{3}-\d{2}-\d{4}$/; // Correspond à un numéro de sécurité sociale américain
let result = regex.test("123-45-6789"); // Retourne true


Conclusion

Les expressions régulières en JavaScript sont un outil puissant pour manipuler des chaînes de caractères. Elles permettent de définir des motifs de recherche complexes et de les appliquer à des chaînes de texte de manière flexible et efficace. En maîtrisant les motifs de recherche et les méthodes associées, vous pouvez accomplir des tâches de traitement de texte avancées.

Understanding Regular Expressions RegEX Javascript

On 04/02/2025

Understanding Regular Expressions (RegEX) in JavaScript

Regular expressions (RegEX) in JavaScript are a powerful tool for searching and manipulating strings. They allow you to define complex search patterns and apply them to text strings. Here is a detailed explanation of how they work:

1. Creating a Regular Expression

In JavaScript, you can create a regular expression in two ways:

  • Literal: Using slashes /.
  • RegExp Object: Using the RegExp constructor.

Literal Example:

let regex = /pattern/;

RegExp Object Example:

let regex = new RegExp("pattern");

2. Using Regular Expressions

Regular expressions can be used with several string methods and RegExp object methods.

String Methods:

  • search(): Searches for a match and returns the index of the first occurrence.
  • match(): Searches for all matches and returns an array of results.
  • replace(): Replaces matches with another string.
  • split(): Splits a string into an array based on matches.

RegExp Object Methods:

  • test(): Checks if a string contains a match.
  • exec(): Searches for a match and returns an array of information about the match.

3. Practical Examples

Search for a Match:

let str = "Hello, world!"; let regex = /world/; let result = str.search(regex); // Returns 7

Find All Matches:

 


let str = "Hello, world! Hello, everyone!"; 
let regex = /Hello/g; // The 'g' flag means global, to find all occurrences 
let result = str.match(regex); // Returns ["Hello", "Hello"] 

 

Replace Matches:

let str = "Hello, world!"; let regex = /world/; let result = str.replace(regex, "universe"); // Returns "Hello, universe!"

Split a String:

let str = "one,two,three"; let regex = /,/; let result = str.split(regex); // Returns ["one", "two", "three"]

Test for a Match:

let str = "Hello, world!"; let regex = /world/; let result = regex.test(str); // Returns true

Use exec():

let str = "Hello, world!"; let regex = /world/; let result = regex.exec(str); // Returns ["world", index: 7, input: "Hello, world!", groups: undefined]

4. Flags

Regular expressions can include flags to modify their behavior:

  • i: Case-insensitive.
  • g: Global search (find all occurrences).
  • m: Multi-line mode (treat each line separately).
  • s: DotAll mode (the dot . matches newlines).
  • u: Unicode mode.
  • y: Sticky mode (search from the lastIndex position).

Example with Flags:

let regex = /hello/i; // Case-insensitive let result = regex.test("Hello"); // Returns true

5. Search Patterns

Regular expressions allow you to define complex patterns:

  • ^: Start of the string.
  • $: End of the string.
  • .: Any character except a newline.
  • \d: A digit.
  • \w: An alphanumeric character.
  • \s: A whitespace character.
  • *: Zero or more occurrences of the preceding pattern.
  • +: One or more occurrences of the preceding pattern.
  • ?: Zero or one occurrence of the preceding pattern.
  • {n}: Exactly n occurrences of the preceding pattern.
  • {n,m}: Between n and m occurrences of the preceding pattern.

Complex Pattern Example:

 


let regex = /^\d{3}-\d{2}-\d{4}$/; // Matches a US Social Security Number 
let result = regex.test("123-45-6789"); // Returns true 

 

Conclusion

Regular expressions in JavaScript are a powerful tool for manipulating strings. They allow you to define complex search patterns and apply them to text strings flexibly and efficiently. By mastering search patterns and associated methods, you can accomplish advanced text processing tasks.

SharePoint Sites.Selected

On 03/02/2025

How to give permission for an Azure app you has permission : Sites.Selected

You must be admin of Azure

In Graph Explorer use this request to get the Azure Id of you Site

Add for permission Sites.selected and Site.FullControl for the account (in modify permissions Tab)

Graphexplorerpermissions

 

https://graph.microsoft.com/v1.0/sites/m365x87466739.sharepoint.com:/sites/allcompany?$select=id

replace the m365x87466739 by your Tenant name, and allcompany by the name / url of your site, 

it wiil returns you the azure id of your site


{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#sites(id)/$entity",
    "id": "m365x87466739.sharepoint.com,1dc83cb4-d304-4afa-a0ff-cf33270f1c8b,e615f00e-ac05-4dfc-928e-e51688e8273b"
}

Then post a news query https://graph.microsoft.com/v1.0/sites/m365x87466739.sharepoint.com,1dc83cb4-d304-4afa-a0ff-cf33270f1c8b,e615f00e-ac05-4dfc-928e-e51688e8273b/permissions

 


{
  "roles": ["write"],//permission level you want to give
  "grantedToIdentities": [{
    "application": {
      "id": "9fb5c53a-5f25-4100-ba33-9a4595390c27",//this is you App Id
      "displayName": "AppSharePointDocebo"
    }
  }]
}

then you can use Connect-PnPOnline -Url $siteUrl -ClientId $clientId -Thumbprint $thumbprint -Tenant $tenantId

Postsite selectedpng

 

Fileshare Migration to SharePoint

On 07/01/2025

Use SharePoint Migration Tool to upload your folder in a document library, here base settings in a json file

{
  "Tasks": [
    {
      "SourcePath": "\\\\mySite.fr\\divisions\\Processed matrices\\Doc1",
      "TargetPath": "https://test.sharepoint.com/sites/test1",
      "TargetList": "FDbase",
      "TargetListRelativePath": "Satellites/Doc1",
      "Options": {
        "PreserveFileSharePermissions": false,
        "MigrateHiddenFiles": true,
        "MigrateReadOnlyFiles": true,
        "PreserveLastModifiedTime": true,
        "PreserveCreatedTime": true,
        "SkipEmptyFolders": false
      }
    }
  ]
}

SPFX react Hooks

On 18/12/2024

Base hooks context


import { WebPartContext } from "@microsoft/sp-webpart-base";

export interface iMAContext {
    context: WebPartContext;
}

component


import * as React from 'react';
import styles from './MaCountries.module.scss';
import type { IMaCountriesProps } from './IMaCountriesProps';
import { iMAContext } from '../../../entities/iMAContext';
//import { escape } from '@microsoft/sp-lodash-subset';

export const MaCountriesContext = React.createContext({} as iMAContext);
export const MaCountries: React.FunctionComponent = (props: IMaCountriesProps) => {
  
  return (
        <MaCountriesContext.Provider value={{ context: props.context }}><div>
dfvdfv
</div>
</MaCountriesContext.Provider > ); };

webpart


import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
  type IPropertyPaneConfiguration,
  PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { IReadonlyTheme } from '@microsoft/sp-component-base';

import * as strings from 'MaCountriesWebPartStrings';
import { MaCountries } from './components/MaCountries';
import { IMaCountriesProps } from './components/IMaCountriesProps';

export interface IMaCountriesWebPartProps {
  description: string;
}

export default class MaCountriesWebPart extends BaseClientSideWebPart {
 private _isDarkTheme: boolean;
  public render(): void {
    const element: React.ReactElement = React.createElement(
      MaCountries,
      {
        description: this.properties.description,
        context: this.context,
        isDarkTheme: this._isDarkTheme
      }
    );

    ReactDom.render(element, this.domElement);
  }

  protected onInit(): Promise {
    return this._getEnvironmentMessage().then(message => {
    });
  }

  private _getEnvironmentMessage(): Promise {
    if (!!this.context.sdks.microsoftTeams) { // running in Teams, office.com or Outlook
      return this.context.sdks.microsoftTeams.teamsJs.app.getContext()
        .then(context => {
          let environmentMessage: string = '';
          switch (context.app.host.name) {
            case 'Office': // running in Office
              environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOffice : strings.AppOfficeEnvironment;
              break;
            case 'Outlook': // running in Outlook
              environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOutlook : strings.AppOutlookEnvironment;
              break;
            case 'Teams': // running in Teams
            case 'TeamsModern':
              environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentTeams : strings.AppTeamsTabEnvironment;
              break;
            default:
              environmentMessage = strings.UnknownEnvironment;
          }

          return environmentMessage;
        });
    }

    return Promise.resolve(this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentSharePoint : strings.AppSharePointEnvironment);
  }

  protected onThemeChanged(currentTheme: IReadonlyTheme | undefined): void {
    if (!currentTheme) {
      return;
    }

    this._isDarkTheme = !!currentTheme.isInverted;
    const {
      semanticColors
    } = currentTheme;

    if (semanticColors) {
      this.domElement.style.setProperty('--bodyText', semanticColors.bodyText || null);
      this.domElement.style.setProperty('--link', semanticColors.link || null);
      this.domElement.style.setProperty('--linkHovered', semanticColors.linkHovered || null);
    }

  }

  protected onDispose(): void {
    ReactDom.unmountComponentAtNode(this.domElement);
  }

  protected get dataVersion(): Version {
    return Version.parse('1.0');
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          header: {
            description: strings.PropertyPaneDescription
          },
          groups: [
            {
              groupName: strings.BasicGroupName,
              groupFields: [
                PropertyPaneTextField('description', {
                  label: strings.DescriptionFieldLabel
                })
              ]
            }
          ]
        }
      ]
    };
  }
}


hide native CSS


@import '~@fluentui/react/dist/sass/References.scss';

div[data-automation-id="pageHeader"] {
    display: none;
}

Shared css


@import '~@fluentui/react/dist/sass/References.scss';

/* remove this color TODO*/
html,
body {
    background-color: #d2d9dd !important;
}

:global root-148.root-148.root-148.root-148.root-148 {
    background-color: #d2d9dd !important;
}

:global CanvasSection {
    background-color: #d2d9dd !important;
}
//global, hide not decored css or native hoverride
:global .fui-DatePicker__popupSurface {
    background-color: #fff;
}

/* end remove this color TODO*/
$eulightBlue: #007dba;
$eulightDark: #10377A;
$euAlert: #AB0000;
$euGrey: #ECF6FA;
$euligthGrey: #D8E4EA;
$euTextColor: #4C7A8F;
$euAlertOrange: #E38100;
$euOkGreen: #00B400;
$red: #FA505C;

//bold
$fontBoldWeight: 600;
$fontBoldSize: 14px;
//bolder
$fontBolderWeight: 600;
$fontBolderSize: 16px;
//normal
$fontNormalWeight: 500;
$fontNormalSize: 12px;
//small
$fontSmallWeight: 500;
$fontSmallSize: 10px;

.shared {
    .eutclear {
        display: block;
        clear: both;
        line-height: 0;
    }

    .eutclearfix:before,
    .eutclearfix:after {
        display: table;
        clear: both;
        content: '';
    }

    .container {
        // border: 1px solid black;
        width: 100%;
        // margin-right: auto;
        // margin-left: auto;
    }

    @media (min-width: 576px) {
        .container {
            max-width: 540px;
        }
    }

    @media (min-width: 768px) {
        .container {
            max-width: 720px;
        }
    }

    @media (min-width: 992px) {
        .container {
            max-width: 960px;
        }
    }

    @media (min-width: 1200px) {
        .container {
            max-width: 1140px;
        }
    }

    .containerFluid {
        width: 100%;
        padding-right: 15px;
        padding-left: 15px;
        margin-right: auto;
        margin-left: auto;
    }

    .row {
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        -ms-flex-wrap: wrap;
        flex-wrap: wrap;
    }

    .col3 {
        margin: auto;
        -webkit-box-flex: 0;
        max-width: 100%;
        flex: none;
        -ms-flex: none;
    }

    @media (min-width: 576px) {
        .col3 {
            max-width: 100%;
            flex: none;
            -ms-flex: none;
        }
    }

    @media (min-width: 768px) {
        .col3 {
            -webkit-box-flex: 0;
            -ms-flex: 0 0 32%;
            flex: 0 0 32%;
            max-width: 32%;
        }
    }

    @media (min-width: 992px) {
        .col3 {
            -webkit-box-flex: 0;
            -ms-flex: 0 0 31%;
            flex: 0 0 31%;
            max-width: 31%;
        }
    }

    @media (min-width: 1200px) {
        .col3 {
            -webkit-box-flex: 0;
            -ms-flex: 0 0 32%;
            flex: 0 0 32%;
            max-width: 32%;
        }
    }
}

In Office

Excel Count Distinct Rows

On 16/12/2024

Group Data Table

Id Group Name   Group Count
1 Group1 Dietrich   Group1 3
2 Group1 toto   Group2 2
3 Group1 titi   Group3 1
4 Group2 nana      
5 Group2 popo      
6 Group3 pipi      

 

Unique value : =UNIQUE(B2:B7), for a specific sheet : =UNIQUE(Append1_1!F2:F337888)// here Append1_1 is the name of the sheet

Count unique value : =COUNTIF(B2:B7,F1)

 

Group Count
Group1 3
Group2 2
Group3 1
In Office

Excel Power Query Functions

On 16/12/2024

Power Query Functions with Examples

Function Description Example
Table.AddColumn Adds a new column to a table. Table.AddColumn(Source, "NewColumn", each [OldColumn] * 2)
Table.RemoveColumns Removes one or more columns from a table. Table.RemoveColumns(Source, {"Column1", "Column2"})
Table.SelectRows Filters rows based on a condition. Table.SelectRows(Source, each [Age] > 18)
Table.Sort Sorts a table by one or more columns. Table.Sort(Source, {{"ColumnName", Order.Ascending}})
Text.Upper Converts text to uppercase. Text.Upper("hello") returns HELLO
Text.Lower Converts text to lowercase. Text.Lower("HELLO") returns hello
Text.Combine Combines a list of text values into one. Text.Combine({"Hello", "World"}, " ") returns Hello World
Number.Round Rounds a number to a specified number of digits. Number.Round(3.14159, 2) returns 3.14
DateTime.LocalNow Returns the current date and time. DateTime.LocalNow()
List.Sum Calculates the sum of a list of numbers. List.Sum({1, 2, 3, 4}) returns 10
List.Distinct Removes duplicate values from a list. List.Distinct({1, 2, 2, 3}) returns {1, 2, 3}
Record.Field Gets the value of a field in a record. Record.Field([Record], "FieldName")
Record.AddField Adds a field to a record. Record.AddField([Record], "NewField", 123)
Table.AddColumn Adds a new column to a table. Table.AddColumn(Source, "NewColumn", each [OldColumn] * 2)
Table.RemoveColumns Removes one or more columns from a table. Table.RemoveColumns(Source, {"Column1", "Column2"})
Table.SelectRows Filters rows based on a condition. Table.SelectRows(Source, each [Age] > 18)
Table.Sort Sorts a table by one or more columns. Table.Sort(Source, {{"ColumnName", Order.Ascending}})
Text.Upper Converts text to uppercase. Text.Upper("hello") returns HELLO
Text.Lower Converts text to lowercase. Text.Lower("HELLO") returns hello
Text.Combine Combines a list of text values into one. Text.Combine({"Hello", "World"}, " ") returns Hello World
Number.Round Rounds a number to a specified number of digits. Number.Round(3.14159, 2) returns 3.14
DateTime.LocalNow Returns the current date and time. DateTime.LocalNow()
List.Sum Calculates the sum of a list of numbers. List.Sum({1, 2, 3, 4}) returns 10
List.Average Calculates the average of a list of numbers. List.Average({1, 2, 3, 4}) returns 2.5
List.Max Returns the maximum value from a list. List.Max({1, 2, 3, 4}) returns 4
List.Min Returns the minimum value from a list. List.Min({1, 2, 3, 4}) returns 1
List.Count Counts the number of items in a list. List.Count({1, 2, 3, 4}) returns 4
List.Distinct Removes duplicate values from a list. List.Distinct({1, 2, 2, 3}) returns {1, 2, 3}
List.Length Returns the length of a list. List.Length({1, 2, 3, 4}) returns 4
Record.Field Gets the value of a field in a record. Record.Field([Record], "FieldName")
Record.AddField Adds a field to a record. Record.AddField([Record], "NewField", 123)