Partager via


Guide pratique pour connecter votre application de code à Azure SQL (préversion)

Ce guide explique comment configurer une base de données Azure SQL Database et la connecter à une application de code Power Apps à l’aide du Kit de développement logiciel (SDK) Power.

Note

Les fonctionnalités d'évaluation ne sont pas destinées à une utilisation en production et peuvent être restreintes. Ces fonctionnalités sont disponibles avant une publication officielle afin que les clients puissent obtenir un accès anticipé et fournir des commentaires.

Ce guide couvre les points suivants :

  • Approvisionnement d’un serveur et d’une base de données Azure SQL Server
  • Création de tables SQL et de procédures stockées
  • Connexion d’une application de code Power Apps à l’aide du Kit de développement logiciel (SDK) Power

Prerequisites

Configurer Azure SQL Server et la base de données

  1. Accéder à l’option Sélectionner un déploiement SQL - Microsoft Azure
  2. Sélectionner une base de données SQL -> Type de ressource : base de données unique ->Créer
  3. Remplir:
    • Groupe de ressources : sélectionnez Créer et entrez un nom de groupe de ressources, par exemple, rg-codeapps-dev
    • Nom de la base de données : sqldb-codeapps-dev
    • Serveur : sélectionnez Créer et remplir :
      • Nom du serveur : sql-codeapps-dev
      • Emplacement : sélectionnez la région la plus proche de votre environnement Power Platform.
      • Méthode d’authentification : Utiliser l’authentification Microsoft Entra-only
      • Définissez l’administrateur Microsoft Entra : sélectionnez Définir l’administrateur, puis sélectionnez votre propre utilisateur.
    • Cliquez sur OK.
  4. Calcul + stockage : Usage général - Serverless
  5. Sélectionnez Suivant : Mise en réseau.
  6. Remplir:
    • Méthode de connectivité : point de terminaison public
    • Autoriser les services et ressources Azure à accéder à ce serveur : Oui
    • Ajouter l’adresse IP du client actuel : Oui
  7. Sélectionner Vérifier + créer ->Créer
  8. Attendez que le déploiement se termine, puis sélectionnez Accéder à la ressource

