Zarządzanie wywołaniami użytkowników usługi Teams za pomocą zestawu SDK wywołującego usługi Communication Services
Dowiedz się, jak zarządzać wywołaniami za pomocą zestawu SDK usług Azure Communication Services. Dowiesz się, jak umieszczać wywołania, zarządzać ich uczestnikami i właściwościami.
Wymagania wstępne
- Konto platformy Azure z aktywną subskrypcją. Utwórz konto bezpłatnie.
- Wdrożony zasób usług komunikacyjnych. Utwórz zasób usług komunikacyjnych.
- Element umożliwiający
User Access Token
włączenie klienta wywołania. Aby uzyskać więcej informacji na temat sposobu uzyskiwaniaUser Access Token
- Opcjonalnie: ukończ przewodnik Szybki start, aby rozpocząć dodawanie wywołań wideo do aplikacji
Instalacja zestawu SDK
Użyj polecenia , npm install
aby zainstalować wywołania usług Azure Communication Services i typowe zestawy SDK dla języka JavaScript.
npm install @azure/communication-common --save
npm install @azure/communication-calling --save
Inicjowanie wymaganych obiektów
Utwórz wystąpienie w CallClient
celu zainicjowania stosu wywołującego. Rejestrowanie wywoływanego zestawu SDK można skonfigurować przy użyciu AzureLogger
wystąpienia i setLogLevel
metody. Dostęp do deviceManager
systemu operacyjnego można uzyskać za pomocą metody getDeviceManager
.
Następnie użyj metody createTeamsCallAgent
, aby utworzyć asynchronicznie TeamsCallAgent
wystąpienie, które będzie zarządzać przychodzącymi i wychodzącymi wywołaniami użytkownika usługi Teams. Metoda przyjmuje CommunicationTokenCredential
jako argument reprezentujący token dostępu dla użytkownika usługi Teams.
const { CallClient } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential} = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");
// Set the logger's log level
setLogLevel('verbose');
// Redirect log output to wherever desired. To console, file, buffer, REST API, etc...
AzureLogger.log = (...args) => {
console.log(...args); // Redirect log output to console
};
const userToken = '<USER_TOKEN>';
callClient = new CallClient();
const tokenCredential = new AzureCommunicationTokenCredential(userToken);
const teamsCallAgent = await callClient.createTeamsCallAgent(tokenCredential);
const deviceManager = await callClient.getDeviceManager();
Umieszczanie połączenia
Uruchom synchroniczne wywołanie jeden do jednego lub grupy za pomocą startCall
interfejsu API w systemie teamsCallAgent
. Możesz podać MicrosoftTeamsUserIdentifier
parametr lub PhoneNumberIdentifier
jako parametr, aby zdefiniować element docelowy wywołania. Metoda zwraca TeamsCall
wystąpienie, które umożliwia subskrybowanie zdarzeń wywołania.
Uwaga
Uruchom wywołanie grupy za pomocą teamsCallAgent
polecenia wymaga czatu threadId
podczas wywoływania startCall
metody. Utworzone TeamsCall
wystąpienie ma właściwość threadId
przechwytujące ten wątek. Zestaw SDK połączeń usług komunikacyjnych nie przechowuje uczestników podczas rozmowy i synchronizacji listy połączeń. Firma Microsft zachęca deweloperów do synchronizowania listy w celu uzyskania najlepszego środowiska użytkownika. Dowiedz się, jak zarządzać wątkiem czatu.
Uruchom jedno-do-jednego wywołanie adresu IP (VoIP) do użytkownika usługi Teams:
const userCallee = { microsoftTeamsUserId: '<MICROSOFT_TEAMS_USER_ID>' };
const oneToOneCall = teamsCallAgent.startCall(userCallee);
Rozpocznij połączenie telefoniczne jeden do jednego na numer telefonu E.164:
const phoneCallee = { phoneNumber: '<PHONE_NUMBER_E164_FORMAT>' }
const oneToOneCall = teamsCallAgent.startCall(phoneCallee );
Rozpocznij połączenie grupowe z użytkownikiem usługi Teams przy użyciu adresu IP (VoIP) i numeru telefonu:
const userCallee = { microsoftTeamsUserId: '<MICROSOFT_TEAMS_USER_ID>' }
const phoneCallee = { phoneNumber: '<PHONE_NUMBER_E164_FORMAT>'};
const groupCall = teamsCallAgent.startCall([userCallee, phoneCallee], { threadId: '<THREAD_ID>' });
Dołączanie do połączenia
Dołącz do spotkania w Teams
Spotkania usługi Teams można dołączyć do metody join
w wystąpieniu teamsCallAgent
. Użytkownicy usługi Teams mogą dołączać do spotkania usługi Teams, podając TeamsMeetingLinkLocator
element , TeamsMeetingCoordinatesLocator
lub TeamsMeetingIdLocator
.
Dołącz do spotkania usługi Teams przy użyciu adresu URL spotkania:
const meetingCall = teamsCallAgent.join({ meetingLink: '<MEETING_LINK>' });
Dołącz do spotkania usługi Teams przy użyciu kombinacji identyfikatora wątku, identyfikatora organizatora, identyfikatora dzierżawy i identyfikatora wiadomości:
const meetingCall = teamsCallAgent.join({ threadId: '<THREAD_ID>', organizerId: '<ORGANIZER_ID>', tenantId: '<TENANT_ID>', messageId: '<MESSAGE_ID>' });
Dołącz do spotkania usługi Teams przy użyciu kodu spotkania i kodu dostępu:
const meetingCall = teamsCallAgent.join({ meetingId: '<MEETING_CODE>', passcode: '<PASSCODE>'});
Dołącz do spotkania usługi Teams przy użyciu identyfikatora spotkania i kodu dostępu:
Deweloperzy mogą używać wielu sposobów dołączania do spotkania w usłudze Teams. Jednym z nich jest identyfikator spotkania i kod dostępu, który umożliwia użytkownikom dołączanie do spotkania usługi Teams, do którego są zapraszani z urządzenia lub aplikacji. Aby dołączyć do spotkania, zawsze musisz podać zarówno identyfikator spotkania, jak i kod dostępu. W kodzie dostępu jest uwzględniana wielkość liter.
Format identyfikatora spotkania i kodu dostępu to:
- Identyfikator spotkania: 12 cyfr.
- Kod dostępu: 6 znaków
Jak często trzeba odświeżyć identyfikator spotkania i kod dostępu?
- Identyfikator spotkania i kod dostępu nie zmieniają się po utworzeniu. Deweloperzy nie muszą odświeżać żadnej ze zmian.
- Organizator spotkania usługi Teams nie może ponownie wygenerować identyfikatora spotkania i kodu dostępu.
Czy istnieje różnica w środowisku spotkania usługi Teams, jeśli użytkownik dołącza za pośrednictwem adresu URL lub identyfikatora spotkania i kodu dostępu?
- L.p. Użytkownicy będą mieli takie samo środowisko użytkownika, jeśli dołączą do spotkania usługi Teams za pośrednictwem adresu URL spotkania usługi Teams lub identyfikatora spotkania i kodu dostępu.
Jak deweloperzy powinni przechowywać kod dostępu i zarządzać nim?
- Identyfikator spotkania i kod dostępu są współrzędnymi, aby dołączyć do spotkania. Deweloperzy powinni traktować go jako wpis tajny, który powinien być zaszyfrowany, a następnie przechowywany za kontrolą dostępu.
- Jeśli współrzędne są uwidocznione, każdy może dołączyć do spotkania i zrujnować doświadczenie dla wszystkich na spotkaniu.
Jak uzyskać identyfikator spotkania i kod dostępu?
- Interfejs API programu Graph: użyj interfejsu API programu Graph, aby pobrać informacje o
onlineMeeting
zasobie i sprawdzić obiekt we właściwościjoinMeetingIdSettings
. - Teams: w aplikacji Teams przejdź do
Calendar
aplikacji i otwórz szczegóły spotkania. Spotkania online mają identyfikator spotkania i kod dostępu w definicji spotkania. - Outlook: Identyfikator spotkania i kod dostępu można znaleźć w wydarzeniach kalendarza lub w zaproszeniach na spotkanie e-mail.
- Deweloperzy nie mogą pobrać identyfikatora spotkania i kodu dostępu za pośrednictwem wywoływanego zestawu SDK ani pobrać go z pełnych dzienników konsoli.
- Interfejs API programu Graph: użyj interfejsu API programu Graph, aby pobrać informacje o
Jak sprawdzić, czy identyfikator spotkania i kod dostępu są poprawne?
- Identyfikator spotkania i weryfikacja kodu dostępu można wykonać za pomocą polecenia : https://www.microsoft.com/en-us/microsoft-teams/join-a-meeting
Odbieranie połączenia przychodzącego usługi Teams
Możesz subskrybować incomingCall
zdarzenie na teamsCallAgent
wystąpieniu, aby zarejestrować połączenia przychodzące do użytkownika usługi Teams. Zdarzenie ma właściwość z wystąpieniemteamsIncomingCall
, które umożliwia accept
lub reject
wywołanie przychodzące.TeamsIncomingCall
const incomingCallHandler = async (args: { teamsIncomingCall: TeamsIncomingCall }) => {
const incomingCall = args.teamsIncomingCall;
// Get Teams incoming call ID
const incomingCallId = incomingCall.id;
// Get information about this Call. This API is provided as a preview for developers
// and may change based on feedback that we receive. Do not use this API in a production environment.
// To use this API please use 'beta' release of Azure Communication Services Calling Web SDK
const callInfo = incomingCall.info;
// Get information about caller
const callerInfo = incomingCall.callerInfo
// Accept the call
const teamsCall = await incomingCall.accept();
// Reject the call
incomingCall.reject();
// Subscribe to callEnded event and get the call end reason
incomingCall.on('callEnded', args => {
console.log(args.callEndReason);
});
// callEndReason is also a property of IncomingCall
var callEndReason = incomingCall.callEndReason;
};
teamsCallAgent.on('incomingCall', incomingCallHandler);
Włączanie i wyłączanie wideo
Możesz pobrać lokalną kolekcję strumieni wideo z właściwości localVideoStreams
w wystąpieniu TeamsCall
. Jeśli ta opcja jest włączona, kolekcja będzie zawierać strumień udostępniania ekranu i kanały wideo aparatu. Strumienie wideo uczestników zdalnych można uzyskać, sprawdzając właściwość TeamsCall
.remoteParticipants
gdzie każdy uczestnik ma kolekcję strumieni wideo we właściwości videoStreams
.
Wycisz i Wyłącz wyciszenie
Możesz użyć mute
interfejsów API asynchronicznych i unmute
w wystąpieniu TeamsCall
, aby wyciszyć lub usunąć wyciszenie użytkowników usługi Teams lokalnie. Lokalne wyciszenie uniemożliwi wysyłanie dźwięku do innych uczestników.
//mute local device
await call.mute();
//unmute local device
await call.unmute();
Wycisz innych uczestników
Aby wyciszyć wszystkich innych uczestników lub wyciszyć określonego uczestnika, możesz użyć asynchronicznych interfejsów muteAllRemoteParticipants
API podczas wywołania i mute
uczestnika zdalnego:
//mute all participants except yourself
await call.muteAllRemoteParticipants();
//mute a specific participant
await call.remoteParticipants[0].mute();
Uwaga
Ten interfejs API jest udostępniany dla deweloperów i może zostać zmieniony na podstawie otrzymanych opinii. Nie należy używać tego interfejsu API w środowisku produkcyjnym. Aby użyć tego interfejsu API, użyj wersji beta zestawu SDK wywołującego internetową usługę Azure Communication Services
Zarządzanie uczestnikami zdalnymi
Inni uczestnicy połączeń są dostępni w wystąpieniu TeamsCall
w ramach właściwości remoteParticipants
. Jest to kolekcja RemoteParticipant
obiektów. Możesz wyświetlić listę, dodać i usunąć innych uczestników z wywołania.
Uwaga
Dodanie metody uczestnika wymaga czatu threadId
. Zestaw SDK połączeń usług komunikacyjnych nie przechowuje uczestników podczas rozmowy i synchronizacji listy połączeń. Firma Microsft zachęca deweloperów do synchronizowania listy w celu uzyskania najlepszego środowiska użytkownika. Dowiedz się, jak zarządzać wątkiem czatu.
Możesz dodać nowego użytkownika lub numeru telefonu usługi Teams do połączenia usługi Teams lub spotkania usługi Teams, wywołując metodę addParticipant
w obiekcie TeamsCall
. Metoda akceptuje identyfikatory MicrosoftTeamsUserIdentifier
lub PhoneNumberIdentifier
jako dane wejściowe i zwraca synchronicznie wystąpienie RemoteParticipant
i wyzwala zdarzenie remoteParticipantsUpdated
w wystąpieniu TeamsCall
.
Możesz usunąć uczestnika z połączenia usługi Teams lub spotkania usługi Teams, wywołując metodę removeParticipant
w wystąpieniu TeamsCall
asynchronicznie. Metoda akceptuje identyfikatory MicrosoftTeamsUserIdentifier
lub PhoneNumberIdentifier
jako dane wejściowe. Metoda jest rozpoznawana po RemoteParticipant
usunięciu remoteParticipants
z kolekcji, a zdarzenie remoteParticipantsUpdated
w wystąpieniu TeamsCall
jest wyzwalane.
Wyświetl listę innych uczestników połączeń:
const participants = call.remoteParticipants; // [remoteParticipant, remoteParticipant....]
Dodaj użytkownika i numer telefonu usługi Teams do połączenia usługi Teams lub spotkania usługi Teams:
const teamsUser = { microsoftTeamsUserId: '<MICROSOFT_TEAMS_USER_ID>' };
const phoneUser = { phoneNumber: '<PHONE_NUMBER_E164_FORMAT>' }
const remoteParticipant = call.addParticipant(teamsUser , { threadId: '<THREAD_ID>' });
const remoteParticipant2 = call.addParticipant(phoneUser , { threadId: '<THREAD_ID>' });
Usuń użytkownika i numer telefonu usługi Teams z połączenia usługi Teams lub spotkania w usłudze Teams:
const teamsUser = { microsoftTeamsUserId: '<MICROSOFT_TEAMS_USER_ID>' };
const phoneUser = { phoneNumber: '<PHONE_NUMBER_E164_FORMAT>' }
await call.removeParticipant(teamsUser);
await call.removeParticipant(phoneUser);
Uczestnicy zdalni
Uczestnicy zdalni reprezentują punkt końcowy połączony z trwającym połączeniem usługi Teams lub spotkaniem usługi Teams. Klasa remoteParticipant
ma następujący zestaw właściwości i kolekcji:
identifier
: zwraca jeden z następujących identyfikatorów:CommunicationUserIdentifier
,MicrosoftTeamsUserIdentifier
,PhoneNumberIdentifier
lubUnknownIdentifier
.
const identifier = remoteParticipant.identifier;
state
: zwraca wartośćstring
reprezentującą stan uczestnika zdalnego. Stan może mieć jedną z następujących wartości:
Wartość stanu | Kiedy | opis |
---|---|---|
Idle |
Stan początkowy | Jest to pierwszy stan uczestnika |
Connecting |
Po Idle |
Stan przejścia, gdy uczestnik nawiązuje połączenie z połączeniem. |
Ringing |
Po Connecting |
Uczestnik otrzymał incomingCall powiadomienie lub dzwoni klient usługi Teams |
Connected |
Po Ringing , lub EarlyMedia Connecting InLobby |
Uczestnik zaakceptował zaproszenie do połączenia lub dołączył do połączenia. Nośniki przepływa do uczestnika. |
Hold |
Po Connected |
Uczestnik połączenia został wstrzymany. |
EarlyMedia |
Po Connecting |
Nośniki są odtwarzane przed nawiązaniem połączenia przez uczestnika |
InLobby |
Po Ringing , Connecting lub EarlyMedia |
Uczestnik znajduje się w holu spotkań usługi Teams. |
Disconnected |
Stan końcowy | Uczestnik jest odłączony od połączenia. Jeśli uczestnik zdalny utraci łączność sieciową, jego stan zmieni się na Disconnected po dwóch minutach. |
Stany uczestników zdalnych w wywołaniach jeden do jednego lub grupy:
Stany uczestników zdalnych na spotkaniach usługi Teams:
const state = remoteParticipant.state;
callEndReason
: zwraca obiekt zawierający dodatkowe informacje o przyczynie zakończenia wywołania. Właściwośćcode
zwraca liczbę skojarzona z przyczyną isubCode
zwraca liczbę skojarzona z kodem i przyczyną. Więcej informacji na temat kodów błędów można znaleźć.
const callEndReason = remoteParticipant.callEndReason;
const callEndReasonCode = callEndReason.code
const callEndReasonSubCode = callEndReason.subCode
isMuted
: zwracaBoolean
wartość reprezentującą stan wyciszenia lokalnego.
const isMuted = remoteParticipant.isMuted;
isSpeaking
: zwracaBoolean
wartość reprezentującą stan wysyłanego niepustego dźwięku.
const isSpeaking = remoteParticipant.isSpeaking;
videoStreams
: zwraca kolekcję obiektów wysyłanychRemoteVideoStream
przez uczestników.
const videoStreams = remoteParticipant.videoStreams; // [RemoteVideoStream, ...]
displayName
: zwraca nazwę wyświetlaną reprezentującąstring
. Usługa Communication Services wywołująca zestaw SDK nie ustawia tej wartości dla użytkowników usługi Teams.
const displayName = remoteParticipant.displayName;
Wywołanie
id
: zwraca ciąg reprezentujący unikatowy identyfikator wywołania.
const callId = call.id;
• : info
Zwraca informacje o wywołaniu:
Uwaga
Ten interfejs API jest udostępniany dla deweloperów i może zostać zmieniony na podstawie otrzymanych opinii. Nie należy używać tego interfejsu API w środowisku produkcyjnym. Aby użyć tego interfejsu API, użyj wersji beta zestawu SDK wywołującego internetową usługę Azure Communication Services
• info
: zwraca obiekt zawierający informacje o wywołaniu. Właściwość threadId
jest ciągiem reprezentującym identyfikator wątku czatu pokazany w kliencie usługi Teams.
const callInfo = call.info;
const threadId = call.info.threadId;
• : remoteParticipants
Zwraca kolekcję remoteParticipant
obiektów reprezentujących innych uczestników połączenia usługi Teams lub spotkania usługi Teams.
const remoteParticipants = call.remoteParticipants;
• : callerInfo
zwraca obiekt, CallerInfo
jeśli jest to wywołanie przychodzące. Właściwość identifier
może być jedną z następujących obiektów CommunicationUserIdentifier
, , MicrosoftTeamsUserIdentifier
, PhoneNumberIdentifier
lub UnknownIdentifier
. displayName
Właściwość jest ciągiem reprezentującym nazwę wyświetlaną w przypadku ustawienia.
const callerIdentity = call.callerInfo.identifier;
const callerIdentity = call.callerInfo.displayName;
• : state
zwraca ciąg reprezentujący stan wywołania. Właściwość może mieć jedną z następujących wartości:
Wartość stanu | Kiedy | opis |
---|---|---|
None |
Stan początkowy | Początkowy stan wywołania. |
Connecting |
Po None |
Stan po umieszczeniu, dołączeniu lub zaakceptowaniu spotkania w usłudze Teams lub spotkaniu usługi Teams. |
Ringing |
Po Connecting |
Uczestnik zdalny odebrał incomingCall zdarzenie lub dzwoni klient usługi Teams. |
EarlyMedia |
Po Ringing lub Connecting |
Nośniki są odtwarzane przed połączeniem. |
Connected |
Po Ringing , , InLobby EarlyMedia LocalHold iRemoteHold |
Połączenie jest połączone. Nośnik przepływa między lokalnymi punktami końcowymi i uczestnikami zdalnymi. |
LocalHold |
Po Connected |
Połączenie zostało wstrzymane przez lokalnego uczestnika. Żaden nośnik nie przepływa między lokalnym punktem końcowym a uczestnikami zdalnymi. |
RemoteHold |
Po Connected |
Połączenie zostało wstrzymane przez uczestnika zdalnego. Żaden nośnik nie przepływa między lokalnym punktem końcowym a uczestnikami zdalnymi. |
InLobby |
Po Ringing lub Connecting |
Uczestnik zdalny znajduje się w holu spotkań usługi Teams. Żaden nośnik nie przepływa między lokalnym punktem końcowym a uczestnikami zdalnymi. |
Disconnecting |
Po dowolnym stanie | Stan przejścia przed przejściem wywołania Disconnected do stanu. |
Disconnected |
Stan końcowy | Końcowy stan połączenia. Jeśli połączenie sieciowe zostanie utracone, stan zmieni się na Disconnected po dwóch minutach. |
Stany dla wywołań jeden-do-jednego lub grup:
Stany spotkań usługi Teams:
const callState = call.state;
• callEndReason
: Zwraca obiekt CallEndReason
zawierający dodatkowe informacje o zakończonym wywołaniu. Właściwość code
zwraca liczbę skojarzona z przyczyną i subCode
zwraca liczbę skojarzona z kodem i przyczyną. Więcej informacji na temat kodów błędów można znaleźć
const callEndReason = call.callEndReason;
const callEndReasonCode = callEndReason.code
const callEndReasonSubCode = callEndReason.subCode
• : direction
zwraca string
kierunek wywołania. Właściwość może mieć jedną z następujących wartości: "Przychodzące" lub Outgoing
.
const isIncoming = call.direction == 'Incoming';
const isOutgoing = call.direction == 'Outgoing';
• : isMuted
Zwraca Boolean
wartość reprezentującą stan wyciszenia lokalnego.
const muted = call.isMuted;
• : isScreenSharingOn
Zwraca Boolean
wartość true, jeśli wysyłasz strumień udostępniania ekranu do innych uczestników.
const isScreenSharingOn = call.isScreenSharingOn;
• localVideoStreams
: zwraca kolekcję LocalVideoStream
obiektów reprezentujących strumienie wideo wysyłane do uczestników zdalnych.
const localVideoStreams = call.localVideoStreams;
Zarządzanie wątkiem czatu
Podanie identyfikatora czatu jest obowiązkowe do nawiązywania połączeń grupowych i dodawania uczestników do istniejących połączeń. Skojarzony czat i połączenie mają oddzielną listę uczestników. Przed dodaniem uczestników do połączenia dodaj użytkownika do czatu, aby zapewnić najlepsze środowisko użytkownika i spełnić wymagania dotyczące barier informacyjnych. Dodanie użytkownika do połączenia bez dodawania użytkownika do czatu może spowodować wyjątki, jeśli zostanie skonfigurowana bariera informacyjna.
Rozważmy następujący scenariusz, w którym Alice wywołuje Boba, a następnie Alice dodaje Charliego, a 3 minuty później Alice usuwa Charliego z połączenia.
- Utwórz wątek czatu między Alice, Bob i Charlie. Zachowaj czas rozmowy
threadId
na później. - Alicja wywołuje Boba i Charliego przy użyciu
startCall
metody wTeamsCallAgent
wystąpieniu. - Dodawanie elementu Dan do wątku
threadId
czatu przy użyciu interfejsu API programu Chat Graph w celu dodania członka - Alicja dodaje dan do wywołania przy użyciu
addParticipant
metody oncall
i określathreadId
- Alice usuwa dan z wywołania przy użyciu
removeParticipant
metody oncall
i określathreadId
- Usuwanie elementu Dan z wątku
threadId
czatu przy użyciu interfejsu API programu Chat Graph w celu usunięcia członka
Jeśli użytkownik usługi Teams zatrzymuje nagrywanie połączeń, nagranie zostanie umieszczone w czacie skojarzonym z wątkiem. Podany identyfikator czatu ma wpływ na środowisko użytkowników usługi Teams w klientach usługi Teams.
Rekomendacje zarządzania identyfikatorem czatu:
- Eskalacja połączenia telefonicznego 1:1 przez dodanie innego uczestnika telefonu: Użyj interfejsu API programu Graph, aby uzyskać istniejący identyfikator czatu tylko jako uczestnik lub utworzyć nowy czat grupy z uczestnikami: identyfikator użytkownika usługi Teams i "000000000-0000-0000-0000-000000000000000000"
- Połączenie grupowe z jednym użytkownikiem usługi Teams i wieloma uczestnikami telefonu: użyj interfejsu API programu Graph, aby uzyskać istniejący identyfikator czatu z użytkownikiem usługi Teams tylko jako uczestnik lub utworzyć nowy czat grupowy z uczestnikami: identyfikator użytkownika aplikacji Teams i "0000000-0000-0000000000000000000000"
- Wywołanie grupy z ponad 2 użytkownikami usługi Teams: użyj interfejsu API programu Graph, aby uzyskać lub utworzyć czat grupowy z użytkownikami usługi Teams
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla