Skip to content

Commit 18fd786

Browse files
committed
Merge branch 'main' into feat/table-styling
2 parents e8c0b81 + 63442ea commit 18fd786

File tree

8 files changed

+213
-9
lines changed

8 files changed

+213
-9
lines changed

browser-extension/src/lib/config.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ const MODES = ['PROD', 'PLAYGROUNDS_PR'] as const
22

33
export type ModeType = (typeof MODES)[number]
44

5+
const LOG_LEVELS = ['DEBUG', 'INFO', 'WARN', 'ERROR'] as const
6+
7+
export type LogLevel = (typeof LOG_LEVELS)[number]
8+
59
export const CONFIG = {
610
ADDED_OVERTYPE_CLASS: 'gitcasso-overtype',
7-
DEBUG: true, // enabled debug logging
811
EXTENSION_NAME: 'gitcasso', // decorates logs
12+
LOG_LEVEL: 'INFO' satisfies LogLevel,
913
MODE: 'PROD' satisfies ModeType,
1014
} as const
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import OverType, { type OverTypeInstance } from 'overtype'
2+
import type { CommentEnhancer, CommentSpot } from '../../enhancer'
3+
import { logger } from '../../logger'
4+
import { modifyDOM } from '../modifyDOM'
5+
import { githubHighlighter } from './githubHighlighter'
6+
7+
interface GitHubIssueNewCommentSpot extends CommentSpot {
8+
type: 'GH_ISSUE_NEW_COMMENT'
9+
domain: string
10+
slug: string // owner/repo
11+
}
12+
13+
export class GitHubIssueNewCommentEnhancer implements CommentEnhancer<GitHubIssueNewCommentSpot> {
14+
forSpotTypes(): string[] {
15+
return ['GH_ISSUE_NEW_COMMENT']
16+
}
17+
18+
tryToEnhance(_textarea: HTMLTextAreaElement): GitHubIssueNewCommentSpot | null {
19+
if (document.querySelector('meta[name="hostname"]')?.getAttribute('content') !== 'github.com') {
20+
return null
21+
}
22+
23+
// Parse GitHub URL structure: /owner/repo/issues/123 or /owner/repo/pull/456
24+
logger.debug(`${this.constructor.name} examing url`, window.location.pathname)
25+
26+
const match = window.location.pathname.match(/^\/([^/]+)\/([^/]+)(?:\/issues\/new)/)
27+
logger.debug(`${this.constructor.name} found match`, window.location.pathname)
28+
29+
if (!match) return null
30+
const [, owner, repo] = match
31+
const slug = `${owner}/${repo}`
32+
const unique_key = `github.com:${slug}:new`
33+
return {
34+
domain: 'github.com',
35+
slug,
36+
type: 'GH_ISSUE_NEW_COMMENT',
37+
unique_key,
38+
}
39+
}
40+
41+
prepareForFirstEnhancement(): void {
42+
OverType.setCodeHighlighter(githubHighlighter)
43+
}
44+
45+
enhance(textArea: HTMLTextAreaElement, _spot: GitHubIssueNewCommentSpot): OverTypeInstance {
46+
const overtypeContainer = modifyDOM(textArea)
47+
return new OverType(overtypeContainer, {
48+
autoResize: true,
49+
minHeight: '400px',
50+
padding: 'var(--base-size-16)',
51+
placeholder: 'Type your description here...',
52+
})[0]!
53+
}
54+
55+
tableTitle(spot: GitHubIssueNewCommentSpot): string {
56+
const { slug } = spot
57+
return `${slug} New Issue`
58+
}
59+
60+
tableIcon(_: GitHubIssueNewCommentSpot): string {
61+
return '🔄' // PR icon TODO: icon urls in /public
62+
}
63+
64+
buildUrl(spot: GitHubIssueNewCommentSpot): string {
65+
return `https://${spot.domain}/${spot.slug}/issue/new`
66+
}
67+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import OverType, { type OverTypeInstance } from 'overtype'
2+
import type { CommentEnhancer, CommentSpot } from '../../enhancer'
3+
import { logger } from '../../logger'
4+
import { modifyDOM } from '../modifyDOM'
5+
import { githubHighlighter } from './githubHighlighter'
6+
7+
interface GitHubPRNewCommentSpot extends CommentSpot {
8+
type: 'GH_PR_NEW_COMMENT'
9+
domain: string
10+
slug: string // owner/repo/base-branch/compare-branch
11+
}
12+
13+
export class GitHubPRNewCommentEnhancer implements CommentEnhancer<GitHubPRNewCommentSpot> {
14+
forSpotTypes(): string[] {
15+
return ['GH_PR_NEW_COMMENT']
16+
}
17+
18+
tryToEnhance(_textarea: HTMLTextAreaElement): GitHubPRNewCommentSpot | null {
19+
if (document.querySelector('meta[name="hostname"]')?.getAttribute('content') !== 'github.com') {
20+
return null
21+
}
22+
23+
// /owner/repo/compare/feature/more-enhancers?expand=1
24+
// or /owner/repo/compare/feat/issue-static-and-dynamic...feature/more-enhancers?expand=1
25+
logger.info(`${this.constructor.name} examing url`, window.location.pathname)
26+
27+
const match = window.location.pathname.match(
28+
/^\/([^/]+)\/([^/]+)\/compare\/(?:([^.?]+)\.\.\.)?([^?]+)/,
29+
)
30+
logger.info(`${this.constructor.name} found match`, window.location.pathname, match)
31+
32+
if (!match) return null
33+
const [, owner, repo, baseBranch, compareBranch] = match
34+
const slug = baseBranch
35+
? `${owner}/${repo}/${baseBranch}...${compareBranch}`
36+
: `${owner}/${repo}/${compareBranch}`
37+
const unique_key = `github.com:${slug}`
38+
return {
39+
domain: 'github.com',
40+
slug,
41+
type: 'GH_PR_NEW_COMMENT',
42+
unique_key,
43+
}
44+
}
45+
46+
prepareForFirstEnhancement(): void {
47+
OverType.setCodeHighlighter(githubHighlighter)
48+
}
49+
50+
enhance(textArea: HTMLTextAreaElement, _spot: GitHubPRNewCommentSpot): OverTypeInstance {
51+
const overtypeContainer = modifyDOM(textArea)
52+
return new OverType(overtypeContainer, {
53+
autoResize: true,
54+
minHeight: '250px',
55+
padding: 'var(--base-size-16)',
56+
placeholder: 'Type your description here...',
57+
})[0]!
58+
}
59+
60+
tableTitle(spot: GitHubPRNewCommentSpot): string {
61+
const { slug } = spot
62+
return `${slug} New Issue`
63+
}
64+
65+
tableIcon(_: GitHubPRNewCommentSpot): string {
66+
return '🔄' // PR icon TODO: icon urls in /public
67+
}
68+
69+
buildUrl(spot: GitHubPRNewCommentSpot): string {
70+
return `https://${spot.domain}/${spot.slug}/issue/new`
71+
}
72+
}

browser-extension/src/lib/enhancers/modifyDOM.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,23 @@ export function modifyDOM(overtypeInput: HTMLTextAreaElement): HTMLElement {
2626
attributes: true,
2727
})
2828