Déployer des exemples de données

  1. Dans Visual Studio Code, sélectionnez Extensions (Ctrl+ Maj + X)

  2. Recherchez l’extension SQL Server (mssql) dans la barre d’activité et ouvrez-la, ou utilisez Ctrl + Alt + D

  3. Sous Connexions, sélectionnez + Ajouter une connexion

    Ajouter une connexion dans l’extension VS Code SQL Server

  4. Dans la boîte de dialogue Se connecter à la base de données , sélectionnez Parcourir Azure, sélectionnez votre abonnement, groupe de ressources (par exemple : rg-codeapps-dev), Serveur (par exemple : sql-codeapps-dev), puis base de données (par exemple sqldb-codeapps-dev )

  5. Sous Type d’authentification, sélectionnez Microsoft Entra ID - Universal with MFA support

  6. Vérifiez que votre portail Azure est ouvert dans votre navigateur, puis sélectionnez Se connecter. Vous devez être invité à vous connecter, puis voir :

    Invite de connexion Microsoft Entra pour la connexion SQL

  7. Sélectionner Se connecter

    Connecté à une base de données Azure SQL dans VS Code

  8. Dans le panneau SQL SERVER, cliquez avec le bouton droit sur votre base de données et sélectionnez Nouvelle requête

    Nouvelle commande de requête pour la base de données dans l’extension SQL VS Code

  9. Dans la nouvelle fenêtre de requête, collez le code SQL suivant :

    -- Drop existing objects if they exist
    IF OBJECT_ID('dbo.Projects', 'U') IS NOT NULL DROP TABLE dbo.Projects;
    
    -- =============================================
    -- CREATE TABLES
    -- =============================================
    
    -- Projects Table
    CREATE TABLE [dbo].[Projects](
        [ProjectId] [int] IDENTITY(1,1) NOT NULL,
        [Name] [nvarchar](255) NOT NULL,
        [Description] [nvarchar](max) NULL,
        [StartDate] [date] NULL,
        [EndDate] [date] NULL,
        [Status] [nvarchar](50) NOT NULL DEFAULT ('Planning'),
        [Priority] [nvarchar](20) NOT NULL DEFAULT ('Medium'),
        [Budget] [decimal](18, 2) NULL,
        [ProjectManagerEmail] [nvarchar](255) NOT NULL,
        [CreatedBy] [nvarchar](255) NOT NULL,
        [CreatedDate] [datetime2](7) NOT NULL DEFAULT (getutcdate()),
        [IsActive] [bit] NOT NULL DEFAULT (1),
        CONSTRAINT [PK_Projects] PRIMARY KEY ([ProjectId])
    );
    GO
    
    -- =============================================
    -- ADD CONSTRAINTS
    -- =============================================
    
    -- Project Status Check
    ALTER TABLE [dbo].[Projects] ADD CONSTRAINT [CK_Projects_Status] 
    CHECK ([Status] IN ('Planning', 'Active', 'On Hold', 'Completed', 'Cancelled'));
    
    -- Project Priority Check
    ALTER TABLE [dbo].[Projects] ADD CONSTRAINT [CK_Projects_Priority] 
    CHECK ([Priority] IN ('Low', 'Medium', 'High', 'Critical'));
    GO
    
    -- =============================================
    -- STORED PROCEDURES
    -- =============================================
    
    -- Get All Projects
    IF OBJECT_ID('dbo.GetAllProjects', 'P') IS NOT NULL DROP PROCEDURE dbo.GetAllProjects;
    GO
    CREATE PROCEDURE [dbo].[GetAllProjects]
    AS
    BEGIN
        SET NOCOUNT ON;
    
        SELECT 
            [ProjectId], [Name], [Description], [StartDate], [EndDate],
            [Status], [Priority], [Budget], [ProjectManagerEmail],
            [CreatedBy], [CreatedDate], [IsActive]
        FROM [dbo].[Projects]
        WHERE [IsActive] = 1
        ORDER BY [CreatedDate] DESC;
    END
    GO
    
    -- Create Project
    IF OBJECT_ID('dbo.CreateProject', 'P') IS NOT NULL DROP PROCEDURE dbo.CreateProject;
    GO
    CREATE PROCEDURE [dbo].[CreateProject]
        @Name NVARCHAR(255),
        @Description NVARCHAR(MAX) = NULL,
        @StartDate DATE = NULL,
        @EndDate DATE = NULL,
        @Status NVARCHAR(50) = 'Planning',
        @Priority NVARCHAR(20) = 'Medium',
        @Budget DECIMAL(18,2) = NULL,
        @ProjectManagerEmail NVARCHAR(255),
        @CreatedBy NVARCHAR(255)
    AS
    BEGIN
        SET NOCOUNT ON;
    
        INSERT INTO [dbo].[Projects] (
            [Name], [Description], [StartDate], [EndDate], 
            [Status], [Priority], [Budget], [ProjectManagerEmail], [CreatedBy]
        )
        VALUES (
            @Name, @Description, @StartDate, @EndDate,
            @Status, @Priority, @Budget, @ProjectManagerEmail, @CreatedBy
        );
    
        SELECT SCOPE_IDENTITY() as ProjectId;
    END
    GO
    
    -- Update Project
    IF OBJECT_ID('dbo.UpdateProject', 'P') IS NOT NULL DROP PROCEDURE dbo.UpdateProject;
    GO
    CREATE PROCEDURE [dbo].[UpdateProject]
        @ProjectId INT,
        @Name NVARCHAR(255) = NULL,
        @Description NVARCHAR(MAX) = NULL,
        @StartDate DATE = NULL,
        @EndDate DATE = NULL,
        @Status NVARCHAR(50) = NULL,
        @Priority NVARCHAR(20) = NULL,
        @Budget DECIMAL(18,2) = NULL,
        @ProjectManagerEmail NVARCHAR(255) = NULL
    AS
    BEGIN
        SET NOCOUNT ON;
    
        UPDATE [dbo].[Projects]
        SET 
            [Name] = ISNULL(@Name, [Name]),
            [Description] = ISNULL(@Description, [Description]),
            [StartDate] = ISNULL(@StartDate, [StartDate]),
            [EndDate] = ISNULL(@EndDate, [EndDate]),
            [Status] = ISNULL(@Status, [Status]),
            [Priority] = ISNULL(@Priority, [Priority]),
            [Budget] = ISNULL(@Budget, [Budget]),
            [ProjectManagerEmail] = ISNULL(@ProjectManagerEmail, [ProjectManagerEmail])
        WHERE [ProjectId] = @ProjectId AND [IsActive] = 1;
    
        SELECT @@ROWCOUNT as RowsAffected;
    END
    GO
    
    -- Delete Project (Soft Delete)
    IF OBJECT_ID('dbo.DeleteProject', 'P') IS NOT NULL DROP PROCEDURE dbo.DeleteProject;
    GO
    CREATE PROCEDURE [dbo].[DeleteProject]
        @ProjectId INT
    AS
    BEGIN
        SET NOCOUNT ON;
    
        UPDATE [dbo].[Projects]
        SET [IsActive] = 0
        WHERE [ProjectId] = @ProjectId AND [IsActive] = 1;
    
        SELECT @@ROWCOUNT as RowsAffected;
    END
    GO
    
    -- =============================================
    -- SAMPLE DATA
    -- =============================================
    
    -- Insert Sample Projects
    INSERT INTO [dbo].[Projects] ([Name], [Description], [StartDate], [EndDate], [Status], [Priority], [Budget], [ProjectManagerEmail], [CreatedBy]) VALUES
    ('Website Redesign', 'Complete redesign of company website with modern UI/UX', '2025-06-01', '2025-08-31', 'Active', 'High', 75000.00, 'sarah.johnson@company.com', 'admin@company.com'),
    ('Mobile App Development', 'Develop iOS and Android mobile application for customer portal', '2025-07-01', '2025-12-31', 'Planning', 'Critical', 150000.00, 'mike.chen@company.com', 'admin@company.com'),
    ('Database Migration', 'Migrate legacy database to cloud infrastructure', '2025-05-15', '2025-09-30', 'Active', 'Medium', 50000.00, 'lisa.williams@company.com', 'admin@company.com');
    GO
    
    PRINT 'Projects-only database schema created successfully with sample data!';
    
  10. Sélectionnez l’icône de lecture verte (Ctrl-Maj-E) pour exécuter la requête.

  11. Vous ne devez pas voir d’erreurs dans la sortie DES RÉSULTATS DE REQUÊTE .

