Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/feedback/src/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ export const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;
export const DOCUMENT = WINDOW.document;
export const NAVIGATOR = WINDOW.navigator;

export const ACTOR_LABEL = 'Report a Bug';
export const TRIGGER_LABEL = 'Report a Bug';
export const CANCEL_BUTTON_LABEL = 'Cancel';
export const SUBMIT_BUTTON_LABEL = 'Send Bug Report';
export const CONFIRM_BUTTON_LABEL = 'Confirm';
export const FORM_TITLE = 'Report a Bug';
export const EMAIL_PLACEHOLDER = '[email protected]';
export const EMAIL_LABEL = 'Email';
Expand All @@ -20,7 +21,9 @@ export const MESSAGE_LABEL = 'Description';
export const NAME_PLACEHOLDER = 'Your Name';
export const NAME_LABEL = 'Name';
export const SUCCESS_MESSAGE_TEXT = 'Thank you for your report!';
export const IS_REQUIRED_TEXT = '(required)';
export const IS_REQUIRED_LABEL = '(required)';
export const ADD_SCREENSHOT_LABEL = 'Add a screenshot';
export const REMOVE_SCREENSHOT_LABEL = 'Remove screenshot';

export const FEEDBACK_WIDGET_SOURCE = 'widget';
export const FEEDBACK_API_SOURCE = 'api';
Expand Down
10 changes: 5 additions & 5 deletions packages/feedback/src/core/components/Actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createActorStyles } from './Actor.css';
import { FeedbackIcon } from './FeedbackIcon';

export interface ActorProps {
buttonLabel: string;
triggerLabel: string;
shadow: ShadowRoot;
}

Expand All @@ -22,16 +22,16 @@ export interface ActorComponent {
/**
* The sentry-provided button to open the feedback modal
*/
export function Actor({ buttonLabel, shadow }: ActorProps): ActorComponent {
export function Actor({ triggerLabel, shadow }: ActorProps): ActorComponent {
const el = DOCUMENT.createElement('button');
el.type = 'button';
el.className = 'widget__actor';
el.ariaHidden = 'false';
el.ariaLabel = buttonLabel;
el.ariaLabel = triggerLabel;
el.appendChild(FeedbackIcon());
if (buttonLabel) {
if (triggerLabel) {
const label = DOCUMENT.createElement('span');
label.appendChild(DOCUMENT.createTextNode(buttonLabel));
label.appendChild(DOCUMENT.createTextNode(triggerLabel));
el.appendChild(label);
}

Expand Down
27 changes: 18 additions & 9 deletions packages/feedback/src/core/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@ import type {
} from '@sentry/types';
import { isBrowser, logger } from '@sentry/utils';
import {
ACTOR_LABEL,
ADD_SCREENSHOT_LABEL,
CANCEL_BUTTON_LABEL,
CONFIRM_BUTTON_LABEL,
DEFAULT_THEME,
DOCUMENT,
EMAIL_LABEL,
EMAIL_PLACEHOLDER,
FORM_TITLE,
IS_REQUIRED_TEXT,
IS_REQUIRED_LABEL,
MESSAGE_LABEL,
MESSAGE_PLACEHOLDER,
NAME_LABEL,
NAME_PLACEHOLDER,
REMOVE_SCREENSHOT_LABEL,
SUBMIT_BUTTON_LABEL,
SUCCESS_MESSAGE_TEXT,
TRIGGER_LABEL,
} from '../constants';
import { DEBUG_BUILD } from '../util/debug-build';
import { isScreenshotSupported } from '../util/isScreenshotSupported';
Expand Down Expand Up @@ -80,18 +83,21 @@ export const buildFeedbackIntegration = ({
themeDark,

// FeedbackTextConfiguration
buttonLabel = ACTOR_LABEL,
addScreenshotButtonLabel = ADD_SCREENSHOT_LABEL,
triggerLabel = TRIGGER_LABEL,
cancelButtonLabel = CANCEL_BUTTON_LABEL,
submitButtonLabel = SUBMIT_BUTTON_LABEL,
formTitle = FORM_TITLE,
confirmButtonLabel = CONFIRM_BUTTON_LABEL,
emailLabel = EMAIL_LABEL,
emailPlaceholder = EMAIL_PLACEHOLDER,
formTitle = FORM_TITLE,
isRequiredLabel = IS_REQUIRED_LABEL,
messageLabel = MESSAGE_LABEL,
messagePlaceholder = MESSAGE_PLACEHOLDER,
nameLabel = NAME_LABEL,
namePlaceholder = NAME_PLACEHOLDER,
removeScreenshotButtonLabel = REMOVE_SCREENSHOT_LABEL,
submitButtonLabel = SUBMIT_BUTTON_LABEL,
successMessageText = SUCCESS_MESSAGE_TEXT,
isRequiredText = IS_REQUIRED_TEXT,

// FeedbackCallbacks
onFormOpen,
Expand Down Expand Up @@ -121,9 +127,10 @@ export const buildFeedbackIntegration = ({
...themeLight,
},

buttonLabel,
triggerLabel,
cancelButtonLabel,
submitButtonLabel,
confirmButtonLabel,
formTitle,
emailLabel,
emailPlaceholder,
Expand All @@ -132,7 +139,9 @@ export const buildFeedbackIntegration = ({
nameLabel,
namePlaceholder,
successMessageText,
isRequiredText,
isRequiredLabel,
addScreenshotButtonLabel,
removeScreenshotButtonLabel,

onFormClose,
onFormOpen,
Expand Down Expand Up @@ -250,7 +259,7 @@ export const buildFeedbackIntegration = ({

const _createActor = (optionOverrides: OverrideFeedbackConfiguration = {}): ActorComponent => {
const shadow = _createShadow(_options);
const actor = Actor({ buttonLabel: _options.buttonLabel, shadow });
const actor = Actor({ triggerLabel: _options.triggerLabel, shadow });
const mergedOptions = mergeOptions(_options, {
...optionOverrides,
onFormOpen() {
Expand Down
24 changes: 13 additions & 11 deletions packages/feedback/src/modal/components/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { getMissingFields } from '../../util/validate';
export interface Props
extends Pick<
FeedbackInternalOptions,
| 'addScreenshotButtonLabel'
| 'removeScreenshotButtonLabel'
| 'cancelButtonLabel'
| 'emailLabel'
| 'emailPlaceholder'
Expand All @@ -28,7 +30,7 @@ export interface Props
| 'showEmail'
| 'showName'
| 'submitButtonLabel'
| 'isRequiredText'
| 'isRequiredLabel'
> {
defaultEmail: string;
defaultName: string;
Expand All @@ -48,6 +50,8 @@ function retrieveStringValue(formData: FormData, key: string): string {
}

export function Form({
addScreenshotButtonLabel,
removeScreenshotButtonLabel,
cancelButtonLabel,
defaultEmail,
defaultName,
Expand All @@ -66,7 +70,7 @@ export function Form({
showEmail,
showName,
submitButtonLabel,
isRequiredText,
isRequiredLabel,
screenshotInput,
}: Props): VNode {
// TODO: set a ref on the form, and whenever an input changes call proceessForm() and setError()
Expand Down Expand Up @@ -159,7 +163,7 @@ export function Form({

{showName ? (
<label for="name" class="form__label">
<LabelText label={nameLabel} isRequiredText={isRequiredText} isRequired={isNameRequired} />
<LabelText label={nameLabel} isRequiredLabel={isRequiredLabel} isRequired={isNameRequired} />
<input
class="form__input"
defaultValue={defaultName}
Expand All @@ -176,7 +180,7 @@ export function Form({

{showEmail ? (
<label for="email" class="form__label">
<LabelText label={emailLabel} isRequiredText={isRequiredText} isRequired={isEmailRequired} />
<LabelText label={emailLabel} isRequiredLabel={isRequiredLabel} isRequired={isEmailRequired} />
<input
class="form__input"
defaultValue={defaultEmail}
Expand All @@ -192,7 +196,7 @@ export function Form({
)}

<label for="message" class="form__label">
<LabelText label={messageLabel} isRequiredText={isRequiredText} isRequired />
<LabelText label={messageLabel} isRequiredLabel={isRequiredLabel} isRequired />
<textarea
autoFocus
class="form__input form__input--textarea"
Expand All @@ -206,8 +210,6 @@ export function Form({

{ScreenshotInputComponent ? (
<label for="screenshot" class="form__label">
<span class="form__label__text">Screenshot</span>

<button
class="btn btn--default"
type="button"
Expand All @@ -216,7 +218,7 @@ export function Form({
setShowScreenshotInput(prev => !prev);
}}
>
{showScreenshotInput ? 'Remove' : 'Add'}
{showScreenshotInput ? removeScreenshotButtonLabel : addScreenshotButtonLabel}
</button>
{screenshotError ? <div class="form__error-container">{screenshotError.message}</div> : null}
</label>
Expand All @@ -238,12 +240,12 @@ export function Form({
function LabelText({
label,
isRequired,
isRequiredText,
}: { label: string; isRequired: boolean; isRequiredText: string }): VNode {
isRequiredLabel,
}: { label: string; isRequired: boolean; isRequiredLabel: string }): VNode {
return (
<span class="form__label__text">
{label}
{isRequired && <span class="form__label__text--required">{isRequiredText}</span>}
{isRequired && <span class="form__label__text--required">{isRequiredLabel}</span>}
</span>
);
}
6 changes: 4 additions & 2 deletions packages/feedback/src/modal/integration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const feedbackModalIntegration = ((): FeedbackModalIntegration => {
},
};

const screenshotInput = screenshotIntegration && screenshotIntegration.createInput(h, dialog);
const screenshotInput = screenshotIntegration && screenshotIntegration.createInput(h, dialog, options);

const renderContent = (open: boolean): void => {
render(
Expand All @@ -68,7 +68,9 @@ export const feedbackModalIntegration = ((): FeedbackModalIntegration => {
defaultName={(userKey && user && user[userKey.name]) || ''}
defaultEmail={(userKey && user && user[userKey.email]) || ''}
successMessageText={options.successMessageText}
isRequiredText={options.isRequiredText}
isRequiredLabel={options.isRequiredLabel}
addScreenshotButtonLabel={options.addScreenshotButtonLabel}
removeScreenshotButtonLabel={options.removeScreenshotButtonLabel}
onFormClose={() => {
renderContent(false);
options.onFormClose && options.onFormClose();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { FeedbackDialog } from '@sentry/types';
import type { FeedbackDialog, FeedbackInternalOptions } from '@sentry/types';
/* eslint-disable max-lines */
import type { ComponentType, VNode, h as hType } from 'preact';
// biome-ignore lint: needed for preact
Expand All @@ -17,6 +17,7 @@ interface FactoryParams {
h: typeof hType;
imageBuffer: HTMLCanvasElement;
dialog: FeedbackDialog;
options: FeedbackInternalOptions;
}

interface Props {
Expand Down Expand Up @@ -61,8 +62,7 @@ const getContainedSize = (img: HTMLCanvasElement): Box => {
return { startX: x, startY: y, endX: width + x, endY: height + y };
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function makeScreenshotEditorComponent({ h, imageBuffer, dialog }: FactoryParams): ComponentType<Props> {
export function makeScreenshotEditorComponent({ imageBuffer, dialog, options }: FactoryParams): ComponentType<Props> {
return function ScreenshotEditor({ onError }: Props): VNode {
const styles = useMemo(() => ({ __html: createScreenshotInputStyles().innerText }), []);

Expand Down Expand Up @@ -298,7 +298,7 @@ export function makeScreenshotEditorComponent({ h, imageBuffer, dialog }: Factor
}}
class="btn btn--default"
>
Cancel
{options.cancelButtonLabel}
</button>
<button
onClick={e => {
Expand All @@ -308,7 +308,7 @@ export function makeScreenshotEditorComponent({ h, imageBuffer, dialog }: Factor
}}
class="btn btn--primary"
>
Confirm
{options.confirmButtonLabel}
</button>
</div>
</div>
Expand Down
11 changes: 8 additions & 3 deletions packages/feedback/src/screenshot/integration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import type { FeedbackDialog, FeedbackScreenshotIntegration, IntegrationFn } from '@sentry/types';
import type {
FeedbackDialog,
FeedbackInternalOptions,
FeedbackScreenshotIntegration,
IntegrationFn,
} from '@sentry/types';
import type { Attachment } from '@sentry/types';
import type { h as hType } from 'preact';
import { DOCUMENT } from '../constants';
Expand All @@ -9,12 +14,12 @@ export const feedbackScreenshotIntegration = ((): FeedbackScreenshotIntegration
name: 'FeedbackScreenshot',
// eslint-disable-next-line @typescript-eslint/no-empty-function
setupOnce() {},
createInput: (h: unknown, dialog: FeedbackDialog) => {
createInput: (h: unknown, dialog: FeedbackDialog, options: FeedbackInternalOptions) => {
const imageBuffer = DOCUMENT.createElement('canvas');

return {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
input: makeScreenshotEditorComponent({ h: h as typeof hType, imageBuffer, dialog }) as any,
input: makeScreenshotEditorComponent({ h: h as typeof hType, imageBuffer, dialog, options }) as any,

value: async () => {
const blob = await new Promise<Parameters<BlobCallback>[0]>(resolve => {
Expand Down
19 changes: 17 additions & 2 deletions packages/types/src/feedback/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export interface FeedbackTextConfiguration {
/**
* The label for the Feedback widget button that opens the dialog
*/
buttonLabel: string;
triggerLabel: string;

/**
* The label for the Feedback form cancel button that closes dialog
Expand All @@ -96,6 +96,11 @@ export interface FeedbackTextConfiguration {
*/
submitButtonLabel: string;

/**
* The label for the Screenshot editor cancel buttons
*/
confirmButtonLabel: string;

/**
* The title of the Feedback form
*/
Expand Down Expand Up @@ -139,7 +144,17 @@ export interface FeedbackTextConfiguration {
/**
* Text which indicates that a field is required
*/
isRequiredText: string;
isRequiredLabel: string;

/**
* The label for the button that adds a screeshot and renders the image editor
*/
addScreenshotButtonLabel: string;

/**
* The label for the button that removes a screenshot and hides the image editor
*/
removeScreenshotButtonLabel: string;
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/feedback/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export interface FeedbackScreenshotIntegration extends Integration {
createInput: (
h: HType,
dialog: FeedbackDialog,
options: FeedbackInternalOptions,
) => {
/**
* The preact component
Expand Down