Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

site open extensions, graph pages support, DebugHeaders #3153

Merged
merged 19 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions debug/launch/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ import { Example } from "./sp.js";
// create a settings file using settings.example.js as a template
import(findup("settings.js")).then((settings: { settings: ITestingSettings }) => {

Logger.activeLogLevel = LogLevel.Info;
Logger.activeLogLevel = LogLevel.Info;

// // setup console logger
Logger.subscribe(ConsoleListener("Debug", {
color: "skyblue",
error: "red",
verbose: "lightslategray",
warning: "yellow",
}));
}));

Example(settings.settings);

Expand Down
30 changes: 17 additions & 13 deletions debug/launch/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ import { SPDefault, GraphDefault } from "@pnp/nodejs";
import { spfi, SPFI } from "@pnp/sp";
import { GraphFI, graphfi } from "@pnp/graph";
import { LogLevel, PnPLogging } from "@pnp/logging";
import { Queryable } from "@pnp/queryable";
import { Queryable, DebugHeaders } from "@pnp/queryable";

export function spSetup(settings: ITestingSettings): SPFI {

const sp = spfi(settings.testing.sp.url).using(SPDefault({
msal: {
config: settings.testing.sp.msal.init,
scopes: settings.testing.sp.msal.scopes,
},
})).using(
const sp = spfi(settings.testing.sp.url).using(
SPDefault({
msal: {
config: settings.testing.sp.msal.init,
scopes: settings.testing.sp.msal.scopes,
},
}),
PnPLogging(LogLevel.Verbose),
DebugHeaders(),
function (instance: Queryable) {

instance.on.pre(async (url, init, result) => {
Expand All @@ -29,13 +31,15 @@ export function spSetup(settings: ITestingSettings): SPFI {

export function graphSetup(settings: ITestingSettings): GraphFI {

const graph = graphfi().using(GraphDefault({
msal: {
config: settings.testing.graph.msal.init,
scopes: settings.testing.graph.msal.scopes,
},
})).using(
const graph = graphfi().using(
GraphDefault({
msal: {
config: settings.testing.graph.msal.init,
scopes: settings.testing.graph.msal.scopes,
},
}),
PnPLogging(LogLevel.Verbose),
DebugHeaders(),
function (instance: Queryable) {

instance.on.pre(async (url, init, result) => {
Expand Down
5 changes: 2 additions & 3 deletions debug/launch/sp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,20 @@ import { Logger, LogLevel } from "@pnp/logging";
import { spSetup } from "./setup.js";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";

declare var process: { exit(code?: number): void };

export async function Example(settings: ITestingSettings) {

const sp = spSetup(settings);

const w = await sp.web();
const w = await sp.web.lists();

Logger.log({
data: w,
level: LogLevel.Info,
message: "Web Data",
});

process.exit(0);
}
3 changes: 3 additions & 0 deletions docs/graph/site-openextensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Site Open Extensions

// TODO
37 changes: 37 additions & 0 deletions docs/queryable/behaviors.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,40 @@ setTimeout(() => {
// this is awaiting the results of the request
await p;
```

### DebugHeaders

Adds logging for the request id and timestamp of the request, helpful when contacting Microsoft Support. It works for both Graph and SP libraries.

```TypeScript
import { DebugHeaders } from "@pnp/queryable";
import { spfi } from "@pnp/sp";

const sp = spfi().using(DebugHeaders());

sp.some_action();

// output to log:
// Server Request Id: {guid}
// Server Date: {date}
```

You can also supply additional headers to log from the response:


```TypeScript
import { DebugHeaders } from "@pnp/queryable";
import { spfi } from "@pnp/sp";

const sp = spfi().using(DebugHeaders(["X-MyHeader", "client-request-id"]));

sp.some_action();

// output to log:
// Server Request Id: {guid}
// Server Date: {date}
// X-MyHeader: {value}
// client-request-id: {guid}
```


1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ nav:
- search: 'graph/search.md'
- shares: 'graph/shares.md'
- sites: 'graph/sites.md'
- 'site openextensions': 'graph/site-openextensions.md'
- subscriptions: 'graph/subscriptions.md'
- taxonomy: 'graph/taxonomy.md'
- teams: 'graph/teams.md'
Expand Down
3 changes: 1 addition & 2 deletions packages/core/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ export function combine(...paths: (string | null | undefined)[]): string {

return paths
.filter(path => !stringIsNullOrEmpty(path))
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
.map(path => path!.replace(/^[\\|/]/, "").replace(/[\\|/]$/, ""))
.map(path => path.replace(/^[\\|/]/, "").replace(/[\\|/]$/, ""))
.join("/")
.replace(/\\/g, "/");
}
Expand Down
4 changes: 2 additions & 2 deletions packages/graph/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ export function getById<R>(factory: (...args: any[]) => R) {
return function <T extends { new(...args: any[]): {} }>(target: T) {

return class extends target {
public getById(this: IGraphQueryable, id: string): R {
return factory(this, id);
public getById(this: IGraphQueryable, id: any): R {
return factory(this, `${id}`);
}
};
};
Expand Down
29 changes: 9 additions & 20 deletions packages/graph/graphqueryable.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isArray, objectDefinedNotNull } from "@pnp/core";
import { isArray } from "@pnp/core";
import { IInvokable, Queryable, queryableFactory, op, get, post, patch, del, put } from "@pnp/queryable";
import { ConsistencyLevel } from "./behaviors/consistency-level.js";
import { IPagedResult, Paged } from "./behaviors/paged.js";
Expand Down Expand Up @@ -80,17 +80,12 @@ export class _GraphQueryable<GetType = any> extends Queryable<GetType> {
*
* @param factory The contructor for the class to create
*/
protected getParent<T extends _GraphQueryable>(
factory: IGraphConstructor<T>,
base: GraphInit = this.parentUrl,
path?: string): T {
protected getParent<T extends IGraphQueryable>(
factory: IGraphInvokableFactory<any>,
path?: string,
base: string = this.parentUrl): T {

if (typeof base === "string") {
// we need to ensure the parent has observers, even if we are rebasing the url (#2435)
base = [this, base];
}

return new factory(base, path);
return factory([this, base], path);
}
}

Expand Down Expand Up @@ -169,13 +164,9 @@ export class _GraphCollection<GetType = any[]> extends _GraphQueryable<GetType>

const q = GraphCollection(this).using(Paged(), ConsistencyLevel());

const queryParams = ["$search", "$top", "$select", "$expand", "$filter", "$orderby"];

for (let i = 0; i < queryParams.length; i++) {
const param = this.query.get(queryParams[i]);
if (objectDefinedNotNull(param)) {
q.query.set(queryParams[i], param);
}
// Issue #3136, some APIs take other query params that need to persist through the paging, so we just include everything
for (const [key, value] of this.query) {
q.query.set(key, value);
}

return <AsyncIterator<GetType>>{
Expand All @@ -201,7 +192,6 @@ export class _GraphCollection<GetType = any[]> extends _GraphQueryable<GetType>
};
}
}

export interface IGraphCollection<GetType = any[]> extends _GraphCollection<GetType> { }
export const GraphCollection = graphInvokableFactory<IGraphCollection>(_GraphCollection);

Expand All @@ -210,7 +200,6 @@ export const GraphCollection = graphInvokableFactory<IGraphCollection>(_GraphCol
*
*/
export class _GraphInstance<GetType = any> extends _GraphQueryable<GetType> { }

export interface IGraphInstance<GetType = any> extends IInvokable, IGraphQueryable<GetType> { }
export const GraphInstance = graphInvokableFactory<IGraphInstance>(_GraphInstance);

Expand Down
12 changes: 9 additions & 3 deletions packages/graph/onenote/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@ export {
INotebook,
INotebooks,
IOneNote,
IPages,
IResources,
ISection,
ISections,
Notebook,
Notebooks,
OneNote,
Page,
Pages,
ICopyProps,
IOnenotePage,
IOnenotePages,
ISectionGroup,
ISectionGroups,
OnenotePage,
OnenotePages,
SectionGroup,
SectionGroups,
Resources,
Section,
Sections,
Expand Down
24 changes: 12 additions & 12 deletions packages/graph/onenote/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export class _OneNote extends _GraphInstance<IOnenoteType> {
return Notebooks(this);
}

public get pages(): IPages {
return Pages(this);
public get pages(): IOnenotePages {
return OnenotePages(this);
}

public get resources(): IResources {
Expand Down Expand Up @@ -107,8 +107,8 @@ export const Notebooks = graphInvokableFactory<INotebooks>(_Notebooks);
*/
export class _Section extends _GraphInstance<IOnenoteSectionType> {

public get pages(): IPages {
return Pages(this);
public get pages(): IOnenotePages {
return OnenotePages(this);
}

/**
Expand Down Expand Up @@ -187,7 +187,7 @@ export const SectionGroups = graphInvokableFactory<ISectionGroups>(_SectionGroup
*
*/
@deleteable()
export class _Page extends _GraphInstance<IOnenotePageType> {
export class _OnenotePage extends _GraphInstance<IOnenotePageType> {
/**
* Copy page to section
* @param props of type ICopyPageProps. groupId (id of group to copy to. Use only when copying to M365 group), id of destination notebook
Expand All @@ -202,7 +202,7 @@ export class _Page extends _GraphInstance<IOnenotePageType> {
* @param includeIDs page html body
*/
public async content(includeIDs = false): Promise<string> {
return Page(this, `content?includeIDs=${includeIDs}`).using(TextParse())();
return OnenotePage(this, `content?includeIDs=${includeIDs}`).using(TextParse())();
}

/**
Expand All @@ -213,16 +213,16 @@ export class _Page extends _GraphInstance<IOnenotePageType> {
return graphPatch(GraphQueryable(this, "content"), body(props));
}
}
export interface IPage extends _Page, IDeleteable { }
export const Page = graphInvokableFactory<IPage>(_Page);
export interface IOnenotePage extends _OnenotePage, IDeleteable { }
export const OnenotePage = graphInvokableFactory<IOnenotePage>(_OnenotePage);

/**
* Describes a collection of page objects
*
*/
@defaultPath("pages")
@getById(Page)
export class _Pages extends _GraphCollection<IOnenotePageType[]> {
@getById(OnenotePage)
export class _OnenotePages extends _GraphCollection<IOnenotePageType[]> {
/**
* Create a new page as specified in the request body.
*
Expand All @@ -237,8 +237,8 @@ export class _Pages extends _GraphCollection<IOnenotePageType[]> {
return graphPost(q, { body: html });
}
}
export interface IPages extends _Pages, IGetById<IPage> { }
export const Pages = graphInvokableFactory<IPages>(_Pages);
export interface IOnenotePages extends _OnenotePages, IGetById<IOnenotePage> { }
export const OnenotePages = graphInvokableFactory<IOnenotePages>(_OnenotePages);

/**
* Describes a resources
Expand Down
9 changes: 9 additions & 0 deletions packages/graph/open-extensions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import "./site.js";

export {
IBaseExtensionData as IBaseOpenExtension,
IOpenExtension,
IOpenExtensions,
OpenExtension,
OpenExtensions,
} from "./types.js";
13 changes: 13 additions & 0 deletions packages/graph/open-extensions/site.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { addProp } from "@pnp/queryable";
import { _Site } from "../sites/types.js";
import { IOpenExtensions, OpenExtensions } from "./types.js";

declare module "../sites/types" {
interface _Site {
readonly extensions: IOpenExtensions;
}
interface ISite {
readonly extensions: IOpenExtensions;
}
}
addProp(_Site, "extensions", OpenExtensions);
40 changes: 40 additions & 0 deletions packages/graph/open-extensions/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { body } from "@pnp/queryable";
import { Extension as ExtensionType } from "@microsoft/microsoft-graph-types";
import { _GraphCollection, graphInvokableFactory, graphPatch, graphPost } from "../graphqueryable.js";
import { getById, IGetById, deleteable, IDeleteable, defaultPath } from "../decorators.js";

export interface IBaseExtensionData {
extensionName: string;
}

/**
* Open Extension
*/
@deleteable()
export class _OpenExtension extends _GraphCollection<ExtensionType> {

public update<T extends IBaseExtensionData>(extension: T): Promise<any> {
return graphPatch(this, body(extension));
}
}
export interface IOpenExtension extends _OpenExtension, IDeleteable { }
export const OpenExtension = graphInvokableFactory<IOpenExtension>(_OpenExtension);

/**
* Open Extensions
*/
@defaultPath("extensions")
@getById(OpenExtension)
export class _OpenExtensions extends _GraphCollection<ExtensionType> {

public create<T extends IBaseExtensionData>(extension: T): Promise<any> {

if (extension.extensionName.length > 30) {
throw Error("Extension id length should be less than or equal to 30 characters.");
}

return graphPost(this, body(extension));
}
}
export interface IOpenExtensions extends _OpenExtensions, IGetById<IOpenExtension> { }
export const OpenExtensions = graphInvokableFactory<IOpenExtensions>(_OpenExtensions);
Loading