- Home
- Blog
Blog
On 05/09/2024
Introduction
Le développement de composants pour SharePoint Framework (SPFx) en utilisant React nécessite une attention particulière aux pratiques CSS pour garantir que vos interfaces sont responsives et adaptées à tous les types d'écrans, que ce soit sur mobile, tablette ou desktop.
1. Principes de Base pour des CSS Responsives
1. Unité Relative :
- Utilisez des unités relatives comme `%`, `em`, `rem`, `vh`, et `vw` pour les marges, les paddings, et les dimensions. Cela permet aux éléments de s’adapter dynamiquement à la taille de l'écran.
2. Media Queries :
- Utilisez des media queries pour ajuster les styles en fonction de la taille de l'écran. Par exemple, pour les écrans de moins de 768px de largeur (taille de tablette), vous pouvez ajuster les layouts.
css
@media (max-width: 768px) {
.container {
flex-direction: column;
}
}
3. Flexbox :
- Utilisez Flexbox pour créer des layouts flexibles qui peuvent s'adapter facilement aux différentes tailles d'écran. Flexbox est particulièrement utile pour les barres de navigation, les formulaires, et les mises en page de cartes.
css
.form-container {
display: flex;
flex-wrap: wrap;
}
.form-group {
flex: 1 1 300px; /* Les groupes de formulaire s'ajustent avec un minimum de 300px */
margin: 10px;
}
4. Grid Layout :
- Pour des mises en page plus complexes, comme des tableaux de données ou des calendriers, utilisez CSS Grid. Cela permet de contrôler avec précision la disposition des éléments sur la page.
2. Exemple de Formulaire Responsive
Voici un exemple de formulaire avec différents types d'entrées HTML, construit en React et avec une mise en page responsive.
HTML/JSX pour le Formulaire
jsx
import * as React from 'react';
import './Form.css';
const ResponsiveForm = () => {
return (
<form className="form-container">
<div className="form-group">
<label htmlFor="name">Nom:</label>
<input type="text" id="name" name="name" placeholder="Votre nom" />
</div>
<div className="form-group">
<label htmlFor="email">Email:</label>
<input type="email" id="email" name="email" placeholder="Votre email" />
</div>
<div className="form-group">
<label htmlFor="date">Date:</label>
<input type="date" id="date" name="date" />
</div>
<div className="form-group">
<label htmlFor="color">Couleur:</label>
<input type="color" id="color" name="color" />
</div>
<div className="form-group">
<label>Sexe:</label>
<input type="radio" id="male" name="gender" value="male" />
<label htmlFor="male">Homme</label>
<input type="radio" id="female" name="gender" value="female" />
<label htmlFor="female">Femme</label>
</div>
<div className="form-group">
<label>Langues:</label>
<input type="checkbox" id="english" name="language" value="english" />
<label htmlFor="english">Anglais</label>
<input type="checkbox" id="french" name="language" value="french" />
<label htmlFor="french">Français</label>
</div>
<div className="form-group">
<label htmlFor="people-picker">Personne:</label>
<input type="text" id="people-picker" name="people-picker" placeholder="Sélectionner une personne" />
</div>
<div className="form-group">
<button type="submit">Envoyer</button>
</div>
</form>
);
};
export default ResponsiveForm;
CSS pour le Formulaire
css
.form-container {
display: flex;
flex-wrap: wrap;
margin: 20px;
}
.form-group {
flex: 1 1 300px;
margin: 10px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input[type="text"],
.form-group input[type="email"],
.form-group input[type="date"],
.form-group input[type="color"],
.form-group input[type="radio"],
.form-group input[type="checkbox"] {
width: 100%;
padding: 8px;
margin-bottom: 10px;
box-sizing: border-box;
}
button[type="submit"] {
background-color: #0078d4;
color: white;
padding: 10px 20px;
border: none;
cursor: pointer;
}
button[type="submit"]:hover {
background-color: #005a9e;
}
@media (max-width: 768px) {
.form-container {
flex-direction: column;
}
}
Rendu Visuel
L'utilisation de Flexbox ici permet aux groupes de formulaire de se réarranger dynamiquement en fonction de la largeur de l'écran. Sur des écrans larges, les groupes se placent côte à côte, tandis que sur les petits écrans (comme les mobiles), ils s'empilent verticalement.
3. Exemple de Grille Responsive avec les Jours de la Semaine
Voici un exemple de grille responsive affichant les jours de la semaine.
HTML/JSX pour la Grille
jsx
import * as React from 'react';
import './WeekGrid.css';
const WeekGrid = () => {
return (
<div className="week-grid">
<div className="day">Lundi</div>
<div className="day">Mardi</div>
<div className="day">Mercredi</div>
<div className="day">Jeudi</div>
<div className="day">Vendredi</div>
<div className="day">Samedi</div>
<div className="day">Dimanche</div>
</div>
);
};
export default WeekGrid;
CSS pour la Grille
css
.week-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 10px;
margin: 20px;
}
.day {
background-color: #f4f4f4;
padding: 20px;
text-align: center;
font-weight: bold;
border: 1px solid #ddd;
}
@media (max-width: 768px) {
.week-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 480px) {
.week-grid {
grid-template-columns: 1fr;
}
}
Rendu Visuel
- Grille par Défaut : Les jours de la semaine sont affichés côte à côte sur des écrans larges, en 7 colonnes.
- Tablette : La grille passe à 2 colonnes, ce qui permet de voir deux jours par ligne.
- Mobile : La grille devient une seule colonne, chaque jour étant affiché dans une ligne distincte.
Conclusion
Les bonnes pratiques pour des CSS responsives dans le développement SPFx avec React incluent l'utilisation de Flexbox et CSS Grid pour créer des mises en page adaptatives, l'utilisation judicieuse des media queries, et la préférence pour des unités relatives pour la taille des éléments. Ces techniques permettent de créer des interfaces utilisateurs qui sont à la fois élégantes et fonctionnelles sur tous types de dispositifs.
Css Best Practices For SPFX React
On 04/09/2024
Créer des CSS responsives pour une solution SPFX (SharePoint Framework) avec React nécessite une approche structurée et l'utilisation de bonnes pratiques. Voici quelques recommandations pour vous aider à y parvenir :
1. Utiliser des Media Queries
Les media queries sont essentielles pour créer des designs responsives. Elles permettent d'appliquer des styles différents en fonction de la taille de l'écran.
@media (max-width: 600px) { .container { flex-direction: column; } }
2. Frameworks CSS Responsive
Utiliser des frameworks CSS comme Bootstrap, Tailwind CSS ou Material-UI peut simplifier la création de designs responsives. Ces frameworks offrent des classes utilitaires et des composants pré-stylisés qui sont déjà responsives.
3. Flexbox et Grid Layout
Utilisez Flexbox et CSS Grid pour créer des mises en page flexibles et responsives.
.container { display: flex; flex-wrap: wrap; } .item { flex: 1 1 100%; } @media (min-width: 600px) { .item { flex: 1 1 50%; } }
4. Variables CSS
Utilisez des variables CSS pour gérer les valeurs récurrentes comme les couleurs, les marges et les tailles de police.
:root { --primary-color: #3498db; --font-size: 16px; } .button { background-color: var(--primary-color); font-size: var(--font-size); }
5. Unités Relatives
Utilisez des unités relatives comme em, rem, % et vw/vh pour créer des designs qui s'adaptent aux différentes tailles d'écran.
.container { width: 90%; max-width: 1200px; margin: 0 auto; }
6. Mobile-First Approach
Adoptez une approche mobile-first en écrivant d'abord les styles pour les petits écrans, puis en utilisant des media queries pour ajuster les styles pour les écrans plus grands.
.container { display: flex; flex-direction: column; } @media (min-width: 600px) { .container { flex-direction: row; } }
7. Utiliser des Composants React Responsive
Il existe des bibliothèques comme react-responsive qui permettent de créer des composants React responsives.
import { useMediaQuery } from 'react-responsive'; const MyComponent = () => { const isMobile = useMediaQuery({ query: '(max-width: 600px)' }); return ( <div className={isMobile ? 'mobile-container' : 'desktop-container'}> {/* Your content here */} </div> ); };
8. Optimiser les Images
Utilisez des images responsives avec les attributs srcset et sizes pour servir des images de différentes tailles en fonction de la résolution de l'écran.
<img src="image.jpg" srcset="image-320w.jpg 320w, image-640w.jpg 640w" sizes="(max-width: 600px) 100vw, 50vw" alt="Responsive Image">
9. Utiliser des Outils de Développement
Utilisez des outils comme les DevTools de Chrome pour tester et déboguer vos designs responsives.
10. Documentation et Tests
Documentez vos styles et testez-les sur différents appareils et navigateurs pour vous assurer qu'ils fonctionnent correctement.
En suivant ces bonnes pratiques, vous pouvez créer des CSS responsives efficaces pour votre solution SPFX avec React, garantissant ainsi une expérience utilisateur optimale sur tous les appareils.
Reccueil Besoin Projet SharePoint
On 04/09/2024
Lors de la phase de recueil des besoins pour une application SharePoint, il est essentiel de poser des questions stratégiques pour bien comprendre les attentes du client, définir le périmètre du projet, et éviter les dépassements de budget ou de calendrier. Voici une liste de questions importantes à poser, organisées par catégorie, pour vous aider à affiner les besoins et rédiger des spécifications fonctionnelles précises.
1. Questions générales sur le projet
Quel est l'objectif principal de cette application ?
Quels problèmes ou besoins spécifiques cherchez-vous à résoudre avec cette application ?
Qui sont les principaux utilisateurs de l'application ?
Y a-t-il des applications ou des systèmes existants que l'application SharePoint devra remplacer ou compléter ?
Avez-vous des exemples de solutions similaires que vous avez utilisées ou que vous aimeriez imiter ?
2. Fonctionnalités principales
Quelles sont les fonctionnalités indispensables de l'application ?
Quelles sont les fonctionnalités secondaires ou souhaitables ?
Y a-t-il des flux de travail spécifiques que vous souhaitez automatiser ?
Quels types de contenu seront gérés (documents, listes, bibliothèques, etc.) ?
Comment souhaitez-vous que les utilisateurs interagissent avec l'application (interface utilisateur, expérience utilisateur) ?
3. Gestion des utilisateurs et permissions
Comment les utilisateurs seront-ils gérés ? Faut-il intégrer des groupes d'utilisateurs existants ?
Quelles permissions spécifiques doivent être définies pour différents types d'utilisateurs ?
Y a-t-il des rôles utilisateurs spécifiques à définir (administrateurs, contributeurs, lecteurs, etc.) ?
4. Intégration et interopérabilité
L'application devra-t-elle s'intégrer avec d'autres systèmes (ERP, CRM, etc.) ou services externes (API, services web) ?
Quels outils ou technologies internes existants doivent être compatibles avec cette application ?
Avez-vous des besoins spécifiques concernant l'importation ou l'exportation de données ?
5. Structure des données
Quelles sont les principales entités de données que l'application doit gérer ?
Comment les données seront-elles organisées (listes SharePoint, bibliothèques de documents, métadonnées) ?
Y a-t-il des exigences spécifiques en matière de recherche, de tri ou de filtrage des données ?
6. Design et expérience utilisateur
Avez-vous des attentes spécifiques en matière de design ou de branding (couleurs, logo, etc.) ?
Souhaitez-vous que l'application soit compatible avec des appareils mobiles ?
Quels sont les critères clés pour l'expérience utilisateur (simplicité, rapidité, accessibilité) ?
7. Performance et évolutivité
Quel est le nombre prévu d'utilisateurs simultanés ?
Quelle est la quantité estimée de contenu que l'application devra gérer (documents, données, etc.) ?
L'application doit-elle être évolutive pour accueillir une augmentation du nombre d'utilisateurs ou de contenu ?
8. Sécurité et conformité
Quelles sont les exigences de sécurité spécifiques pour cette application (chiffrement, audit, etc.) ?
Y a-t-il des réglementations ou des normes de conformité spécifiques à respecter (RGPD, ISO, etc.) ?
Faut-il prévoir des sauvegardes régulières ou des procédures de récupération en cas de sinistre ?
9. Maintenance et support
Qui sera responsable de la maintenance de l'application après son déploiement ?
Avez-vous des exigences pour le support technique (SLA, support 24/7, etc.) ?
Souhaitez-vous une formation pour les utilisateurs finaux ou les administrateurs ?
10. Périmètre et calendrier
Quelles sont les fonctionnalités ou parties du projet qui peuvent être reportées dans une phase ultérieure ?
Quel est le calendrier souhaité pour le déploiement de l'application ?
Y a-t-il des dates limites ou des jalons importants à respecter ?
11. Budget
Quel est le budget alloué pour ce projet ?
Y a-t-il des contraintes budgétaires qui pourraient affecter la portée ou les fonctionnalités de l'application ?
12. Risques et challenges
Voyez-vous des risques ou des défis spécifiques pour ce projet ?
Y a-t-il des points d'incertitude ou des zones grises dans les exigences actuelles ?
13. Feedback et révisions
Comment souhaitez-vous valider les différentes étapes du projet ?
À quelle fréquence souhaitez-vous des réunions ou des rapports d'avancement ?
Conclusion
Ces questions vous permettront de mieux comprendre les besoins du client, de clarifier les attentes, de définir un périmètre clair et de rédiger des spécifications fonctionnelles précises. Assurez-vous de bien documenter les réponses et de valider les points critiques avec le client pour éviter tout malentendu ou ajustement coûteux en cours de projet.
SharePoint Restore File Version
On 03/06/2024
/_api/web/getlist('/sites/MySite/MyDocLib')/items(341)/File/versions/restoreByLabel(versionlabel='5.0')
On 28/05/2024
$String = "François-Demaison!?!#@$%^&*()_+\|}{○<>??/ €$¥£¢ \^$.|?*+()[{ 0123456789"
$String -replace '[^\p{L}\p{Nd}/(/_/_]', '_'
Csom query All Items More than 5000
On 28/05/2024
$url = "https://test.sharepoint.com/sites/monSitte" # Connect-PnPOnline -Url $url -Interactive Clear-Host $listTitle = "EarthStation_Authorisations" $list = Get-PnPList -Identity "Antenna_Model_Ressources" -ThrowExceptionIfListNotFound $ctx = Get-PnPContext $page = $null $pageNumber = 0; $rowLimit = 3000 $datas = @(); #get first item $reqFirst = "<View
Scope='RecursiveAll'> <Query> <ViewFields> <FieldRef Name='ID' /> </ViewFields> <Where> </Where> <OrderBy> <FieldRef Name='ID' Ascending='TRUE' /> </OrderBy> </Query> <RowLimit>1</RowLimit> </View>" $spqQuery = New-Object Microsoft.SharePoint.Client.CamlQuery # $req123 # $spqQuery.ViewXml = $reqFirst # $itemki = $list.GetItems($spqQuery); $ctx.Load($itemki) $ctx.ExecuteQuery(); $itemId = $itemki[0].ID # get last item $reqFirst = "<View
Scope='RecursiveAll'> <Query> <ViewFields> <FieldRef Name='ID' /> </ViewFields> <Where> </Where> <OrderBy> <FieldRef Name='ID' Ascending='FALSE' /> </OrderBy> </Query> <RowLimit>1</RowLimit> </View>" $spqQuery = New-Object Microsoft.SharePoint.Client.CamlQuery # $req123 # $spqQuery.ViewXml = $reqFirst # $itemki = $list.GetItems($spqQuery); $ctx.Load($itemki) $ctx.ExecuteQuery(); $max = $itemki[0].ID $startDate = Get-Date . ..\common.ps1 Do { $stringBuilder = New-Object System.Text.StringBuilder
$stringBuilder.Append("<View Scope='RecursiveAll'>") | Out-Null $stringBuilder.Append("<Query><Where><And><And><Geq><FieldRef Name='Modified' /><Value Type='DateTime'>1900-12-01T19:49:00Z</Value></Geq><Gt><FieldRef Name='ID' /><Value Type='Counter'>$($itemId)</Value></Gt></And><Leq><FieldRef Name='ID' /><Value Type='Counter'>$($itemId + $rowLimit)</Value></Leq></And></Where>") | Out-Null # $stringBuilder.Append("<Query><Where><And><And><Geq><FieldRef Name='Modified' /><Value Type='DateTime'>1900-12-01T19:49:00Z</Value></Geq><Gt><FieldRef Name='ID' /><Value Type='Counter'>$($itemId)</Value></Gt></And><Leq><FieldRef Name='ID' /><Value Type='Counter'>$($itemId + $rowLimit)</Value></Leq></And></Where>") | Out-Null $stringBuilder.Append("<OrderBy><FieldRef Name='ID' Ascending='TRUE' /></OrderBy>") | Out-Null $stringBuilder.Append("</Query>") | Out-Null $stringBuilder.Append("<ViewFields>") | Out-Null $stringBuilder.Append("<FieldRef Name='Title' />") | Out-Null $stringBuilder.Append("<FieldRef Name='FileLeafRef' />") | Out-Null $stringBuilder.Append("<FieldRef Name='FileRef' />") | Out-Null $stringBuilder.Append("<FieldRef Name='Modified' />") | Out-Null $stringBuilder.Append("<FieldRef Name='Created' />") | Out-Null $stringBuilder.Append("<FieldRef Name='ID' />") | Out-Null $stringBuilder.Append("<FieldRef Name='Editor' />") | Out-Null $stringBuilder.Append("</ViewFields>") | Out-Null $stringBuilder.Append("<RowLimit Paged='TRUE'>$($rowLimit)</RowLimit>") | Out-Null $stringBuilder.Append("</View>") | Out-Null $req123 = Get-Content -Path ".\req\req1.xml" -Encoding:UTF8 $spqQuery = New-Object Microsoft.SharePoint.Client.CamlQuery # $req123 # $spqQuery.ViewXml = $stringBuilder.ToString(); $spqQuery.ListItemCollectionPosition = $page $pageNumber ++; $itemki = $list.GetItems($spqQuery); $spqQuery.ListItemCollectionPosition = $itemki.ListItemCollectionPosition try { $ctx.Load($itemki) $ctx.ExecuteQuery(); } catch { <#Do this if a terminating exception happens#> Write-Host "$($_)" Write-Host "$($_)" exit 0 } Write-Host "################## PAGE " $($page.PagingInfo) " #########################" Write-Host "processing query results. Recs: $($itemki.Count) itemId $($itemId) max $($max)" $Counter = 0; foreach ($item in $itemki) { # Write-Host "$($item["ID"]) title pageNumber '$($pageNumber)' : $($item["Title"])" $datas += [PSCustomObject]@{ "FileLeafRef" = $item["FileLeafRef"] "Title" = $item["Title"] "FileRef" = $item["FileRef"] "Modified" = $item["Modified"] "Created" = $item["Created"] "Editor" = $item["Editor"].Email } $itemId = $item.ID } $page = $itemki.ListItemCollectionPosition # $itemId += $rowLimit } Until($itemId -ge $max) Write-Host "$($listTitle) list.ItemCount $($list.ItemCount)" $datas | Export-Csv -Path ".\datas\$($listTitle)_7.csv" -Encoding utf8 -NoTypeInformation -Delimiter ";" -Append Write-Host "$(AddNiceTimeSpan -start $startDate)"
SharePoint Copy Files To Library
On 27/05/2024
{
"siteUrl": "https://tenant.sharepoint.com/sites/fdiSandBox/",
"targetFolder": "/Shared%20Documents/test",
"sourceFolder": "C:\\temp\\myFolderr",
"checkIfFileExists": true,
"forceOverWrite": false,
"includeChildFolders": true,
"copyDates": false,
"copyAuthor": false,
"lofFileName": "copyfiles",
"forbiddenChars": "~,#,%,&,*,{,},\\,:,<,>,?,/,|,",
"replacementChar": "_"
}
Clear-Host
. .\common.ps1
#get copy configuration
$config = GetConnectionConfiguration -filePath ".\config\configuration.json"
$logFileName = "$($config.lofFileName))_$(Get-Date -Format "yyyyMMddhhmmss").log"
$loadedFolders = @();
$startDate = Get-Date
function CheckAlreadyConnected {
Param([Parameter (Mandatory = $true)][string]$url)
$ctx = Get-PnPContext
if ($null -eq $ctx) {
Connect-PnPOnline -Url $url -Interactive -ErrorAction Stop
WriteInfo -Message "connected to $($url)"
}
else {
$web = Get-PnPWeb
if ($web.Url.Trim().ToLower().trim("/") -ne $url.Trim().ToLower().trim("/")) {
Disconnect-PnPOnline
WriteInfo -Message "Disconnect-PnPOnline $($web.Url)"
Connect-PnPOnline -Url $url -Interactive -ErrorAction Stop
WriteInfo -Message "connected to $($url)"
}
}
}
CheckAlreadyConnected -url $config.siteUrl
$web = Get-PnPWeb
function copyFileToSp {
Param([Parameter (Mandatory = $true)][string]$sourceFilePath,
[Parameter (Mandatory = $true)][string]$destinationPath
, $created, $modified
)
#check target folder exists
if (-not $loadedFolders.Contains($destinationPath)) {
$folder = Get-PnPFolder -Url $destinationPath -ErrorAction SilentlyContinue
if ($null -eq $folder) {
$datas = $destinationPath.Split("/", [System.StringSplitOptions]::RemoveEmptyEntries)
$folderName = $datas[$datas.Length - 1];
$target = $destinationPath.Substring(0, $destinationPath.Length - $folderName.Length - 1)
Add-PnPFolder -Name $folderName -Folder $target
}
$loadedFolders += $destinationPath
}
$destination
$destinationPath
$Asset = @{}
$valuesOk = $false
# modified
if ($null -ne $modified) {
$date = Get-Date -Date $modified
$Asset.add("Modified", $date.ToString("yyyy-MM-dd HH:mm"))
$valuesOk = $true;
}
# created
if ($null -ne $created) {
$date = Get-Date -Date $created
$Asset.add("Created", $date.ToString("yyyy-MM-dd HH:mm"))
$valuesOk = $true;
}
if ($valuesOk -eq $true) {
$spFile = Add-PnPFile -Path $sourceFilePath -Folder $destinationPath -Values $Asset
}
else {
$spFile = Add-PnPFile -Path $sourceFilePath -Folder $destinationPath
}
$pp = 0;
$pp ++;
}
if ($config.includeChildFolders) {
$filesToCopy = Get-ChildItem -LiteralPath $config.sourceFolder -Recurse
}
else {
$filesToCopy = Get-ChildItem -LiteralPath $config.sourceFolder
}
$filesToCopy.Length
foreach ($file in $filesToCopy) {
$file.FullName;
$file.LastAccessTime
if ($file.GetType().Name -eq "FileInfo") {
$filePath = $file.DirectoryName
$destinationFileName = $filePath.Substring($config.sourceFolder.Length).trim("\").Replace("\", "/")
$destinationFileName = "$($web.ServerRelativeUrl)/$($config.targetFolder.Trim().Trim("/"))/$($destinationFileName)".Replace("%20", " ").TrimEnd("/")
Write-Host "dest : '$($destinationFileName)'"
copyFileToSp -sourceFilePath $file.FullName -destinationPath $destinationFileName -modified $file.LastWriteTime -created $file.CreationTime
}
}
WriteInfo -Message "nb files / folders added : $($filesToCopy.Length)"
AddNiceTimeSpan -start $startDate
Sharepoint REST roleassignments Break
On 14/05/2024
roleassignments
_api/lists/getByTitle('myLList')/items(2)/roleassignments/addroleassignment(principalid=15)},roledefid=1073741826)
break role inheritance
_api/lists/getByTitle('@{triggerBody()?['ListTitle']}')/items(@{int(triggerBody()['ItemId'])})/breakroleinheritance(copyRoleAssignments=false,clearSubscopes=true)
get role assigments ids
/_api/Web/RoleDefinitions?$select=Name,Description,Id
Name Description Id
Full ControlHas full control.1073741829
DesignCan view, add, update, delete, approve, and customize.1073741828
EditCan add, edit and delete lists; can view, add, update and delete list items and documents.1073741830
ContributeCan view, add, update, and delete list items and documents.1073741827
ReadCan view pages and list items and download documents.1073741826
Restricted ViewCan view pages, list items, and documents. Documents can be viewed in the browser but not downloaded.1073741832
Limited AccessCan view specific lists, document libraries, list items, folders, or documents when given permissions.1073741825
System.LimitedViewnull1073741924
System.LimitedEditnull1073741925