Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
817eac8
Update the client implementation to use the new capture feedback js api
antonis Nov 27, 2024
5370a99
Updates SDK API
antonis Nov 27, 2024
42e2fa1
Adds new feedback button in the sample
antonis Nov 27, 2024
514b102
Adds changelog
antonis Nov 27, 2024
0935bbd
Removes unused mock
antonis Nov 27, 2024
9ea5496
Update CHANGELOG.md
antonis Nov 28, 2024
da0d4ac
Directly use captureFeedback from sentry/core
antonis Nov 28, 2024
3e36c6d
Use import from core
antonis Nov 28, 2024
5f3df64
Fixes imports order lint issue
antonis Nov 28, 2024
71b28e8
Fixes build issue
antonis Nov 28, 2024
f9d2b59
Adds captureFeedback tests from sentry-javascript
antonis Nov 28, 2024
d05d531
Update CHANGELOG.md
krystofwoldrich Nov 28, 2024
2bb104b
Only deprecate client captureUserFeedback
antonis Nov 28, 2024
4339274
Add simple form UI
antonis Nov 29, 2024
6ce799b
Adds basic form functionality
antonis Nov 29, 2024
f2cefc6
Update imports
antonis Nov 29, 2024
694ee33
Update imports
antonis Dec 2, 2024
18b1c33
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 2, 2024
034efde
Remove useState hook to avoid multiple react instances issues
antonis Dec 2, 2024
67a492d
Move types and styles in different files
antonis Dec 2, 2024
8eaa61d
Removes attachment button to be added back separately along with the …
antonis Dec 2, 2024
0b88cc5
Add basic field validation
antonis Dec 2, 2024
ae11b8d
Adds changelog
antonis Dec 2, 2024
7f2ca06
Updates changelog
antonis Dec 2, 2024
064b6c4
Updates changelog
antonis Dec 2, 2024
e2add4a
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 2, 2024
e21718a
Trim whitespaces from the submitted feedback
antonis Dec 2, 2024
407f179
Adds tests
antonis Dec 2, 2024
14ac005
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 2, 2024
4e13866
Adds attachment button UI
antonis Dec 3, 2024
3373b9b
Adds changelog
antonis Dec 3, 2024
eabacb4
Add attachment handling based on the client implementation
antonis Dec 3, 2024
26b4da0
Reduce render method complexity
antonis Dec 3, 2024
21f537d
Adds test for attachment button visibility
antonis Dec 3, 2024
645d932
Format code
antonis Dec 3, 2024
34bf6a8
Pick image with react-native-image-picker
antonis Dec 3, 2024
0cd3982
Convert base64 string to Uint8Array before sending
antonis Dec 3, 2024
e8aa30b
Updates changelog
antonis Dec 3, 2024
ddade00
Renames FeedbackFormScreen to FeedbackForm
antonis Dec 6, 2024
1bc1e4c
Add beta label
antonis Dec 6, 2024
7934756
Extract default text to constants
antonis Dec 6, 2024
95e1e0f
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 10, 2024
a169362
Moves constant to a separate file and aligns naming with JS
antonis Dec 10, 2024
4b5df7a
Adds input text labels
antonis Dec 10, 2024
4fa81ce
Close screen before sending the feedback to minimise wait time
antonis Dec 10, 2024
4fff82f
Rename file for consistency
antonis Dec 10, 2024
0258bf2
Flatten configuration hierarchy and clean up
antonis Dec 10, 2024
458ebc2
Align required values with JS
antonis Dec 10, 2024
f0e1bef
Use Sentry user email and name when set
antonis Dec 10, 2024
b9235f2
Simplifies email validation
antonis Dec 10, 2024
6717a84
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 11, 2024
39a67bd
Show success alert message
antonis Dec 11, 2024
501a134
Aligns naming with JS and unmounts the form by default
antonis Dec 11, 2024
4b290a2
Use the minimum config without props in the changelog
antonis Dec 11, 2024
7109deb
Adds development not for unimplemented function
antonis Dec 11, 2024
c80c5cb
Show email and name conditionally
antonis Dec 11, 2024
8c56753
Adds sentry branding (png logo)
antonis Dec 11, 2024
d6e9229
Adds sentry logo resource
antonis Dec 11, 2024
5292475
Add assets in module exports
antonis Dec 11, 2024
efd809f
Revert "Add assets in module exports"
antonis Dec 11, 2024
bc7ae65
Revert "Adds sentry logo resource"
antonis Dec 11, 2024
79ee5ba
Revert "Adds sentry branding (png logo)"
antonis Dec 11, 2024
ba13320
Add last event id
antonis Dec 11, 2024
1f5fb56
Mock lastEventId
antonis Dec 11, 2024
5bb03f7
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' into antonis/3…
antonis Dec 12, 2024
1c5b87e
Remove changelog
antonis Dec 12, 2024
c837f8e
Reverse unrelated change
antonis Dec 12, 2024
439367a
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 13, 2024
9831482
Adds beta note in the changelog
antonis Dec 13, 2024
08a5805
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' into antonis/3…
antonis Dec 13, 2024
4097347
Updates changelog
antonis Dec 13, 2024
f8a82fd
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 13, 2024
30a7b10
Align colors with JS
antonis Dec 13, 2024
3eccf25
Update CHANGELOG.md
antonis Dec 13, 2024
bc96fce
Update CHANGELOG.md
antonis Dec 13, 2024
995a9ca
Update CHANGELOG.md
antonis Dec 13, 2024
3aacaf7
Use regular fonts for both buttons
antonis Dec 13, 2024
20e3a6c
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' of https://git…
antonis Dec 13, 2024
78e412c
Handle keyboard properly
antonis Dec 13, 2024
c45a5e6
Adds an option on whether the email should be validated
antonis Dec 13, 2024
6e39119
Merge properties only once
antonis Dec 13, 2024
57d99e9
Loads current user data on form construction
antonis Dec 13, 2024
6fb8ab4
Remove unneeded extra padding
antonis Dec 13, 2024
fd2e317
Fix background color issue
antonis Dec 13, 2024
03215dd
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' into antonis/3…
antonis Dec 13, 2024
b793937
Fixes changelog typo
antonis Dec 16, 2024
b209ad6
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 16, 2024
a40fde6
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 17, 2024
2a8f13f
Updates styles background color
antonis Dec 17, 2024
0f3a244
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 17, 2024
9a96e74
Use defaultProps
antonis Dec 17, 2024
10c1c0e
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 17, 2024
2be08a6
Correct defaultProps
antonis Dec 17, 2024
0588552
Adds test to verify when getUser is called
antonis Dec 17, 2024
85e3484
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' into antonis/3…
antonis Dec 17, 2024
d316adf
Add default value in doc comment
antonis Dec 18, 2024
614514e
Add a more clear doc comment
antonis Dec 18, 2024
e0ec92d
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 18, 2024
2900dec
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' into antonis/3…
antonis Dec 18, 2024
265e629
(2.2) feat: Add Feedback Form UI Branding logo (#4357)
antonis Dec 19, 2024
da0e3ea
Autoinject feedback form (#4370)
antonis Dec 19, 2024
a931ba9
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 19, 2024
37ad066
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' into antonis/3…
antonis Dec 19, 2024
5f9dec6
Align changelog entry
antonis Dec 19, 2024
8359696
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 19, 2024
76518cc
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 23, 2024
c472348
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' into antonis/3…
antonis Dec 23, 2024
b0384ed
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Dec 30, 2024
61886c2
Merge branch 'main' into antonis/3859-newCaptureFeedbackAPI-Form
antonis Jan 9, 2025
9853630
Update changelog
antonis Jan 9, 2025
38812a7
Merge branch 'antonis/3859-newCaptureFeedbackAPI-Form' into antonis/3…
antonis Jan 9, 2025
fe23346
Merge branch 'feedback-ui' into antonis/3959-captureFeedback-attachem…
antonis Jan 10, 2025
a1cb828
Use AddScreenshot naming
antonis Jan 10, 2025
0a4b12d
Allow only Uint8Array for screenshots
antonis Jan 10, 2025
239c64c
Rename callback parameter
antonis Jan 10, 2025
7bc1d0d
Merge branch 'feedback-ui' into antonis/3959-captureFeedback-attachem…
antonis Jan 14, 2025
fc0040c
Merge branch 'feedback-ui' into antonis/3959-captureFeedback-attachem…
antonis Jan 15, 2025
a107436
Adds snapshot tests for screenshot button
antonis Jan 15, 2025
cb2559e
Merge branch 'feedback-ui' into antonis/3959-captureFeedback-attachem…
antonis Jan 15, 2025
4b8f1d8
Merge branch 'feedback-ui' into antonis/3959-captureFeedback-attachem…
antonis Jan 16, 2025
91a4b8a
Rename screenshot button for clarity
antonis Jan 16, 2025
c25996e
Use a library to get the Uint8Array
antonis Jan 16, 2025
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
11 changes: 11 additions & 0 deletions packages/core/src/js/feedback/FeedbackForm.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ const defaultStyles: FeedbackFormStyles = {
textAlignVertical: 'top',
color: FORGROUND_COLOR,
},
screenshotButton: {
backgroundColor: '#eee',
padding: 15,
borderRadius: 5,
marginBottom: 20,
alignItems: 'center',
},
screenshotText: {
color: '#333',
fontSize: 16,
},
submitButton: {
backgroundColor: PURPLE,
paddingVertical: 15,
Expand Down
32 changes: 30 additions & 2 deletions packages/core/src/js/feedback/FeedbackForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ export class FeedbackForm extends React.Component<FeedbackFormProps, FeedbackFor
return;
}

const attachments = this.state.filename && this.state.attachment
? [
{
filename: this.state.filename,
data: this.state.attachment,
},
]
: undefined;

const eventId = lastEventId();
const userFeedback: SendFeedbackParams = {
message: trimmedDescription,
Expand All @@ -78,7 +87,7 @@ export class FeedbackForm extends React.Component<FeedbackFormProps, FeedbackFor

try {
this.setState({ isVisible: false });
captureFeedback(userFeedback);
captureFeedback(userFeedback, attachments ? { attachments } : undefined);
onSubmitSuccess({ name: trimmedName, email: trimmedEmail, message: trimmedDescription, attachments: undefined });
Alert.alert(text.successMessageText);
onFormSubmitted();
Expand All @@ -90,6 +99,17 @@ export class FeedbackForm extends React.Component<FeedbackFormProps, FeedbackFor
}
};

public onScreenshotButtonPress: () => void = () => {
if (!this.state.filename && !this.state.attachment) {
const { onAddScreenshot } = { ...defaultConfiguration, ...this.props };
onAddScreenshot((filename: string, attachement: Uint8Array) => {
this.setState({ filename, attachment: attachement });
});
} else {
this.setState({ filename: undefined, attachment: undefined });
}
}

/**
* Renders the feedback form screen.
*/
Expand Down Expand Up @@ -167,7 +187,15 @@ export class FeedbackForm extends React.Component<FeedbackFormProps, FeedbackFor
onChangeText={(value) => this.setState({ description: value })}
multiline
/>

{config.enableScreenshot && (
<TouchableOpacity style={styles.screenshotButton} onPress={this.onScreenshotButtonPress}>
<Text style={styles.screenshotText}>
{!this.state.filename && !this.state.attachment
? text.addScreenshotButtonLabel
: text.removeScreenshotButtonLabel}
</Text>
</TouchableOpacity>
)}
<TouchableOpacity style={styles.submitButton} onPress={this.handleFeedbackSubmit}>
<Text style={styles.submitText}>{text.submitButtonLabel}</Text>
</TouchableOpacity>
Expand Down
25 changes: 25 additions & 0 deletions packages/core/src/js/feedback/FeedbackForm.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ export interface FeedbackGeneralConfiguration {
*/
showName?: boolean;

/**
* This flag determines whether the "Add Screenshot" button is displayed
* @default false
*/
enableScreenshot?: boolean;

/**
* Fill in email/name input fields with Sentry user context if it exists.
* The value of the email/name keys represent the properties of your user context.
Expand Down Expand Up @@ -113,6 +119,16 @@ export interface FeedbackTextConfiguration {
*/
isRequiredLabel?: string;

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

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

/**
* The title of the error dialog
*/
Expand Down Expand Up @@ -148,6 +164,11 @@ export interface FeedbackCallbacks {
*/
onFormClose?: () => void;

/**
* Callback when a screenshot is added
*/
onAddScreenshot?: (attachFile: (filename: string, data: Uint8Array) => void) => void;

/**
* Callback when feedback is successfully submitted
*
Expand Down Expand Up @@ -179,6 +200,8 @@ export interface FeedbackFormStyles {
submitText?: TextStyle;
cancelButton?: ViewStyle;
cancelText?: TextStyle;
screenshotButton?: ViewStyle;
screenshotText?: TextStyle;
titleContainer?: ViewStyle;
sentryLogo?: ImageStyle;
}
Expand All @@ -191,4 +214,6 @@ export interface FeedbackFormState {
name: string;
email: string;
description: string;
filename?: string;
attachment?: string | Uint8Array;
}
10 changes: 10 additions & 0 deletions packages/core/src/js/feedback/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const ERROR_TITLE = 'Error';
const FORM_ERROR = 'Please fill out all required fields.';
const EMAIL_ERROR = 'Please enter a valid email address.';
const SUCCESS_MESSAGE_TEXT = 'Thank you for your report!';
const ADD_SCREENSHOT_LABEL = 'Add a screenshot';
const REMOVE_SCREENSHOT_LABEL = 'Remove screenshot';
const GENERIC_ERROR_TEXT = 'Unable to send feedback due to an unexpected error.';

export const defaultConfiguration: Partial<FeedbackFormProps> = {
Expand All @@ -31,6 +33,11 @@ export const defaultConfiguration: Partial<FeedbackFormProps> = {
);
}
},
onAddScreenshot: (_: (filename: string, data: Uint8Array) => void) => {
if (__DEV__) {
Alert.alert('Development note', 'onAddScreenshot callback is not implemented.');
}
},
onSubmitSuccess: () => {
// Does nothing by default
},
Expand All @@ -53,6 +60,7 @@ export const defaultConfiguration: Partial<FeedbackFormProps> = {
isNameRequired: false,
showEmail: true,
showName: true,
enableScreenshot: false,

// FeedbackTextConfiguration
cancelButtonLabel: CANCEL_BUTTON_LABEL,
Expand All @@ -69,5 +77,7 @@ export const defaultConfiguration: Partial<FeedbackFormProps> = {
formError: FORM_ERROR,
emailError: EMAIL_ERROR,
successMessageText: SUCCESS_MESSAGE_TEXT,
addScreenshotButtonLabel: ADD_SCREENSHOT_LABEL,
removeScreenshotButtonLabel: REMOVE_SCREENSHOT_LABEL,
genericError: GENERIC_ERROR_TEXT,
};
47 changes: 45 additions & 2 deletions packages/core/test/feedback/FeedbackForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { FeedbackForm } from '../../src/js/feedback/FeedbackForm';
import type { FeedbackFormProps, FeedbackFormStyles } from '../../src/js/feedback/FeedbackForm.types';

const mockOnFormClose = jest.fn();
const mockOnAddScreenshot = jest.fn();
const mockOnSubmitSuccess = jest.fn();
const mockOnFormSubmitted = jest.fn();
const mockOnSubmitError = jest.fn();
Expand All @@ -28,9 +29,11 @@ jest.mock('@sentry/core', () => ({

const defaultProps: FeedbackFormProps = {
onFormClose: mockOnFormClose,
onAddScreenshot: mockOnAddScreenshot,
onSubmitSuccess: mockOnSubmitSuccess,
onFormSubmitted: mockOnFormSubmitted,
onSubmitError: mockOnSubmitError,
addScreenshotButtonLabel: 'Add Screenshot',
formTitle: 'Feedback Form',
nameLabel: 'Name Label',
namePlaceholder: 'Name Placeholder',
Expand Down Expand Up @@ -84,6 +87,13 @@ const customStyles: FeedbackFormStyles = {
color: '#ff0000',
fontSize: 10,
},
screenshotButton: {
backgroundColor: '#00ff00',
},
screenshotText: {
color: '#0000ff',
fontSize: 13,
},
};

describe('FeedbackForm', () => {
Expand All @@ -107,8 +117,24 @@ describe('FeedbackForm', () => {
expect(toJSON()).toMatchSnapshot();
});

it('matches the snapshot with default configuration and screenshot button', () => {
const { toJSON } = render(<FeedbackForm enableScreenshot={true}/>);
expect(toJSON()).toMatchSnapshot();
});

it('matches the snapshot with custom texts and screenshot button', () => {
const { toJSON } = render(<FeedbackForm {...defaultProps} enableScreenshot={true}/>);
expect(toJSON()).toMatchSnapshot();
});

it('matches the snapshot with custom styles and screenshot button', () => {
const customStyleProps = {styles: customStyles};
const { toJSON } = render(<FeedbackForm {...customStyleProps} enableScreenshot={true}/>);
expect(toJSON()).toMatchSnapshot();
});

it('renders correctly', () => {
const { getByPlaceholderText, getByText, getByTestId } = render(<FeedbackForm {...defaultProps} />);
const { getByPlaceholderText, getByText, getByTestId, queryByText } = render(<FeedbackForm {...defaultProps} />);

expect(getByText(defaultProps.formTitle)).toBeTruthy();
expect(getByTestId('sentry-logo')).toBeTruthy(); // default showBranding is true
Expand All @@ -118,10 +144,17 @@ describe('FeedbackForm', () => {
expect(getByPlaceholderText(defaultProps.emailPlaceholder)).toBeTruthy();
expect(getByText(`${defaultProps.messageLabel } ${ defaultProps.isRequiredLabel}`)).toBeTruthy();
expect(getByPlaceholderText(defaultProps.messagePlaceholder)).toBeTruthy();
expect(queryByText(defaultProps.addScreenshotButtonLabel)).toBeNull(); // default false
expect(getByText(defaultProps.submitButtonLabel)).toBeTruthy();
expect(getByText(defaultProps.cancelButtonLabel)).toBeTruthy();
});

it('renders attachment button when the enableScreenshot is true', () => {
const { getByText } = render(<FeedbackForm {...defaultProps} enableScreenshot={true} />);

expect(getByText(defaultProps.addScreenshotButtonLabel)).toBeTruthy();
});

it('does not render the sentry logo when showBranding is false', () => {
const { queryByTestId } = render(<FeedbackForm {...defaultProps} showBranding={false} />);

Expand Down Expand Up @@ -188,7 +221,7 @@ describe('FeedbackForm', () => {
message: 'This is a feedback message.',
name: 'John Doe',
email: '[email protected]',
});
}, undefined);
});
});

Expand Down Expand Up @@ -270,6 +303,16 @@ describe('FeedbackForm', () => {
});
});

it('calls onAddScreenshot when the screenshot button is pressed', async () => {
const { getByText } = render(<FeedbackForm {...defaultProps} enableScreenshot={true} />);

fireEvent.press(getByText(defaultProps.addScreenshotButtonLabel));

await waitFor(() => {
expect(mockOnAddScreenshot).toHaveBeenCalled();
});
});

it('calls onFormClose when the cancel button is pressed', () => {
const { getByText } = render(<FeedbackForm {...defaultProps} />);

Expand Down
Loading
Loading