This commit is contained in:
Hugo Bernier 2022-12-30 22:44:59 -05:00
commit 5820cd56ef
10 changed files with 11383 additions and 13849 deletions

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@
"office-ui-fabric-react": "6.189.2",
"@types/webpack-env": "1.13.1",
"botframework-directlinejs": "^0.11.4",
"botframework-webchat": "^4.5.2",
"botframework-webchat": "^4.15.6",
"react": "16.8.5",
"react-dom": "16.8.5",
"swagger-client": "^2.1.23"

View File

@ -0,0 +1 @@
v14.20.0

View File

@ -30,6 +30,7 @@ Version|Date|Comments
1.4|June 29, 2022|Adds the capability to find collapsible section headers and insert them into the navigation
1.5|July 19, 2022|Bug fixes
1.6|August 8, 2022|Add theme provider and bug fixes
1.7|December 22, 2022|Fixed issue with duplicated level 2 headings
## Minimal Path to Awesome

View File

@ -9,7 +9,7 @@
"This web part fetches all the automatically added Header anchor tags in a SharePoint page and displays them in a Navigation component."
],
"creationDateTime": "2019-09-05",
"updateDateTime": "2022-08-17",
"updateDateTime": "2022-12-22",
"products": [
"SharePoint"
],

View File

@ -1,4 +1,5 @@
{
"preset": "@voitanos/jest-preset-spfx-react16",
"rootDir": "../src"
"rootDir": "../src",
"collectCoverage": false
}

View File

@ -0,0 +1,280 @@
import { IHierarchyEntry, navLinkBuilder } from "./NavLinkBuilder";
interface IMockLink extends IHierarchyEntry<IMockLink> {
name: string;
}
const DEPTH_NO_COLLAPSABLE_HEADER = 0;
const DEPTH_COLLAPSABLE_HEADER = 1;
describe("The NavLinkBuilder without a preceding collapsable header", () => {
const depth = DEPTH_NO_COLLAPSABLE_HEADER;
const h1 = depth;
const h2 = h1+1;
const h3 = h2+1;
const h4 = h3+1;
it("should add a single item to an empty list", () => {
const lnk: IMockLink = {
name: "xyz",
};
const actual = [];
navLinkBuilder.build(actual, lnk, h1);
expect(actual).toMatchSnapshot();
});
it("should add a two items on the same level", () => {
const lnk1: IMockLink = {
name: "xyz",
};
const lnk2: IMockLink = {
name: "abc",
};
const actual = [];
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk2, h1);
expect(actual).toMatchSnapshot();
})
it("should add a two items on different levels", () => {
const lnk1: IMockLink = {
name: "xyz",
};
const lnk2: IMockLink = {
name: "abc",
};
const actual = [];
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk2, h2);
expect(actual).toMatchSnapshot();
});
it("should add a two items on the same level and two items on different levels", () => {
const lnk1: IMockLink = {
name: "xyz",
};
const lnk2: IMockLink = {
name: "abc",
};
const lnk11: IMockLink = {
name: "xyz.1",
};
const lnk21: IMockLink = {
name: "abc.1",
};
const actual = [];
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk11, h2);
navLinkBuilder.build(actual, lnk2, h1);
navLinkBuilder.build(actual, lnk21, h2);
expect(actual).toMatchSnapshot();
});
it("should add a four items on different levels", () => {
const lnk1: IMockLink = {
name: "xyz",
};
const lnk2: IMockLink = {
name: "abc",
};
const lnk3: IMockLink = {
name: "def",
};
const lnk4: IMockLink = {
name: "geh",
};
const actual = [];
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk2, h2);
navLinkBuilder.build(actual, lnk3, h3);
navLinkBuilder.build(actual, lnk4, h4);
expect(actual).toMatchSnapshot();
});
it("should not nest two h2", () => {
const lnk1: IMockLink = {
name: "h1",
};
const lnk2: IMockLink = {
name: "h2",
};
const lnk3: IMockLink = {
name: "h2",
};
const lnk4: IMockLink = {
name: "h3",
};
const actual = []
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk2, h2);
navLinkBuilder.build(actual, lnk3, h2);
navLinkBuilder.build(actual, lnk4, h3);
expect(actual).toMatchSnapshot();
});
it("should not nest two h3", () => {
const lnk0: IMockLink = {
name: "h1",
};
const lnk1: IMockLink = {
name: "h1",
};
const lnk2: IMockLink = {
name: "h2",
};
const lnk3: IMockLink = {
name: "h2",
};
const lnk4: IMockLink = {
name: "h3",
};
const lnk5: IMockLink = {
name: "h3",
};
const lnk6: IMockLink = {
name: "h4",
};
const actual = [];
navLinkBuilder.build(actual, lnk0, h1);
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk2, h2);
navLinkBuilder.build(actual, lnk3, h2);
navLinkBuilder.build(actual, lnk4, h3);
navLinkBuilder.build(actual, lnk5, h3);
navLinkBuilder.build(actual, lnk6, h4);
expect(actual).toMatchSnapshot();
});
});
describe("The NavLinkBuilder with a collapsable header", () => {
let head: IMockLink;
const depth = DEPTH_COLLAPSABLE_HEADER;
const h1 = depth;
const h2 = h1+1;
const h3 = h2+1;
const h4 = h3+1;
beforeEach(() => {
head = {
name: "head",
};
});
it("should add a single item to the heading", () => {
const lnk: IMockLink = {
name: "xyz",
};
const actual = [ head ];
navLinkBuilder.build(actual, lnk, h1);
expect(actual).toMatchSnapshot();
});
it("should add a two items on the same level", () => {
const lnk1: IMockLink = {
name: "xyz",
};
const lnk2: IMockLink = {
name: "abc",
};
const actual = [ head ];
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk2, h1);
expect(actual).toMatchSnapshot();
})
it("should add a one item in a collapsable section two inside that one", () => {
const lnk1: IMockLink = {
name: "xyz",
};
const lnk2: IMockLink = {
name: "abc",
};
const lnk3: IMockLink = {
name: "def",
};
const actual = [ head ];
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk2, h2);
navLinkBuilder.build(actual, lnk3, h2);
expect(actual).toMatchSnapshot();
})
it("should not nest two h2", () => {
const lnk1: IMockLink = {
name: "h1",
};
const lnk2: IMockLink = {
name: "h2",
};
const lnk3: IMockLink = {
name: "h2",
};
const lnk4: IMockLink = {
name: "h3",
};
const actual = [ head ];
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk2, h2);
navLinkBuilder.build(actual, lnk3, h2);
navLinkBuilder.build(actual, lnk4, h3);
expect(actual).toMatchSnapshot();
});
it("should not nest two h3", () => {
const lnk0: IMockLink = {
name: "h1",
};
const lnk1: IMockLink = {
name: "h1",
};
const lnk2: IMockLink = {
name: "h2",
};
const lnk3: IMockLink = {
name: "h2",
};
const lnk4: IMockLink = {
name: "h3",
};
const lnk5: IMockLink = {
name: "h3",
};
const lnk6: IMockLink = {
name: "h4",
};
const actual = [ head ];
navLinkBuilder.build(actual, lnk0, h1);
navLinkBuilder.build(actual, lnk1, h1);
navLinkBuilder.build(actual, lnk2, h2);
navLinkBuilder.build(actual, lnk3, h2);
navLinkBuilder.build(actual, lnk4, h3);
navLinkBuilder.build(actual, lnk5, h3);
navLinkBuilder.build(actual, lnk6, h4);
expect(actual).toMatchSnapshot();
});
});

View File

@ -0,0 +1,27 @@
export interface IHierarchyEntry<T extends IHierarchyEntry<T>> {
links?: IHierarchyEntry<T>[];
}
export class navLinkBuilder {
/**
* Nests a new nav link within the nav links tree. Modifies the current tree IN PLACE.
* @param currentLinks current nav links
* @param newLink the new nav link to be added to the structure
* @param order place order of the new link
* @returns navLinks
*/
public static build<T extends IHierarchyEntry<T>>(currentLinks: T[], newLink: T, order: number) {
const lastIndex = currentLinks.length - 1;
if (lastIndex < 0 || order <= 0) {
currentLinks.push(newLink);
return;
}
const lastTopLevelLink = currentLinks[lastIndex];
lastTopLevelLink.links = lastTopLevelLink.links || [];
order--;
this.build(lastTopLevelLink.links, newLink, order);
}
}

View File

@ -1,6 +1,7 @@
import { INavLink } from 'office-ui-fabric-react/lib/Nav';
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { SPHttpClient } from '@microsoft/sp-http';
import { navLinkBuilder } from './NavLinkBuilder';
export class SPService {
/* Array to store all unique anchor URLs */
@ -37,33 +38,6 @@ export class SPService {
return anchorUrl;
}
/**
* Nests a new nav link within the nav links tree
* @param currentLinks current nav links
* @param newLink the new nav link to be added to the structure
* @param order place order of the new link
* @param depth sequence depth
* @returns navLinks
*/
public static navLinkBuilder(currentLinks: INavLink[], newLink: INavLink, order: number, depth: number): INavLink[] {
const lastIndex = currentLinks.length - 1;
if (lastIndex === -1) {
currentLinks.push(newLink);
} else if (currentLinks[lastIndex].links.length === 0 || order === depth) {
if (order !== depth || depth !== 0) {
currentLinks[lastIndex].links.push(newLink);
} else {
currentLinks.push(newLink);
}
} else {
depth++;
currentLinks[lastIndex].links.concat(this.navLinkBuilder(currentLinks[lastIndex].links, newLink, order, depth));
}
return currentLinks;
}
/**
* Returns the Anchor Links for Nav element
* @param context Web part context
@ -126,7 +100,7 @@ export class SPService {
// Add link to nav element
const newNavLink: INavLink = { name: headingValue, key: anchorUrl, url: anchorUrl, links: [], isExpanded: true };
anchorLinks = this.navLinkBuilder(anchorLinks, newNavLink, headingOrder, hasCollapsableHeader ? 1 : 0);
navLinkBuilder.build<INavLink>(anchorLinks, newNavLink, headingOrder);
});
}
});

View File

@ -0,0 +1,243 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`The NavLinkBuilder with a collapsable header should add a one item in a collapsable section two inside that one 1`] = `
Array [
Object {
"links": Array [
Object {
"links": Array [
Object {
"name": "abc",
},
Object {
"name": "def",
},
],
"name": "xyz",
},
],
"name": "head",
},
]
`;
exports[`The NavLinkBuilder with a collapsable header should add a single item to the heading 1`] = `
Array [
Object {
"links": Array [
Object {
"name": "xyz",
},
],
"name": "head",
},
]
`;
exports[`The NavLinkBuilder with a collapsable header should add a two items on the same level 1`] = `
Array [
Object {
"links": Array [
Object {
"name": "xyz",
},
Object {
"name": "abc",
},
],
"name": "head",
},
]
`;
exports[`The NavLinkBuilder with a collapsable header should not nest two h2 1`] = `
Array [
Object {
"links": Array [
Object {
"links": Array [
Object {
"name": "h2",
},
Object {
"links": Array [
Object {
"name": "h3",
},
],
"name": "h2",
},
],
"name": "h1",
},
],
"name": "head",
},
]
`;
exports[`The NavLinkBuilder with a collapsable header should not nest two h3 1`] = `
Array [
Object {
"links": Array [
Object {
"name": "h1",
},
Object {
"links": Array [
Object {
"name": "h2",
},
Object {
"links": Array [
Object {
"name": "h3",
},
Object {
"links": Array [
Object {
"name": "h4",
},
],
"name": "h3",
},
],
"name": "h2",
},
],
"name": "h1",
},
],
"name": "head",
},
]
`;
exports[`The NavLinkBuilder without a preceding collapsable header should add a four items on different levels 1`] = `
Array [
Object {
"links": Array [
Object {
"links": Array [
Object {
"links": Array [
Object {
"name": "geh",
},
],
"name": "def",
},
],
"name": "abc",
},
],
"name": "xyz",
},
]
`;
exports[`The NavLinkBuilder without a preceding collapsable header should add a single item to an empty list 1`] = `
Array [
Object {
"name": "xyz",
},
]
`;
exports[`The NavLinkBuilder without a preceding collapsable header should add a two items on different levels 1`] = `
Array [
Object {
"links": Array [
Object {
"name": "abc",
},
],
"name": "xyz",
},
]
`;
exports[`The NavLinkBuilder without a preceding collapsable header should add a two items on the same level 1`] = `
Array [
Object {
"name": "xyz",
},
Object {
"name": "abc",
},
]
`;
exports[`The NavLinkBuilder without a preceding collapsable header should add a two items on the same level and two items on different levels 1`] = `
Array [
Object {
"links": Array [
Object {
"name": "xyz.1",
},
],
"name": "xyz",
},
Object {
"links": Array [
Object {
"name": "abc.1",
},
],
"name": "abc",
},
]
`;
exports[`The NavLinkBuilder without a preceding collapsable header should not nest two h2 1`] = `
Array [
Object {
"links": Array [
Object {
"name": "h2",
},
Object {
"links": Array [
Object {
"name": "h3",
},
],
"name": "h2",
},
],
"name": "h1",
},
]
`;
exports[`The NavLinkBuilder without a preceding collapsable header should not nest two h3 1`] = `
Array [
Object {
"name": "h1",
},
Object {
"links": Array [
Object {
"name": "h2",
},
Object {
"links": Array [
Object {
"name": "h3",
},
Object {
"links": Array [
Object {
"name": "h4",
},
],
"name": "h3",
},
],
"name": "h2",
},
],
"name": "h1",
},
]
`;