Initialiser votre application de code

Si vous ne l’avez pas encore fait, créez et/ou initialisez votre application de code à l’aide des instructions fournies ici : Créez une application à partir de zéro.

Créer une connexion SQL Server dans Power Platform

  1. Ouvrir Power Apps

  2. Sélectionnez votre environnement

  3. Accédez à Connexions. C’est peut-être dans le menu Plus.

  4. Sélectionner + Nouvelle connexion

    + Nouvelle connexion dans Power Apps

  5. Sélectionner SQL Server

  6. Sélectionner le type d’authentification : Microsoft Entra ID Integrated

  7. Sélectionnez Créer et se connecter dans la fenêtre d’authentification pop-up

Ajouter des connexions de table SQL à votre application

  1. Répertoriez les connexions disponibles dans votre environnement. Vous devez voir la connexion que vous avez créée :

    pac connection list
    

    Vous devez voir une liste similaire à :

    Liste des connexions Power Platform montrant la connexion SQL

  2. Pour ajouter la table de projets au projet, copiez l’ID de connexion (la première colonne) et utilisez la commande suivante :

    pac code add-data-source -a "shared_sql" -c "[CONNECTION ID]"  -d "[SQL SERVER NAME].database.windows.net,[DATA BASE NAME]" -sp "dbo.GetAllProjects"
    

    Par exemple:

    pac code add-data-source -a "shared_sql" -c "aaaa0000bb11222233cc444444dddddd"  -d "sql-codeapps-dev.database.windows.net,sqldb-codeapps-dev" -sp "dbo.GetAllProjects"
    
  3. Ouvrez les dossiers Services et Models, puis observez le code nouvellement généré.