29+
// Find the button that contains the text "Preview"
30+
const writePreviewTabs = Array.from(
31+
(overtypeContainer.firstElementChild as HTMLElement).querySelectorAll('button'),
32+
)
33+
const writeTab = writePreviewTabs.find((button) => button.textContent.includes('Write'))
34+
const previewTab = writePreviewTabs.find((button) => button.textContent.includes('Preview'))
35+
36+
if (writeTab && previewTab) {
37+
// Hide the textarea when the user is on the "Preview" tab
38+
writeTab.addEventListener('click', () => {
39+
overtypeWrapper.style.display = 'inline-block'
40+
})
41+
42+
previewTab.addEventListener('click', () => {
43+
overtypeWrapper.style.display = 'none'
44+
})
45+
}
46+
2947
return overtypeContainer.parentElement!.closest('div')!
3048
}
Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CONFIG } from './config'
1+
import { CONFIG, type LogLevel } from './config'
22

33
/**
44
* Simple logging utilities for the extension
@@ -9,12 +9,25 @@ const prefix = `[${CONFIG.EXTENSION_NAME}]`
99
// No-op function for disabled logging
1010
const noop = () => {}
1111

12+
// Log level hierarchy - index represents priority
13+
const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
14+
DEBUG: 0,
15+
ERROR: 3,
16+
INFO: 1,
17+
WARN: 2,
18+
}
19+
20+
// Helper function to check if a log level is enabled
21+
const shouldLog = (level: LogLevel): boolean => {
22+
return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[CONFIG.LOG_LEVEL]
23+
}
24+
1225
// Export simple logging functions
1326
export const logger = {
14-
debug: CONFIG.DEBUG ? console.log.bind(console, prefix) : noop,
15-
error: console.error.bind(console, prefix),
16-
info: CONFIG.DEBUG ? console.log.bind(console, prefix) : noop,
17-
time: CONFIG.DEBUG ? console.time.bind(console) : noop,
18-
timeEnd: CONFIG.DEBUG ? console.timeEnd.bind(console) : noop,
19-
warn: console.warn.bind(console, prefix),
27+
debug: shouldLog('DEBUG') ? console.log.bind(console, prefix) : noop,
28+
error: shouldLog('ERROR') ? console.error.bind(console, prefix) : noop,
29+
info: shouldLog('INFO') ? console.log.bind(console, prefix) : noop,
30+
time: shouldLog('INFO') ? console.time.bind(console) : noop,
31+
timeEnd: shouldLog('INFO') ? console.timeEnd.bind(console) : noop,
32+
warn: shouldLog('WARN') ? console.warn.bind(console, prefix) : noop,
2033
}

browser-extension/src/lib/registries.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import type { OverTypeInstance } from 'overtype'
22
import OverType from 'overtype'
33
import type { CommentEnhancer, CommentSpot } from './enhancer'
44
import { GitHubIssueAddCommentEnhancer } from './enhancers/github/githubIssueAddComment'
5+
import { GitHubIssueNewCommentEnhancer } from './enhancers/github/githubIssueNewComment'
56
import { GitHubPRAddCommentEnhancer } from './enhancers/github/githubPRAddComment'
7+
import { GitHubPRNewCommentEnhancer } from './enhancers/github/githubPRNewComment'
68

79
export interface EnhancedTextarea<T extends CommentSpot = CommentSpot> {
810
textarea: HTMLTextAreaElement
@@ -19,7 +21,9 @@ export class EnhancerRegistry {
1921
constructor() {
2022
// Register all available handlers
2123
this.register(new GitHubIssueAddCommentEnhancer())
24+
this.register(new GitHubIssueNewCommentEnhancer())
2225
this.register(new GitHubPRAddCommentEnhancer())
26+
this.register(new GitHubPRNewCommentEnhancer())
2327
const textColor = 'rgb(31, 35, 40)'
2428
const headingColor = 'rgb(174, 52, 151)'
2529
OverType.setTheme({

browser-extension/tests/har-fixture.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export { expect }
4141
export function usingHar(harKey: keyof typeof PAGES) {
4242
return {
4343
it: (name: string, fn: () => void | Promise<void>) => {
44-
return baseTest(name, async () => {
44+
return baseTest(`${harKey}:${name}`, async () => {
4545
// Setup HAR DOM before test
4646
await setupHarDOM(harKey)
4747

browser-extension/tests/lib/enhancers/github.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ describe('github', () => {
3838
</span>
3939
`)
4040
})
41+
usingHar('gh_new_pr').it('should create the correct spot object', async () => {
42+
const enhancers = new EnhancerRegistry()
43+
const textareas = document.querySelectorAll('textarea')
44+
expect(textareas.length).toBe(2)
45+
expect(enhancers.tryToEnhance(textareas[0]!)?.spot).toMatchInlineSnapshot(`
46+
{
47+
"domain": "github.com",
48+
"slug": "diffplug/selfie/main...cavia-porcellus:selfie:main",
49+
"type": "GH_PR_NEW_COMMENT",
50+
"unique_key": "github.com:diffplug/selfie/main...cavia-porcellus:selfie:main",
51+
}
52+
`)
53+
})
4154
usingHar('gh_issue').it('should create the correct spot object', async () => {
4255
const enhancers = new EnhancerRegistry()
4356
const textareas = document.querySelectorAll('textarea')
@@ -70,4 +83,17 @@ describe('github', () => {
7083
</span>
7184
`)
7285
})
86+
usingHar('gh_new_issue').it('should create the correct spot object', async () => {
87+
const enhancers = new EnhancerRegistry()
88+
const textareas = document.querySelectorAll('textarea')
89+
expect(textareas.length).toBe(1)
90+
expect(enhancers.tryToEnhance(textareas[0]!)?.spot).toMatchInlineSnapshot(`
91+
{
92+
"domain": "github.com",
93+
"slug": "diffplug/selfie",
94+
"type": "GH_ISSUE_NEW_COMMENT",
95+
"unique_key": "github.com:diffplug/selfie:new",
96+
}
97+
`)
98+
})
7399
})

0 commit comments

Comments
 (0)