Skip to content

Commit 7b30df7

Browse files
authored
Fix Linear icons & add support for integration to define Pages functions (GitbookIO#95)
* Add ability for integration to upload Pages functions * Add Pages function to generate status svg icon * Update integration code to use new icons and status icon function * Remove unessary status assets
1 parent b81ac52 commit 7b30df7

37 files changed

+247
-41
lines changed

.gitignore

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
22

3-
# Cloudflare pages assets folder
4-
dist/
3+
# Cloudflare pages assets & functions folder
4+
/dist/
5+
/functions
56

67
# dependencies
78
node_modules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const VALID_STATUS_TYPES = ['backlog', 'unstarted', 'started', 'completed', 'canceled'];
2+
3+
export async function onRequestGet({ request, params, env }) {
4+
const statusType = params.type;
5+
6+
if (!VALID_STATUS_TYPES.includes(statusType)) {
7+
return new Response(`Invalid status type ${statusType}`, {
8+
status: 400,
9+
});
10+
}
11+
12+
const origReqURL = new URL(request.url);
13+
const query = origReqURL.searchParams;
14+
15+
const fillColor = query.get('fill');
16+
const strokeColor = query.get('stroke');
17+
18+
const statusAssetURL = origReqURL;
19+
statusAssetURL.search = '';
20+
statusAssetURL.pathname = `/linear/status-${statusType}.svg`;
21+
22+
// Fetch the SVG corresponding to the status type
23+
let statusAssetResponse: Response;
24+
try {
25+
statusAssetResponse = await env.ASSETS.fetch(statusAssetURL);
26+
} catch (error) {
27+
return new Response(`Error while fetching the status asset.`, {
28+
status: 500,
29+
});
30+
}
31+
32+
return new HTMLRewriter()
33+
.on('svg > path', {
34+
element(element) {
35+
if (fillColor) {
36+
element.setAttribute('fill', `#${fillColor}`);
37+
}
38+
39+
if (strokeColor) {
40+
element.setAttribute('stroke', `#${strokeColor}`);
41+
}
42+
},
43+
})
44+
.transform(statusAssetResponse);
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"target": "ES2020",
4+
"module": "CommonJS",
5+
"lib": ["ES2020"],
6+
"types": ["@cloudflare/workers-types"]
7+
}
8+
}
Loading
Loading
-203 Bytes
Binary file not shown.
Loading
Loading
-227 Bytes
Binary file not shown.
Loading
Loading
-225 Bytes
Binary file not shown.
Loading
Loading
-236 Bytes
Binary file not shown.
Loading
Loading
-281 Bytes
Binary file not shown.
-423 Bytes
Binary file not shown.
Loading
-439 Bytes
Binary file not shown.
Loading
Loading
-408 Bytes
Binary file not shown.
-501 Bytes
Binary file not shown.
-547 Bytes
Binary file not shown.
Loading
-402 Bytes
Binary file not shown.
Loading
Loading
Loading
Loading
-561 Bytes
Binary file not shown.

integrations/linear/src/index.tsx

+27-14
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,31 @@ function renderGenericCard(url: string, context: LinearRuntimeContext): ContentK
3333
}
3434

3535
/**
36-
*
36+
* Get the issue icons based on the issue details.
3737
*/
38-
function getIssueIconsURLs(context: LinearRuntimeContext, status: string, priority: string) {
39-
const statusIcon = `status-${status.toLowerCase().replaceAll(' ', '-')}.png`;
40-
const priorityIcon = `priority-${priority.toLocaleLowerCase().replaceAll(' ', '-')}.png`;
38+
function getIssueIconsURLs(
39+
context: LinearRuntimeContext,
40+
issueQueryResponse: IssueQuery,
41+
theme: string
42+
) {
43+
const { issue } = issueQueryResponse;
44+
const { state, priorityLabel: priority } = issue;
45+
46+
const assetsBaseURL = context.environment.integration.urls.assets;
47+
const statusIconURL = new URL(`${assetsBaseURL}/status/${state.type}`);
48+
statusIconURL.searchParams.set('fill', state.color.replace('#', ''));
49+
statusIconURL.searchParams.set('theme', theme);
50+
51+
const priorityIcon = `priority-${priority
52+
.toLocaleLowerCase()
53+
.replaceAll(' ', '-')}-${theme}.svg`;
4154

4255
return {
43-
status: `${context.environment.integration.urls.assets}/${statusIcon}`,
44-
priority: `${context.environment.integration.urls.assets}/${priorityIcon}`,
45-
unassigned: `${context.environment.integration.urls.assets}/unassigned.png`,
56+
status: statusIconURL.toString(),
57+
priority: `${assetsBaseURL}/${priorityIcon}`,
58+
assignee: issue.assignee
59+
? issue.assignee.avatarUrl
60+
: `${assetsBaseURL}/unassigned-${theme}.svg`,
4661
};
4762
}
4863

@@ -96,9 +111,9 @@ const embedBlock = createComponent<{
96111
return renderGenericCard(element.props.url, context);
97112
}
98113

114+
const icons = getIssueIconsURLs(context, response, element.context.theme);
115+
99116
const { issue } = response;
100-
const icons = getIssueIconsURLs(context, issue.state.name, issue.priorityLabel);
101-
// TODO: add images with Linear icons once we've added build script to publish public assets to Cloudflare
102117
const hint = [
103118
<image source={{ url: icons.priority }} aspectRatio={1} />,
104119
<text>{issueId}</text>,
@@ -203,19 +218,17 @@ const previewModal = createComponent<{
203218
return renderGenericModal(element.props.url, context);
204219
}
205220

221+
const icons = getIssueIconsURLs(context, response, element.context.theme);
206222
const { issue } = response;
207-
const icons = getIssueIconsURLs(context, issue.state.name, issue.priorityLabel);
223+
208224
const subtitle = [
209225
<image source={{ url: icons.priority }} aspectRatio={1} />,
210226
<text>{issueId}</text>,
211227
<text></text>,
212228
<image source={{ url: icons.status }} aspectRatio={1} />,
213229
<text>{issue.state.name}</text>,
214230
<text></text>,
215-
<image
216-
source={{ url: issue.assignee ? issue.assignee.avatarUrl : icons.unassigned }}
217-
aspectRatio={1}
218-
/>,
231+
<image source={{ url: icons.assignee }} aspectRatio={1} />,
219232
<text>
220233
{issue.assignee ? `Assigned to ${issue.assignee.displayName}` : 'Unassigned'}
221234
</text>,

integrations/linear/src/linear/operations.graphql

+3-1
Original file line numberDiff line numberDiff line change
@@ -952,8 +952,10 @@ fragment Issue on Issue {
952952
}
953953
# The workflow state that the issue is associated with.
954954
state {
955-
id
955+
type
956956
name
957+
color
958+
position
957959
}
958960
}
959961

integrations/linear/tsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"extends": "@gitbook/tsconfig/integration.json"
2+
"extends": "@gitbook/tsconfig/integration.json",
3+
"exclude": ["public/functions/**/*"]
34
}

0 commit comments

Comments
 (0)