Ajouter une table de projets

  1. Nous utilisons Fluent UI pour afficher une table de projets, donc passer à React 18 et l’installer à l’aide de :

    npm install react@^18.0.0 react-dom@^18.0.0 @types/react@^18.0.0 @types/react-dom@^18.0.0
    npm install @fluentui/react-components
    
  2. Ajoutez un nouveau fichier sous src nommé ProjectsTable.tsx avec le code suivant :

    /**
     * ProjectsTable Component - Displays project data from Power Platform in a sortable DataGrid
     */
    import React, { useEffect, useState, useCallback, useMemo } from 'react';
    import {
      DataGrid,
      DataGridHeader,
      DataGridRow,
      DataGridHeaderCell,
      DataGridCell,
      DataGridBody,
      TableColumnDefinition,
      TableRowId,
      Spinner,
      MessageBar,
      Badge,
      makeStyles,
      tokens,
    } from '@fluentui/react-components';
    import { GetAllProjectsService } from './Services/GetAllProjectsService';
    
    // String formatting utility for localizable messages
    const formatMessage = (template: string, params: Record<string, string | number> = {}): string => {
      return template.replace(/\{(\w+)\}/g, (match, key) => {
        const value = params[key];
        return value !== undefined ? String(value) : match;
      });
    };
    
    // Common UI messages
    const MESSAGE_STRINGS = {
      LOADING: 'Loading data...',
      NO_DATA: 'No data found.',
      GENERIC_ERROR: 'An unexpected error occurred',
      LOAD_ERROR: 'Failed to load data. Please try again.',
      PROJECT_COUNTER_SINGLE: 'Showing {count} project',
      PROJECT_COUNTER_PLURAL: 'Showing {count} projects',
      COLUMN_PROJECT_NAME: 'Project Name',
      COLUMN_DESCRIPTION: 'Description',
      COLUMN_START_DATE: 'Start Date',
      COLUMN_END_DATE: 'End Date',
      COLUMN_STATUS: 'Status',
      COLUMN_PRIORITY: 'Priority',
      ARIA_LABEL_DATA_GRID: 'Projects data grid',
    } as const;
    
    // Project data type
    type ProjectItem = {
      ProjectId?: number;
      Name?: string;
      Description?: string;
      StartDate?: string;
      EndDate?: string;
      Status?: string;
      Priority?: string;
      Budget?: number;
      ProjectManagerEmail?: string;
      CreatedBy?: string;
      CreatedDate?: string;
      IsActive?: boolean;
    };
    
    // DataGrid columns
    const COLUMNS: TableColumnDefinition<ProjectItem>[] = [
      {
        columnId: 'name',
        compare: (a, b) => (a.Name || '').localeCompare(b.Name || ''),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_PROJECT_NAME,
        renderCell: (item) => item.Name || '',
      },
      {
        columnId: 'description',
        compare: (a, b) => (a.Description || '').localeCompare(b.Description || ''),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_DESCRIPTION,
        renderCell: (item) => item.Description || '',
      },
      {
        columnId: 'startDate',
        compare: (a, b) => new Date(a.StartDate || '').getTime() - new Date(b.StartDate || '').getTime(),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_START_DATE,
        renderCell: (item) => item.StartDate ? new Date(item.StartDate).toLocaleDateString() : '',
      },
      {
        columnId: 'endDate',
        compare: (a, b) => new Date(a.EndDate || '').getTime() - new Date(b.EndDate || '').getTime(),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_END_DATE,
        renderCell: (item) => item.EndDate ? new Date(item.EndDate).toLocaleDateString() : '',
      }, {
        columnId: 'status',
        compare: (a, b) => (a.Status || '').localeCompare(b.Status || ''),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_STATUS,
        renderCell: (item) => <StatusBadge status={item.Status || ''} />,
      },
      {
        columnId: 'priority',
        compare: (a, b) => (a.Priority || '').localeCompare(b.Priority || ''),
        renderHeaderCell: () => MESSAGE_STRINGS.COLUMN_PRIORITY,
        renderCell: (item) => <PriorityBadge priority={item.Priority || ''} />,
      },
    ];
    
    // Row ID generator
    const getRowId = (item: ProjectItem): TableRowId =>
      item.ProjectId?.toString() || `temp-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
    
    // Extracts a user-friendly error message from various error types
    const extractErrorMessage = (
      error: unknown,
      fallbackMessage = MESSAGE_STRINGS.GENERIC_ERROR
    ): string => {
      if (error instanceof Error) {
        return error.message;
      }
      if (typeof error === 'string') {
        return error;
      } return fallbackMessage;
    };
    
    // Badge component for Priority
    const PriorityBadge: React.FC<{ priority: string }> = React.memo(({ priority }) => {
      const styles = useStyles();
      const badgeProps = useMemo(() => {
        const getPriorityAppearance = (priority: string) => {
          switch (priority?.toLowerCase()) {
            case 'critical':
              return { appearance: 'filled' as const, color: 'danger' as const };
            case 'high':
              return { appearance: 'filled' as const, color: 'important' as const };
            case 'medium':
              return { appearance: 'filled' as const, color: 'warning' as const };
            case 'low':
              return { appearance: 'filled' as const, color: 'success' as const };
            default:
              return { appearance: 'outline' as const, color: 'subtle' as const };
          }
        };
        return getPriorityAppearance(priority);
      }, [priority]);
    
      return (
        <Badge {...badgeProps} className={styles.badge}>
          {priority || 'Unknown'}
        </Badge>
      );
    });
    
    PriorityBadge.displayName = 'PriorityBadge';
    
    // Badge component for Status
    const StatusBadge: React.FC<{ status: string }> = React.memo(({ status }) => {
      const styles = useStyles();
      const badgeProps = useMemo(() => {
        const getStatusAppearance = (status: string) => {
          switch (status?.toLowerCase()) {
            case 'completed':
              return { appearance: 'filled' as const, color: 'success' as const };
            case 'active':
              return { appearance: 'filled' as const, color: 'brand' as const };
            case 'planning':
              return { appearance: 'filled' as const, color: 'informative' as const };
            case 'on hold':
              return { appearance: 'filled' as const, color: 'warning' as const };
            case 'cancelled':
              return { appearance: 'filled' as const, color: 'danger' as const };
            default:
              return { appearance: 'outline' as const, color: 'subtle' as const };
          }
        };
        return getStatusAppearance(status);
      }, [status]);
    
      return (
        <Badge {...badgeProps} className={styles.badge}>
          {status || 'Unknown'}
        </Badge>
      );
    });
    
    StatusBadge.displayName = 'StatusBadge';
    
    // Styles
    const useStyles = makeStyles({
      container: {
        padding: tokens.spacingVerticalXXL,
      },
      loadingContainer: {
        display: 'flex',
        alignItems: 'center',
        gap: tokens.spacingHorizontalS,
        padding: tokens.spacingVerticalXXL,
      },
      messageBar: {
        marginBottom: tokens.spacingVerticalXL,
      },
      projectCounter: {
        marginBottom: tokens.spacingVerticalM,
        fontSize: tokens.fontSizeBase200,
        color: tokens.colorNeutralForeground2,
      }, dataGrid: {
        width: '100%',
      },
      badge: {
        fontSize: tokens.fontSizeBase200,
        fontWeight: tokens.fontWeightMedium,
        textTransform: 'capitalize',
      },
    });
    
    // Custom hook to fetch and manage project data
    const useProjectsData = (): {
      projects: ProjectItem[];
      loading: boolean;
      error: string | null;
      refetch: () => Promise<void>;
    } => {
      const [projects, setProjects] = useState<ProjectItem[]>([]);
      const [loading, setLoading] = useState(true);
      const [error, setError] = useState<string | null>(null);
    
      const fetchProjects = useCallback(async () => {
        try {
          setLoading(true);
          setError(null); const result = await GetAllProjectsService.GetAllProjects();
          if (result.success && result.data?.ResultSets?.Table1) {
            const projectsData = Array.isArray(result.data.ResultSets.Table1)
              ? result.data.ResultSets.Table1 as ProjectItem[]
              : [result.data.ResultSets.Table1] as ProjectItem[];
            setProjects(projectsData);
          } else {
            const errorMsg = result.error instanceof Error
              ? result.error.message
              : result.error || MESSAGE_STRINGS.LOAD_ERROR;
            setError(errorMsg);
            console.error('Failed to fetch projects:', result.error);
          }
        } catch (error) {
          const errorMessage = extractErrorMessage(error, MESSAGE_STRINGS.GENERIC_ERROR);
          setError(errorMessage);
          console.error('Error fetching projects:', error);
        } finally {
          setLoading(false);
        }
      }, []);
    
      useEffect(() => {
        fetchProjects();
      }, [fetchProjects]);
    
      return { projects, loading, error, refetch: fetchProjects };
    };
    
    // UI Components
    const LoadingSpinner: React.FC = () => {
      const styles = useStyles();
      return (
        <div className={styles.loadingContainer}>
          <Spinner size="small" />
          <span>{MESSAGE_STRINGS.LOADING}</span>
        </div>
      );
    };
    
    const ErrorMessage: React.FC<{ error: string }> = ({ error }) => {
      const styles = useStyles();
      return (
        <MessageBar intent="error" className={styles.messageBar}>
          {error}
        </MessageBar>
      );
    };
    
    const EmptyState: React.FC = () => {
      const styles = useStyles();
      return (
        <MessageBar intent="info" className={styles.messageBar} style={{ textAlign: 'center' }}>
          {MESSAGE_STRINGS.NO_DATA}
        </MessageBar>
      );
    };
    
    const ProjectCounter: React.FC<{ count: number }> = ({ count }) => {
      const styles = useStyles();
    
      const counterMessage = useMemo(() => {
        return count === 1
          ? formatMessage(MESSAGE_STRINGS.PROJECT_COUNTER_SINGLE, { count })
          : formatMessage(MESSAGE_STRINGS.PROJECT_COUNTER_PLURAL, { count });
      }, [count]);
    
      return (
        <div className={styles.projectCounter}>
          {counterMessage}
        </div>
      );
    };
    
    // Main component
    const ProjectsTable: React.FC = () => {
      const styles = useStyles();
      const { projects, loading, error } = useProjectsData();
      const projectCount = useMemo(() => projects.length, [projects.length]);
      const memoizedProjects = useMemo(() => projects, [projects]);
      const dataGridProps = useMemo(() => ({
        items: memoizedProjects,
        columns: COLUMNS,
        sortable: true,
        getRowId,
        focusMode: "cell" as const,
        className: styles.dataGrid,
        "aria-label": MESSAGE_STRINGS.ARIA_LABEL_DATA_GRID,
      }), [memoizedProjects, styles.dataGrid]);
    
      if (loading) {
        return (
          <div className={styles.container}>
            <LoadingSpinner />
          </div>
        );
      }
    
      if (error) {
        return (
          <div className={styles.container}>
            <ErrorMessage error={error} />
          </div>
        );
      }
    
      if (projectCount === 0) {
        return (
          <div className={styles.container}>
            <EmptyState />
          </div>
        );
      }
      return (
        <div className={styles.container}>
          <ProjectCounter count={projectCount} />      <DataGrid {...dataGridProps}>
            <DataGridHeader>
              <DataGridRow>
                {({ renderHeaderCell }) => (
                  <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>
                )}
              </DataGridRow>
            </DataGridHeader>
            <DataGridBody<ProjectItem>>
              {({ item, rowId }) => (
                <DataGridRow<ProjectItem> key={rowId}>
                  {({ renderCell }) => (
                    <DataGridCell>{renderCell(item)}</DataGridCell>
                  )}
                </DataGridRow>
              )}
            </DataGridBody>
          </DataGrid>
        </div>
      );
    };
    
    export default React.memo(ProjectsTable);
    
    
  3. Ajoutez les FluentProvider et ProjectsTable à maint.tsx:

     import { StrictMode } from 'react'
     import { createRoot } from 'react-dom/client'
     import './index.css'
     import PowerProvider from './PowerProvider.tsx'
     import { FluentProvider, webLightTheme } from '@fluentui/react-components'
     import ProjectsTable from './ProjectsTable.tsx'
    
     createRoot(document.getElementById('root')!).render(
       <StrictMode>
         <PowerProvider>
           <FluentProvider theme={webLightTheme}>
             <ProjectsTable />
           </FluentProvider>
         </PowerProvider>
       </StrictMode>,
     )
    
    
  4. Exécutez votre application à l’aide de :

    npm run dev
    

    Dans la fenêtre de commande qui s’ouvre, ouvrez le lien de l’application fourni :

    Console de serveur power SDK avec l’URL et l’état de l’application

  5. Lorsque l’application s’ouvre, une boîte de dialogue de consentement doit s’afficher, sélectionnez Autoriser.

    Boîte de dialogue Consentement demandant des autorisations pour l’application

  6. Vous devez voir la grille de données des projets :

    Projette la grille de données avec des colonnes et des badges triables

Publication de l’application dans Power Apps

  1. Une fois que votre application est prête pour la publication et le partage, vérifiez que le serveur Vite est arrêté à l’aide de Ctrl + C, puis utilisez powerShell suivant :

    npm run build
    pac code push
    
  2. Ouvrez l’application à l’aide du lien fourni pour le tester !

    Application publiée sur Power Apps avec lien Ouvrir l’application

Résolution des problèmes

Cette section traite des problèmes courants que vous pouvez rencontrer lors de la configuration d’applications de code Power Apps avec Azure SQL Database.

Problèmes liés à Azure SQL Database

Vous pouvez rencontrer ces problèmes lors de l’utilisation de bases de données Azure SQL.

Impossible de se connecter à Azure SQL Database

Symptômes :

  • Erreurs de délai d’expiration de connexion
  • Échecs d’authentification lors de la connexion à partir de l’extension SQL VS Code

Solutions :

  1. Vérifiez les paramètres du pare-feu :

    • Dans le portail Azure, accédez à votre serveur SQL Server
    • Accéder à SécuritéMise en réseau
    • Vérifiez que « Autoriser les services et ressources Azure à accéder à ce serveur » est défini sur Oui
    • Ajouter votre adresse IP cliente actuelle aux règles de pare-feu
  2. Vérifier la méthode d’authentification :

    • Vérifiez que vous utilisez Microsoft Entra ID - Universal avec prise en charge de l’authentification multifacteur dans VS Code
    • Vérifiez que vous êtes connecté au même compte Azure dans le portail Azure et VS Code
    • Essayez de vous déconnecter et de revenir pour actualiser les jetons d’authentification
  3. Vérifier la connectivité réseau :

    # Test connectivity to SQL Server
    Test-NetConnection -ComputerName "your-sql-server.database.windows.net" -Port 1433
    

Erreurs d’exécution de requête SQL

Symptômes :

  • Erreurs d’autorisation refusées lors de l’exécution de scripts SQL
  • Erreurs d'objet déjà existant

Solutions :

  1. Problèmes d’autorisation :

    • Vérifiez que votre compte d’utilisateur est défini en tant qu’administrateur Microsoft Entra pour SQL Server
    • Vérifiez que vous disposez db_owner ou des autorisations appropriées sur la base de données
  2. Erreurs d'existence de l'objet :

    • Le script SQL inclut des DROP instructions : elles sont sécurisées pour s’exécuter plusieurs fois
    • Si vous obtenez des erreurs de contrainte, commencez par exécuter individuellement les instructions de suppression.

problèmes de Node.js et npm

Vous pouvez rencontrer ces problèmes lors de l’utilisation de Node.js et npm.

Port 3000 déjà utilisé

Symptômes :

  • « EADDRINUSE : adresse déjà utilisée :::3000 »
  • Le serveur Vite ne démarre pas

Solutions :

  1. Tuer le processus existant :

    # Find process using port 3000
    netstat -ano | findstr :3000
    # Kill the process (replace PID with actual process ID)
    taskkill /PID [PID] /F
    
  2. Utilisez un autre port :

    • Pour utiliser un autre port, mettez à jour vite.config.ts
    • Mettre à jour la configuration du Kit de développement logiciel (SDK) Power en conséquence

Échecs d’installation du package

Symptômes :

  • Erreurs d’installation npm
  • Erreurs de module introuvable

Solutions :

  1. Effacer le cache npm :

    npm cache clean --force
    npm install
    
  2. Supprimez node_modules et réinstallez :

    Remove-Item -Recurse -Force node_modules
    Remove-Item package-lock.json
    npm install
    
  3. Problèmes de version de Node :

    # Check Node version
    node --version
    # Should be LTS version (18.x or 20.x)
    

Erreurs de connexion au runtime

Symptômes :

  • « Échec du chargement des données » dans l’application React
  • Erreurs de refus de connexion

Solutions :

  1. Vérifier la connexion Power Platform :

    • Vérifier que la connexion SQL Server fonctionne dans Power Platform
    • Tester la connexion dans Power Apps
  2. Problèmes de consentement :

    • Veillez à donner votre consentement lorsque l’application se charge pour la première fois
    • Effacer le cache du navigateur et réessayer
  3. Incompatibilité de l’environnement :

    • Vérifiez que vous exécutez l’application dans le même environnement que celui où la connexion a été créée
    • Vérifiez que le profil de navigateur correspond à votre compte Power Platform