Skip to content

Commit 0ae25b1

Browse files
committed
additional refactor and fix tests
1 parent f6fdceb commit 0ae25b1

10 files changed

Lines changed: 110 additions & 128 deletions

File tree

src/StatusSection.css

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,46 @@
66

77
.sourcePaneStatus[data-visible='true'] {
88
display: block;
9+
margin: 0;
10+
padding: 12px;
11+
background: var(--dialog-error-background, var(--pink-500, #ffdde6));
12+
border-radius: 5px;
13+
border: 1px solid var(--dialog-error-border, var(--pink-700, #ff98b3));
14+
}
15+
16+
#statusMessageArea {
17+
display: flex;
18+
align-items: center;
19+
gap: 6px;
920
}
1021

1122
.error-text {
1223
margin: 0;
13-
padding: 12px;
14-
background-color: #fde8e8;
15-
border: 1px solid #f8b4b4;
16-
border-radius: 4px;
17-
color: #9b1c1c;
24+
padding: 10px 12px;
25+
background-color: transparent;
26+
border: 0;
27+
border-radius: 0;
28+
color: var(--solid-ui-color-error, #b00020);
1829
font-weight: 500;
30+
flex: 1;
31+
}
32+
33+
.statusCloseButton {
34+
flex: 0 0 auto;
35+
margin-top: 0;
36+
align-self: center;
37+
width: 28px;
38+
height: 28px;
39+
border: 0;
40+
border-radius: 5px;
41+
background: transparent;
42+
color: var(--solid-ui-color-error, #b00020);
43+
font-weight: 600;
44+
line-height: 1;
45+
padding: 0;
46+
cursor: pointer;
47+
}
48+
49+
.statusCloseButton:hover {
50+
background: color-mix(in srgb, var(--solid-ui-color-error, #b00020) 10%, transparent);
1951
}

src/StatusSection.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export function getStatusSection(){
3939
<section class="sourcePaneStatus" role="alert" data-visible="false">
4040
<div id="statusMessageArea" hidden>
4141
<p class="error-text">${statusMessage}</p>
42-
<button @click=${() => clearError()}>X</button>
42+
<button class="statusCloseButton" aria-label="Dismiss error" @click=${() => clearError()}>X</button>
4343
</div>
4444
</section>
4545
`

src/components/source-editor-card/SourceEditorCard.styles.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
flex-direction: column;
99
width: 100%;
1010
align-items: stretch;
11-
padding: 0px 40px;
11+
padding: 0 40px;
1212
}
1313

1414
.sourcePaneEditor {

src/components/source-editor-card/SourceEditorCard.ts

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -185,29 +185,39 @@ export default class SourceEditorCard extends WebComponent {
185185
}
186186
}
187187
}
188-
189-
render() {
188+
189+
private renderFooter() {
190190
const sourceContext = this._requireSourceContext()
191-
const sectionClass = this._editorReady ? 'sourcePaneCard' : 'sourcePaneCard sourcePaneCardLoading'
192191
const compactContentType = sourceContext.editorMetadata.contentType?.split(';')[0]
193192
const showPrettyButton = !sourceContext.sourcePaneState.editing && !!compactContentType && compactable[compactContentType]
194-
const prettyButton = showPrettyButton
195-
? html`
193+
194+
if (sourceContext.sourcePaneState.editing) {
195+
return html`
196+
<div class="sourcePaneEditorFooter">
197+
<solid-ui-button class="sourcePaneCancelButton" variant="secondary" @click=${this.cancelHandler}>Cancel</solid-ui-button>
198+
<solid-ui-button class="sourcePaneSaveButton" variant="primary" @click=${this.saveBack}>Save Changes</solid-ui-button>
199+
</div>
200+
`
201+
}
202+
203+
if (showPrettyButton) {
204+
return html`
205+
<div class="sourcePaneEditorFooter">
196206
<solid-ui-button class="sourcePanePrettyButton" variant="secondary" @click=${this.prettyHandler}>Prettify</solid-ui-button>
197-
`
198-
: nothing
207+
</div>
208+
`
209+
}
210+
211+
return nothing
212+
}
213+
214+
render() {
215+
const sectionClass = this._editorReady ? 'sourcePaneCard' : 'sourcePaneCard sourcePaneCardLoading'
199216

200217
return html`
201218
<section class=${sectionClass}>
202219
<div class="sourcePaneEditor"></div>
203-
<div class="sourcePaneEditorFooter">
204-
${sourceContext.sourcePaneState.editing
205-
? html`
206-
<solid-ui-button class="sourcePaneCancelButton" variant="secondary" @click=${this.cancelHandler}>Cancel</solid-ui-button>
207-
<solid-ui-button class="sourcePaneSaveButton" variant="primary" @click=${this.saveBack}>Save Changes</solid-ui-button>
208-
`
209-
: prettyButton}
210-
</div>
220+
${this.renderFooter()}
211221
</section>
212222
`
213223
}

src/components/source-provider/SourceProvider.styles.css

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
width: 100%;
55
align-self: stretch;
66
box-sizing: border-box;
7-
gap: 23px;
87
padding-bottom: 39px;
98
}
9+
10+
source-pane-source-header {
11+
margin-bottom: 23px;
12+
}

src/components/source-provider/SourceProvider.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,16 +173,13 @@ export default class SourceProvider extends WebComponent {
173173
}
174174

175175
render() {
176-
const { renderStatusSection } = getStatusSection()
177-
178176
return html`
179177
${this.dataLoaded
180178
? html`
181179
<source-pane-source-header></source-pane-source-header>
182180
<source-pane-source-editor-card></source-pane-source-editor-card>
183181
`
184182
: html``}
185-
${renderStatusSection()}
186183
`
187184
}
188185
}

src/icons/sourcePaneIcon.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { html } from "lit";
1+
import { html } from 'lit'
22

33
export const sourcePaneIcon = html`
44
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 26 26" fill="none">

src/sourcePane.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { DataBrowserContext, NewPaneOptions } from 'pane-registry'
99
import * as mime from 'mime-types'
1010
import { html, render as litRender } from 'lit'
1111
import { log } from './debug'
12+
import { getStatusSection } from './StatusSection'
1213
import './sourcePane.css'
1314
import './components/source-provider/SourceProvider'
1415

@@ -83,7 +84,7 @@ const pane = {
8384
},
8485

8586
render: function (subject: NamedNode, context: DataBrowserContext) {
86-
87+
const { renderStatusSection } = getStatusSection()
8788
const sourcePane = context.dom.createElement('div')
8889
sourcePane.setAttribute('class', 'sourcePane')
8990
litRender(html`
@@ -92,6 +93,7 @@ const pane = {
9293
.subject=${subject}
9394
>
9495
</source-pane-source-provider>
96+
${renderStatusSection()}
9597
`, sourcePane)
9698

9799
return sourcePane

test/helpers.test.js

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { beforeEach, describe, expect, it, vi } from 'vitest'
22

3-
import { fetchContentAndMetadata, getResponseHeaders } from '../src/resourceMetadata.ts'
3+
import { fetchContentAndMetadata, getResponseMetadata } from '../src/resourceLoader.ts'
44

5-
describe('helpers', () => {
5+
describe('resourceLoader', () => {
66
beforeEach(() => {
77
vi.clearAllMocks()
88
})
@@ -12,19 +12,27 @@ describe('helpers', () => {
1212
headers: {
1313
get: vi.fn((name) => {
1414
if (name === 'content-type') return 'text/turtle; charset=utf-8'
15-
if (name === 'allow') return 'GET,PUT'
15+
if (name === 'wac-allow') return 'user="write", public="read"'
1616
if (name === 'etag') return '"abc"'
1717
return null
1818
})
1919
}
2020
}
21-
const store = { each: vi.fn(), any: vi.fn(), anyValue: vi.fn(), sym: vi.fn() }
21+
const store = {
22+
each: vi.fn(),
23+
any: vi.fn(),
24+
anyValue: vi.fn(() => undefined),
25+
sym: vi.fn()
26+
}
2227
const subject = { uri: 'https://example.org/profile/card' }
2328

24-
expect(getResponseHeaders(store, subject, response)).toEqual({
29+
expect(getResponseMetadata(store, subject, response)).toEqual({
2530
contentType: 'text/turtle',
26-
allowed: 'GET,PUT',
31+
canEdit: true,
32+
isPublic: true,
2733
eTag: '"abc"'
34+
,
35+
modified: undefined
2836
})
2937
})
3038

@@ -34,7 +42,7 @@ describe('helpers', () => {
3442
headers: {
3543
get: vi.fn((name) => {
3644
if (name === 'content-type') return 'text/turtle'
37-
if (name === 'allow') return 'GET,PUT'
45+
if (name === 'wac-allow') return 'user="write", public="read"'
3846
if (name === 'etag') return '"abc"'
3947
return null
4048
})
@@ -47,27 +55,22 @@ describe('helpers', () => {
4755
},
4856
each: vi.fn(),
4957
any: vi.fn(),
50-
anyValue: vi.fn(),
58+
anyValue: vi.fn(() => undefined),
5159
sym: vi.fn()
5260
}
5361
const subject = { uri: 'https://example.org/profile/card' }
54-
const sourcePaneState = { broken: false, contentType: undefined, allowed: undefined, eTag: undefined }
5562

56-
const result = await fetchContentAndMetadata(store, subject, sourcePaneState)
63+
const result = await fetchContentAndMetadata(store, subject)
5764

5865
expect(result).toEqual({
5966
content: '<> a <#Thing>.',
6067
metadata: {
6168
contentType: 'text/turtle',
62-
allowed: 'GET,PUT',
63-
eTag: '"abc"'
69+
canEdit: true,
70+
isPublic: true,
71+
eTag: '"abc"',
72+
modified: undefined
6473
}
6574
})
66-
expect(sourcePaneState).toEqual({
67-
broken: false,
68-
contentType: 'text/turtle',
69-
allowed: 'GET,PUT',
70-
eTag: '"abc"'
71-
})
7275
})
7376
})

test/sourcePane.test.js

Lines changed: 17 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,27 @@
1-
import { render } from 'lit'
21
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
32

4-
let renderHeader
3+
let sourcePane
54

65
beforeAll(async () => {
7-
class MockSourceEditorCard extends HTMLElement {
8-
constructor () {
9-
super()
10-
this.updateEditingState = vi.fn()
11-
this.setReadOnly = vi.fn()
12-
this.focusEditor = vi.fn()
13-
}
14-
}
15-
16-
if (!globalThis.customElements.get('source-pane-source-editor-card')) {
17-
globalThis.customElements.define('source-pane-source-editor-card', MockSourceEditorCard)
18-
}
19-
20-
const headerModule = await import('../src/Header.ts')
21-
renderHeader = headerModule.renderHeader
22-
6+
await import('../src/components/source-provider/SourceProvider.ts')
237
await import('../src/components/header/SourceHeader.ts')
8+
sourcePane = (await import('../src/sourcePane.ts')).default
9+
2410
})
2511

26-
function renderHeaderIntoDocument (sourcePaneState) {
12+
function renderPaneIntoDocument () {
2713
const container = document.createElement('div')
2814
document.body.appendChild(container)
2915

3016
const store = { findTypeURIs: vi.fn(() => ({})) }
3117
const subject = { uri: 'https://janedoe.example/test.ttl' }
32-
render(renderHeader(store, subject, sourcePaneState), container)
33-
34-
return { container, subject, store }
18+
const context = {
19+
dom: document,
20+
session: { store }
21+
}
22+
const rendered = sourcePane.render(subject, context)
23+
container.appendChild(rendered)
24+
return { container, subject, store, rendered }
3525
}
3626

3727
describe('source-pane', () => {
@@ -40,67 +30,12 @@ describe('source-pane', () => {
4030
vi.clearAllMocks()
4131
})
4232

43-
it('renders the header edit control', async () => {
44-
const sourcePaneState = {
45-
broken: false,
46-
editing: false,
47-
readonly: false,
48-
allowed: undefined,
49-
contentType: undefined,
50-
eTag: undefined
51-
}
52-
53-
const { container } = renderHeaderIntoDocument(sourcePaneState)
54-
await Promise.resolve()
55-
56-
expect(container.querySelector('header.sourcePaneHeader')).not.toBeNull()
57-
expect(container.querySelector('.sourcePaneEditButton')).not.toBeNull()
58-
})
59-
60-
it('activates the editor when edit is clicked', async () => {
61-
const sourcePaneState = {
62-
broken: false,
63-
editing: false,
64-
readonly: false,
65-
allowed: undefined,
66-
contentType: undefined,
67-
eTag: undefined
68-
}
69-
70-
const { container } = renderHeaderIntoDocument(sourcePaneState)
71-
const editorCard = document.createElement('source-pane-source-editor-card')
72-
document.body.appendChild(editorCard)
73-
33+
it('renders the source provider wrapper', async () => {
34+
const { rendered } = renderPaneIntoDocument()
7435
await Promise.resolve()
75-
container.querySelector('.sourcePaneEditButton').click()
76-
77-
expect(editorCard.updateEditingState).toHaveBeenCalledWith(true)
78-
expect(editorCard.setReadOnly).toHaveBeenCalledWith(false)
79-
expect(editorCard.focusEditor).toHaveBeenCalled()
80-
})
81-
82-
it('opens the editor card from the migrated header even without setEditing', async () => {
83-
const header = document.createElement('source-pane-source-header')
84-
Object.defineProperty(header, 'sourceContext', {
85-
value: {
86-
sourcePaneState: {
87-
broken: false
88-
}
89-
},
90-
writable: true
91-
})
92-
93-
const editorCard = document.createElement('source-pane-source-editor-card')
94-
document.body.appendChild(header)
95-
document.body.appendChild(editorCard)
96-
97-
await header.updateComplete
98-
await Promise.resolve()
99-
100-
header.shadowRoot.querySelectorAll('solid-ui-button')[1].click()
10136

102-
expect(editorCard.updateEditingState).toHaveBeenCalledWith(true)
103-
expect(editorCard.setReadOnly).toHaveBeenCalledWith(false)
104-
expect(editorCard.focusEditor).toHaveBeenCalled()
37+
expect(rendered).not.toBeNull()
38+
expect(rendered.className).toBe('sourcePane')
39+
expect(rendered.getAttribute('class')).toBe('sourcePane')
10540
})
10641
})

0 commit comments

Comments
 (0)