Skip to content

Commit a1b5a39

Browse files
committed
Merge branch 'main' into tryMoveAuth
2 parents 9c661b2 + 6a9e81a commit a1b5a39

15 files changed

Lines changed: 30415 additions & 1179 deletions

File tree

package-lock.json

Lines changed: 30043 additions & 959 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"babel-loader": "^8.2.3",
9494
"eslint": "^7.32.0",
9595
"eslint-plugin-jest": "^25.3.0",
96+
"eslint-import-resolver-typescript": "^2.5.0",
9697
"husky": "^7.0.4",
9798
"jest": "^27.4.5",
9899
"jsdom": "^19.0.0",

src/acl/access-groups.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { AccessController } from './access-controller'
1212
import { AgentMapMap, ComboList, PartialAgentTriple } from './types'
1313
import { AddAgentButtons } from './add-agent-buttons'
1414
import * as debug from '../debug'
15-
import { LiveStore } from 'pane-registry'
15+
import { LiveStore } from 'solid-logic'
1616

1717
const ACL = ns.acl
1818

src/acl/acl.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
*/
77

88
import * as ns from '../ns'
9-
import { solidLogicSingleton, ACL_LINK } from 'solid-logic'
9+
import { solidLogicSingleton, ACL_LINK, LiveStore } from 'solid-logic'
1010
import * as utils from '../utils'
1111
import { AgentMapMap, AgentMapUnion, ComboList } from './types'
1212
import * as debug from '../debug'
1313
import { graph, IndexedFormula, NamedNode, serialize, st, Statement, sym } from 'rdflib'
14-
import { LiveStore } from 'pane-registry'
1514

1615
const kb = solidLogicSingleton.store
1716

src/footer/index.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
This file was copied from mashlib/src/global/footer.ts file. It is modified to
3+
work in solid-ui by adjusting where imported functions are found.
4+
*/
5+
import { IndexedFormula, NamedNode } from 'rdflib'
6+
import { authn } from 'solid-logic'
7+
import { addStyleClassToElement, getName, getPod, getPodOwner } from '../utils/headerFooterHelpers'
8+
9+
const DEFAULT_SOLID_PROJECT_URL = 'https://solidproject.org'
10+
const DEFAULT_SOLID_PROJECT_NAME = 'solidproject.org'
11+
12+
/*
13+
FooterOptions allow for customizing the link and name of the link part of the footer.
14+
*/
15+
export type FooterOptions = {
16+
solidProjectUrl?: string,
17+
solidProjectName?: string
18+
}
19+
20+
/**
21+
* Initialize footer component, the footer object returned depends on whether the user is authenticated.
22+
* @param store the data store
23+
* @returns the footer
24+
*/
25+
export async function initFooter (store: IndexedFormula, options?: FooterOptions) {
26+
const footer = document.getElementById('PageFooter')
27+
if (!footer) {
28+
return
29+
}
30+
const pod = getPod()
31+
const podOwner = await getPodOwner(pod, store)
32+
rebuildFooter(footer, store, pod, podOwner, options)()
33+
authn.authSession.onLogin(rebuildFooter(footer, store, pod, podOwner, options))
34+
authn.authSession.onLogout(rebuildFooter(footer, store, pod, podOwner, options))
35+
}
36+
/**
37+
* @ignore exporting this only for the unit test
38+
*/
39+
export function rebuildFooter (footer: HTMLElement, store: IndexedFormula, pod: NamedNode | null, podOwner: NamedNode | null, options?: FooterOptions) {
40+
return async () => {
41+
const user = authn.currentUser()
42+
footer.innerHTML = ''
43+
footer.appendChild(await createControllerInfoBlock(store, user, pod, podOwner, options))
44+
}
45+
}
46+
/**
47+
* @ignore exporting this only for the unit test
48+
*/
49+
export function createControllerInfoBlock (store: IndexedFormula, user: NamedNode | null, pod: NamedNode | null, podOwner: NamedNode | null, options?: FooterOptions): HTMLElement {
50+
const profileLinkContainer = document.createElement('div')
51+
if (!pod || !podOwner || (user && user.equals(podOwner))) {
52+
return profileLinkContainer
53+
}
54+
55+
addStyleClassToElement(profileLinkContainer, ['footer-pod-info', 'footer'], 'footer')
56+
57+
const podLinkPre = document.createElement('span')
58+
podLinkPre.innerText = "You're visiting "
59+
60+
const podLink = document.createElement('a')
61+
podLink.href = pod.uri
62+
podLink.innerText = 'the Pod'
63+
64+
const profileLinkPre = document.createElement('span')
65+
profileLinkPre.innerText = ' controlled by '
66+
67+
const profileLink = document.createElement('a')
68+
profileLink.href = podOwner.uri
69+
profileLink.innerText = getName(store, podOwner)
70+
71+
const solidProjectLinkPre = document.createElement('span')
72+
solidProjectLinkPre.innerText = '. For more info, check out '
73+
74+
const solidProjectLink = document.createElement('a')
75+
solidProjectLink.href = options && options.solidProjectUrl ? options.solidProjectUrl : DEFAULT_SOLID_PROJECT_URL
76+
solidProjectLink.innerText = options && options.solidProjectName ? options.solidProjectName : DEFAULT_SOLID_PROJECT_NAME
77+
78+
const solidProjectLinkPost = document.createElement('span')
79+
solidProjectLinkPost.innerText = '.'
80+
81+
profileLinkContainer.appendChild(podLinkPre)
82+
profileLinkContainer.appendChild(podLink)
83+
profileLinkContainer.appendChild(profileLinkPre)
84+
profileLinkContainer.appendChild(profileLink)
85+
profileLinkContainer.appendChild(solidProjectLinkPre)
86+
profileLinkContainer.appendChild(solidProjectLink)
87+
profileLinkContainer.appendChild(solidProjectLinkPost)
88+
89+
return profileLinkContainer
90+
}

