Skip to content

Commit

Permalink
Better fix image rendering in Jira Cloud tickets' description and com…
Browse files Browse the repository at this point in the history
…ments (#105)

* better fix for images

* fix typo
  • Loading branch information
marcomura authored Feb 12, 2025
1 parent c8b2dc7 commit bd34c1b
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 200 deletions.
4 changes: 0 additions & 4 deletions src/ipc/prActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,3 @@ export interface GetImageAction extends Action {
action: 'getImage';
url: string;
}

export function isGetImage(a: Action): a is GetImageAction {
return (<GetImageAction>a).action === 'getImage';
}
8 changes: 8 additions & 0 deletions src/lib/ipc/fromUI/startWork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ export enum StartWorkActionType {
ClosePage = 'closePage',
StartRequest = 'startRequest',
OpenSettings = 'openSettings',
GetImage = 'getImage',
}

export type StartWorkAction =
| ReducerAction<StartWorkActionType.ClosePage, {}>
| ReducerAction<StartWorkActionType.StartRequest, StartRequestAction>
| ReducerAction<StartWorkActionType.OpenSettings, OpenSettingsAction>
| ReducerAction<StartWorkActionType.GetImage, GetImageAction>
| CommonAction;

export interface StartRequestAction {
Expand All @@ -31,3 +33,9 @@ export interface OpenSettingsAction {
section?: ConfigSection;
subsection?: ConfigSubSection;
}

export interface GetImageAction {
nonce: string;
url: string;
siteDetailsStringified: string;
}
45 changes: 45 additions & 0 deletions src/lib/webview/controller/startwork/startWorkWebviewController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { CommonActionType } from '../../../ipc/fromUI/common';
import { StartWorkAction, StartWorkActionType } from '../../../ipc/fromUI/startWork';
import { WebViewID } from '../../../ipc/models/common';
import { CommonMessage, CommonMessageType } from '../../../ipc/toUI/common';
// eslint-disable-next-line no-restricted-imports
import { Container } from '../../../../container';
import {
BranchType,
emptyStartWorkIssueMessage,
Expand Down Expand Up @@ -158,6 +160,49 @@ export class StartWorkWebviewController implements WebviewController<StartWorkIs
this.api.openSettings(msg.section, msg.subsection);
break;
}
case StartWorkActionType.GetImage: {
try {
const siteDetails = JSON.parse(msg.siteDetailsStringified);
const baseApiUrl = new URL(
siteDetails.baseApiUrl.slice(0, siteDetails.baseApiUrl.lastIndexOf('/rest')),
);
// Prefix base URL for a relative URL
const href = msg.url.startsWith('/') ? new URL(baseApiUrl.href + msg.url) : new URL(msg.url);
// Skip fetching external images (that do not belong to the site)
if (href.hostname !== baseApiUrl.hostname) {
this.postMessage({
type: 'getImageDone',
imgData: '',
nonce: msg.nonce,
} as any);
}

const url = href.toString();

const client = await Container.clientManager.jiraClient(siteDetails);
const response = await client.transportFactory().get(url, {
method: 'GET',
headers: {
Authorization: await client.authorizationProvider('GET', url),
},
responseType: 'arraybuffer',
});
const imgData = Buffer.from(response.data, 'binary').toString('base64');
this.postMessage({
type: 'getImageDone',
imgData: imgData,
nonce: msg.nonce,
} as any);
} catch (e) {
this.logger.error(new Error(`error fetching image: ${msg.url}`));
this.postMessage({
type: 'getImageDone',
imgData: '',
nonce: msg.nonce,
} as any);
}
break;
}
case CommonActionType.Refresh: {
try {
await this.invalidate();
Expand Down
42 changes: 38 additions & 4 deletions src/react/atlascode/startwork/StartWorkPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ import { PrepareCommitTip } from '../common/PrepareCommitTip';
import { StartWorkControllerContext, useStartWorkController } from './startWorkController';
import { AtlascodeErrorBoundary } from '../common/ErrorBoundary';
import { AnalyticsView } from 'src/analyticsTypes';
import { RenderedContent } from '../../../webviews/components/RenderedContent';
import { StartWorkAction, StartWorkActionType } from '../../../lib/ipc/fromUI/startWork';
import { OnMessageEventPromise } from '../../../util/reactpromise';
import { ConnectionTimeout } from '../../../util/time';
import uuid from 'uuid';

const useStyles = makeStyles((theme: Theme) => ({
title: {
Expand Down Expand Up @@ -308,6 +313,33 @@ const StartWorkPage: React.FunctionComponent = () => {
setTransition(inProgressTransitionGuess);
}, [state.issue]);

const postMessageWithEventPromise = (
send: StartWorkAction,
waitForEvent: string,
timeout: number,
nonce?: string,
): Promise<any> => {
controller.postMessage(send);
return OnMessageEventPromise(waitForEvent, timeout, nonce);
};

const fetchImage = async (url: string): Promise<any> => {
const nonce = uuid.v4();
return (
await postMessageWithEventPromise(
{
type: StartWorkActionType.GetImage,
nonce: nonce,
url: url,
siteDetailsStringified: JSON.stringify(state.issue.siteDetails),
},
'getImageDone',
ConnectionTimeout,
nonce,
)
).imgData;
};

return (
<StartWorkControllerContext.Provider value={controller}>
<AtlascodeErrorBoundary
Expand Down Expand Up @@ -380,10 +412,12 @@ const StartWorkPage: React.FunctionComponent = () => {
</Grid>
</Grid>
<Grid item>
<Typography
variant="body2"
dangerouslySetInnerHTML={{ __html: state.issue.descriptionHtml }}
></Typography>
{state.issue.siteDetails.baseApiUrl && (
<RenderedContent
html={state.issue.descriptionHtml}
fetchImage={(url) => fetchImage(url)}
/>
)}
</Grid>
<Grid item>
<Divider />
Expand Down
75 changes: 0 additions & 75 deletions src/util/html.test.ts

This file was deleted.

15 changes: 0 additions & 15 deletions src/util/html.ts

This file was deleted.

18 changes: 18 additions & 0 deletions src/webviews/components/WebviewComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as React from 'react';
import { Action, LegacyPMFData } from '../../ipc/messaging';
import { OnMessageEventPromise } from '../../util/reactpromise';
import { ConnectionTimeout } from '../../util/time';
import { darken, lighten, opacity } from './colors';
import uuid from 'uuid';

interface VsCodeApi {
postMessage(msg: {}): void;
Expand Down Expand Up @@ -113,4 +115,20 @@ export abstract class WebviewComponent<A extends Action, R, P, S> extends React.
this._api.postMessage(send);
return OnMessageEventPromise(waitForEvent, timeout, nonce);
}

protected async fetchImage(url: string): Promise<any> {
const nonce = uuid.v4();
return (
await this.postMessageWithEventPromise(
{
action: 'getImage',
nonce: nonce,
url: url,
},
'getImageDone',
ConnectionTimeout,
nonce,
)
).imgData;
}
}
23 changes: 3 additions & 20 deletions src/webviews/components/issue/AbstractIssueEditorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import {
} from '../../../ipc/issueMessaging';
import { Action, HostErrorMessage, Message } from '../../../ipc/messaging';
import { ConnectionTimeout } from '../../../util/time';
import { replaceRelativeURLsWithAbsolute } from '../../../util/html';
import { colorToLozengeAppearanceMap } from '../colors';
import * as FieldValidators from '../fieldValidators';
import * as SelectFieldHelper from '../selectFieldHelper';
Expand Down Expand Up @@ -372,7 +371,7 @@ export abstract class AbstractIssueEditorPage<
}
}, 100);

protected getInputMarkup(field: FieldUI, baseApiUrl: string, editmode: boolean = false): any {
protected getInputMarkup(field: FieldUI, editmode: boolean = false): any {
switch (field.uiType) {
case UIType.Input: {
let validateFunc = this.getValidateFunction(field, editmode);
Expand Down Expand Up @@ -402,12 +401,10 @@ export abstract class AbstractIssueEditorPage<
let markup: React.ReactNode = <p></p>;

if ((field as InputFieldUI).isMultiline) {
const html = this.state.fieldValues[`${field.key}.rendered`] || undefined;
const fixedHtml = replaceRelativeURLsWithAbsolute(html, baseApiUrl);
markup = (
<EditRenderedTextArea
text={this.state.fieldValues[`${field.key}`]}
renderedText={fixedHtml}
renderedText={this.state.fieldValues[`${field.key}.rendered`]}
fetchUsers={async (input: string) =>
(await this.fetchUsers(input)).map((user) => ({
displayName: user.displayName,
Expand All @@ -420,21 +417,7 @@ export abstract class AbstractIssueEditorPage<
onSave={async (val: string) => {
await this.handleInlineEdit(field, val);
}}
fetchImage={async (url: string) => {
const nonce = uuid.v4();
return (
await this.postMessageWithEventPromise(
{
action: 'getImage',
nonce: nonce,
url: url,
},
'getImageDone',
ConnectionTimeout,
nonce,
)
).imgData;
}}
fetchImage={(img) => this.fetchImage(img)}
/>
);
} else {
Expand Down
5 changes: 1 addition & 4 deletions src/webviews/components/issue/CommentComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@ import React, { useState } from 'react';
import { DetailedSiteInfo } from '../../../atlclients/authInfo';
import { RenderedContent } from '../RenderedContent';
import { TextAreaEditor } from './TextAreaEditor';
import { replaceRelativeURLsWithAbsolute } from '../../../util/html';

type Props = {
siteDetails: DetailedSiteInfo;
comment: JiraComment;
isServiceDeskProject: boolean;
baseApiUrl: string;
fetchUsers: (input: string) => Promise<any[]>;
onSave: (commentBody: string, commentId?: string, restriction?: CommentVisibility) => void;
onDelete: (commentId: string) => void;
Expand All @@ -29,7 +27,6 @@ export const CommentComponent: React.FC<Props> = ({
siteDetails,
comment,
isServiceDeskProject,
baseApiUrl,
fetchUsers,
onSave,
onDelete,
Expand All @@ -40,7 +37,7 @@ export const CommentComponent: React.FC<Props> = ({
const [isSaving, setIsSaving] = useState(false);

const prettyCreated = `${formatDistanceToNow(parseISO(comment.created))} ago`;
const body = replaceRelativeURLsWithAbsolute(comment.renderedBody!, baseApiUrl) || comment.body;
const body = comment.renderedBody ? comment.renderedBody : comment.body;
const type = isServiceDeskProject ? (comment.jsdPublic ? 'external' : 'internal') : undefined;

if (editing && !isSaving) {
Expand Down
4 changes: 2 additions & 2 deletions src/webviews/components/issue/CreateIssuePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -278,11 +278,11 @@ export default class CreateIssuePage extends AbstractIssueEditorPage<Emit, Accep
};

getCommonFieldMarkup(): any {
return this.commonFields.map((field) => this.getInputMarkup(field, this.state.siteDetails.baseApiUrl));
return this.commonFields.map((field) => this.getInputMarkup(field));
}

getAdvancedFieldMarkup(): any {
return this.advancedFields.map((field) => this.getInputMarkup(field, this.state.siteDetails.baseApiUrl));
return this.advancedFields.map((field) => this.getInputMarkup(field));
}

public render() {
Expand Down
Loading

0 comments on commit bd34c1b

Please sign in to comment.