src/footer/styleMap.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export const styleMap = {
2+
footer: {
3+
borderTop: 'solid 1px $divider-color',
4+
fontSize: '0.9em',
5+
padding: '0.5em 1.5em'
6+
}
7+
}

src/header/index.ts

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,90 +4,101 @@
44
work in solid-ui by adjusting where imported functions are found.
55
*/
66
import { IndexedFormula, NamedNode } from 'rdflib'
7-
import { icons } from '..'
7+
import { icons } from '../index'
88
import { authn } from 'solid-logic'
99
import { loginStatusBox } from '../login/login'
1010
// import { loginStatusBox, authSession, currentUser } from '../authn/authn'
1111
import * as widgets from '../widgets'
1212
import { emptyProfile } from './empty-profile'
13-
import { addStyleClassToElement, getPod, throttle } from './headerHelpers'
13+
import { addStyleClassToElement, getPod, throttle } from '../utils/headerFooterHelpers'
14+
15+
/**
16+
* menu icons
17+
*/
18+
const DEFAULT_HELP_MENU_ICON = icons.iconBase + 'noun_help.svg'
19+
const DEFAUL_SOLID_ICON_URL = 'https://solidproject.org/assets/img/solid-emblem.svg'
1420

1521
export type MenuItemLink = {
1622
label: string,
17-
url: string
23+
url: string,
24+
target?: string
1825
}
1926

2027
export type MenuItemButton = {
2128
label: string,
22-
onclick: () => {}
29+
onclick: () => void
2330
}
2431

2532
export type MenuItems = MenuItemLink | MenuItemButton
2633

2734
/*
28-
HeaderOptions allow for customizing the logo and menu list. If a logo is not provided the default
29-
is solid. Menulist will always show a link to logout and to the users profile.
35+
HeaderOptions allow for customizing the logo and menu list. If a logo is not provided the default
36+
is solid. Menulist will always show a link to logout and to the users profile.
3037
*/
3138
export type HeaderOptions = {
3239
logo?: string,
33-
menuList?: MenuItems[]
40+
helpIcon?: string,
41+
helpMenuList?: MenuItems[]
3442
}
3543

3644
/**
3745
* Initialize header component, the header object returned depends on whether the user is authenticated.
3846
* @param store the data store
39-
* @param options allow the header to be customized with a personalized logo and a menu list of links or buttons.
47+
* @param userMenuList a list of menu items when the user is logged in
48+
* @param options allow the header to be customized with a personalized logo, help icon and a help menu list of links or buttons.
4049
* @returns a header for an authenticated user with menu items given or a login screen
4150
*/
42-
export async function initHeader (store: IndexedFormula, options?: HeaderOptions) {
51+
export async function initHeader (store: IndexedFormula, userMenuList: MenuItems[], options?: HeaderOptions) {
4352
const header = document.getElementById('PageHeader')
4453
if (!header) {
4554
return
4655
}
4756

4857
const pod = getPod()
49-
rebuildHeader(header, store, pod, options)()
50-
authn.authSession.onLogout(rebuildHeader(header, store, pod, options))
51-
authn.authSession.onLogin(rebuildHeader(header, store, pod, options))
58+
rebuildHeader(header, store, pod, userMenuList, options)()
59+
authn.authSession.onLogout(rebuildHeader(header, store, pod, userMenuList, options))
60+
authn.authSession.onLogin(rebuildHeader(header, store, pod, userMenuList, options))
5261
}
5362
/**
5463
* @ignore exporting this only for the unit test
5564
*/
56-
export function rebuildHeader (header: HTMLElement, store: IndexedFormula, pod: NamedNode, options?: HeaderOptions) {
65+
export function rebuildHeader (header: HTMLElement, store: IndexedFormula, pod: NamedNode, userMenuList: MenuItems[], options?: HeaderOptions) {
5766
return async () => {
5867
const user = authn.currentUser()
5968
header.innerHTML = ''
60-
header.appendChild(await createBanner(store, pod, user, options))
69+
header.appendChild(await createBanner(store, pod, user, userMenuList, options))
6170
}
6271
}
6372
/**
6473
* @ignore exporting this only for the unit test
6574
*/
66-
export async function createBanner (store: IndexedFormula, pod: NamedNode, user: NamedNode | null, options?: HeaderOptions): Promise<HTMLElement> {
75+
export async function createBanner (store: IndexedFormula, pod: NamedNode, user: NamedNode | null, userMenuList: MenuItems[], options?: HeaderOptions): Promise<HTMLElement> {
6776
const podLink = document.createElement('a')
6877
podLink.href = pod.uri
6978
addStyleClassToElement(podLink, ['header-banner__link'])
7079
const image = document.createElement('img')
7180
if (options) {
72-
image.src = options.logo ? options.logo : 'https://solidproject.org/assets/img/solid-emblem.svg'
81+
image.src = options.logo ? options.logo : DEFAUL_SOLID_ICON_URL
7382
}
7483
addStyleClassToElement(image, ['header-banner__icon'])
7584
podLink.appendChild(image)
7685

7786
const userMenu = user
78-
? await createUserMenu(store, user, options)
87+
? await createUserMenu(store, user, userMenuList)
7988
: createLoginSignUpButtons()
8089

81-
const helpMenu = createHelpMenu()
82-
8390
const banner = document.createElement('div')
8491
addStyleClassToElement(banner, ['header-banner'])
8592
banner.appendChild(podLink)
8693

8794
const leftSideOfHeader = document.createElement('div')
8895
addStyleClassToElement(leftSideOfHeader, ['header-banner__right-menu'])
8996
leftSideOfHeader.appendChild(userMenu)
90-
leftSideOfHeader.appendChild(helpMenu)
97+
98+
if (options && options.helpMenuList) {
99+
const helpMenu = createHelpMenu(options, options.helpMenuList)
100+
leftSideOfHeader.appendChild(helpMenu as HTMLDivElement)
101+
}
91102

92103
banner.appendChild(leftSideOfHeader)
93104

@@ -96,20 +107,25 @@ export async function createBanner (store: IndexedFormula, pod: NamedNode, user:
96107
/**
97108
* @ignore exporting this only for the unit test
98109
*/
99-
export function createHelpMenu () {
110+
export function createHelpMenu (options: HeaderOptions, helpMenuItems: MenuItems[]) {
111+
if (!helpMenuItems) return
100112
const helpMenuList = document.createElement('ul')
101113
addStyleClassToElement(helpMenuList, ['header-user-menu__list'])
102-
helpMenuList.appendChild(createUserMenuItem(createUserMenuLink('User guide', 'https://github.com/solid/userguide', '_blank')))
103-
helpMenuList.appendChild(createUserMenuItem(createUserMenuLink('Report a problem', 'https://github.com/solid/solidos/issues', '_blank')))
114+
helpMenuItems.forEach(function (menuItem) {
115+
const menuItemType: string = (menuItem as MenuItemLink).url ? 'url' : 'onclick'
116+
if (menuItemType === 'url') {
117+
helpMenuList.appendChild(createUserMenuItem(createUserMenuLink(menuItem.label, (menuItem as MenuItemLink).url, (menuItem as MenuItemLink).target)))
118+
} else {
119+
helpMenuList.appendChild(createUserMenuItem(createUserMenuButton(menuItem.label, (menuItem as MenuItemButton).onclick)))
120+
}
121+
})
104122

105123
const helpMenu = document.createElement('nav')
106124

107125
addStyleClassToElement(helpMenu, ['header-user-menu__navigation-menu'])
108126
helpMenu.setAttribute('aria-hidden', 'true')
109127
helpMenu.appendChild(helpMenuList)
110128

111-
const helpIcon = icons.iconBase + 'noun_144.svg'
112-
113129
const helpMenuContainer = document.createElement('div')
114130
addStyleClassToElement(helpMenuContainer, ['header-banner__user-menu'])
115131
addStyleClassToElement(helpMenuContainer, ['header-user-menu'])
@@ -120,7 +136,7 @@ export function createHelpMenu () {
120136
helpMenuTrigger.type = 'button'
121137

122138
const helpMenuIcon = document.createElement('img')
123-
helpMenuIcon.src = helpIcon
139+
helpMenuIcon.src = (options && options.helpIcon) ? options.helpIcon : icons.iconBase + DEFAULT_HELP_MENU_ICON
124140
addStyleClassToElement(helpMenuIcon, ['header-banner__help-icon'])
125141
helpMenuContainer.appendChild(helpMenuTrigger)
126142
helpMenuTrigger.appendChild(helpMenuIcon)
@@ -160,7 +176,7 @@ export function createUserMenuButton (label: string, onClick: EventListenerOrEve
160176
/**
161177
* @ignore exporting this only for the unit test
162178
*/
163-
export function createUserMenuLink (label: string, href: string, target?:string): HTMLElement {
179+
export function createUserMenuLink (label: string, href: string, target?: string): HTMLElement {
164180
const link = document.createElement('a')
165181
addStyleClassToElement(link, ['header-user-menu__link'])
166182
link.href = href
@@ -172,30 +188,25 @@ export function createUserMenuLink (label: string, href: string, target?:string)
172188
/**
173189
* @ignore exporting this only for the unit test
174190
*/
175-
export async function createUserMenu (store: IndexedFormula, user: NamedNode, options?: HeaderOptions): Promise<HTMLElement> {
191+
export async function createUserMenu (store: IndexedFormula, user: NamedNode, userMenuList: MenuItems[]): Promise<HTMLElement> {
176192
const fetcher = (<any>store).fetcher
177193
if (fetcher) {
178194
// Making sure that Profile is loaded before building menu
179195
await fetcher.load(user)
180196
}
197+
181198
const loggedInMenuList = document.createElement('ul')
182199
addStyleClassToElement(loggedInMenuList, ['header-user-menu__list'])
183-
loggedInMenuList.appendChild(createUserMenuItem(createUserMenuLink('Show your profile', user.uri)))
184-
if (options) {
185-
if (options.menuList) {
186-
options.menuList.forEach(function (menuItem) {
187-
const menuItemType: string = (menuItem as MenuItemLink).url ? 'url' : 'onclick'
188-
if (menuItemType === 'url') {
189-
loggedInMenuList.appendChild(createUserMenuItem(createUserMenuLink(menuItem.label, menuItem[menuItemType])))
190-
} else {
191-
loggedInMenuList.appendChild(createUserMenuItem(createUserMenuButton(menuItem.label, menuItem[menuItemType])))
192-
}
193-
})
194-
}
200+
if (userMenuList) {
201+
userMenuList.forEach(function (menuItem) {
202+
const menuItemType: string = (menuItem as MenuItemLink).url ? 'url' : 'onclick'
203+
if (menuItemType === 'url') {
204+
loggedInMenuList.appendChild(createUserMenuItem(createUserMenuLink(menuItem.label, (menuItem as MenuItemLink).url, (menuItem as MenuItemLink).target)))
205+
} else {
206+
loggedInMenuList.appendChild(createUserMenuItem(createUserMenuButton(menuItem.label, (menuItem as MenuItemButton).onclick)))
207+
}
208+
})
195209
}
196-
197-
loggedInMenuList.appendChild(createUserMenuItem(createUserMenuButton('Log out', () => authn.authSession.logout())))
198-
199210
const loggedInMenu = document.createElement('nav')
200211

201212
addStyleClassToElement(loggedInMenu, ['header-user-menu__navigation-menu'])

src/header/styleMap.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,6 @@ export const styleMap = {
114114
width: '65px !important' // may just be 65px round($icon-size * 352 / 322);
115115
},
116116
'header-banner__help-icon': {
117-
backgroundSize: '55px 50px',
118-
height: '50px !important', // this is the icon size
119-
width: '55px !important' // may just be 65px round($icon-size * 352 / 430);
117+
width: '28px !important'
120118
}
121119
}

src/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ import * as utils from './utils'
7373
import * as widgets from './widgets/index'
7474
import versionInfo from './versionInfo'
7575
import { initHeader } from './header'
76+
import { initFooter } from './footer'
7677

7778
const dom = window ? window.document : null // Idea that UI.dom can be adapted in non-browser environments
7879
const store = solidLogicSingleton.store
@@ -104,7 +105,8 @@ if (typeof window !== 'undefined') {
104105
utils,
105106
widgets,
106107
versionInfo,
107-
initHeader
108+
initHeader,
109+
initFooter
108110
} // Simpler access by non-node scripts
109111
}
110112

@@ -134,5 +136,6 @@ export {
134136
utils,
135137
widgets,
136138
versionInfo,
137-
initHeader
139+
initHeader,
140+
initFooter
138141
}

0 commit comments

Comments
 (0)