Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feedback Form #2099

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
339166a
first skeleton for the feedback component
Sep 6, 2024
131f138
star component
Sep 6, 2024
d34adc1
include feedback button
Sep 6, 2024
219d4b0
send data to heap through feedback
Sep 10, 2024
e88317c
remove unused prop and component
Sep 10, 2024
830225e
Merge branch 'main' into feature/feedback-form
Sep 10, 2024
a5d5de9
add title for feedback button
Sep 11, 2024
ba23f57
mood board
Sep 11, 2024
8f07236
update with final design
Sep 12, 2024
2d47972
include messages
Sep 12, 2024
f3c2e71
move to Feedback wrapper instead
Sep 12, 2024
f3e71f8
add local storage to track first time
Sep 12, 2024
278be58
add key for Mood component
Sep 12, 2024
6194843
draft version of local storage
Sep 13, 2024
ffbce1a
update styling
Sep 16, 2024
fd1646e
break the title into 2 lines
Sep 16, 2024
075b03f
move mood to its own component
Sep 16, 2024
28fde20
include the release note
Sep 16, 2024
1eaa1ba
Merge branch 'main' into feature/feedback-form
Sep 16, 2024
172b939
fix eslint error
Sep 16, 2024
bca6d90
Separate feedback to feedback-button and feedback-form to suit the logic
Sep 16, 2024
bc8aea0
tidy up code
Sep 16, 2024
efa5c91
remove unused icon and components
Sep 16, 2024
d4eed38
add transition for feedback-form and button
Sep 16, 2024
997d902
include new message for cancel event
Sep 16, 2024
c131729
update localStorage name
Sep 17, 2024
73e0c68
move feedback to config
Sep 17, 2024
3f5270d
Merge branch 'main' into feature/feedback-form
Sep 17, 2024
46f9e27
update text area colour
Sep 17, 2024
5787fef
update font-size for text area and hover state for button
Sep 17, 2024
b3139d5
update font for place holder in text area
Sep 17, 2024
b10de5c
update font for place holder in text area in feedback
Sep 17, 2024
72108b9
Merge branch 'main' into feature/feedback-form
Sep 17, 2024
291819e
Merge branch 'main' into feature/feedback-form
Sep 17, 2024
72088f7
re-run the test
Sep 18, 2024
2eb4350
include classnames for icons
Sep 18, 2024
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
2 changes: 1 addition & 1 deletion RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Please follow the established format:
- Slice a pipeline functionality. (#2036)

## Bug fixes and other changes

- Add feedback component for slicing pipeline. (#2085)
- Fixes design issues in metadata panel. (#2009)
- Fix missing run command in metadata panel for task nodes. (#2055)
- Add `UnavailableDataset` as a default dataset for `--lite` mode. (#2083)
Expand Down
17 changes: 17 additions & 0 deletions src/components/feedback-button/feedback-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import classnames from 'classnames';

import './feedback-button.scss';

export const FeedbackButton = ({ onClick, visible, title }) => {
return (
<button
className={classnames('feedback-button', {
'feedback-button--visible': visible,
})}
onClick={onClick}
>
{title}
</button>
);
};
21 changes: 21 additions & 0 deletions src/components/feedback-button/feedback-button.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.feedback-button {
background-color: #007bff;
border: none;
color: white;
cursor: pointer;
font-size: 16px;
height: 40px;
line-height: 40px;
opacity: 0;
position: fixed;
right: -96px;
text-align: center;
top: 50%;
padding: 0 16px;
transform: translateY(-50%) rotate(90deg);
}

.feedback-button--visible {
opacity: 1;
transition: opacity 0.5s ease-in;
}
111 changes: 111 additions & 0 deletions src/components/feedback-form/feedback-form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React, { useState, useEffect } from 'react';
import classnames from 'classnames';
import Button from '../ui/button';
import CloseIcon from '../icons/close';
import { Mood } from '../mood/mood';
import { getHeap } from '../../tracking';
import { getDataTestAttribute } from '../../utils/get-data-test-attribute';
import { localStorageFeedbackSeen } from '../../config';
import { loadLocalStorage, saveLocalStorage } from '../../store/helpers';
import { feedbackMessageDelayTimeout } from '../../config';

import './feedback-form.scss';

export const FeedbackForm = ({ hideForm, title, usageContext }) => {
const [formStatus, setFormStatus] = useState('active'); // 'active', 'submitted', 'cancelled'
const [activeMood, setActiveMood] = useState(null);
const [feedbackText, setFeedbackText] = useState('');

const handleFormAction = (action) => {
setFormStatus(action);

const timer = setTimeout(() => {
updateLocalStorageUsageContext(false);
hideForm();
}, feedbackMessageDelayTimeout);

return () => clearTimeout(timer);
};

const updateLocalStorageUsageContext = (value) => {
const existingData = loadLocalStorage(localStorageFeedbackSeen) || {};
existingData[usageContext] = value;
saveLocalStorage(localStorageFeedbackSeen, existingData);
};

useEffect(() => {
if (formStatus === 'submitted' || formStatus === 'cancelled') {
const timer = setTimeout(() => {
setFormStatus('active');
setActiveMood(null);
setFeedbackText('');
}, feedbackMessageDelayTimeout);

return () => clearTimeout(timer);
}
}, [formStatus]);

const handleFormSubmit = (e) => {
e.preventDefault();
handleFormAction('submitted');
getHeap().track(getDataTestAttribute(usageContext, 'feedback-form'), {
rating: activeMood,
feedback: feedbackText,
});
};

const getMessages = () => {
if (formStatus === 'submitted') {
return 'Thank you for sharing feedback!';
}
if (formStatus === 'cancelled') {
return (
<>
You can provide feedback any time by using
<br />
the feedback button in the sliced view.
</>
);
}
};

if (formStatus === 'submitted' || formStatus === 'cancelled') {
return (
<div className="feedback-form--wrapper feedback-form--message">
{getMessages()}
</div>
);
} else {
return (
<div
className={classnames('feedback-form--wrapper', {
'feedback-form--wrapper-no-text-area': activeMood === null,
})}
>
<div
className="feedback-form--close-icon"
onClick={() => handleFormAction('cancelled')}
>
<CloseIcon />
</div>
<h2 className="feedback-form--title">{title}</h2>
<div className="feedback-form">
<Mood selectedMood={activeMood} onClick={setActiveMood} />
{activeMood !== null && (
<>
<textarea
className="feedback-form--text-area"
value={feedbackText}
onChange={(event) => setFeedbackText(event.target.value)}
placeholder="How can we improve this feature?"
/>
<Button type="submit" onClick={handleFormSubmit}>
Submit feedback
</Button>
</>
)}
</div>
</div>
);
}
};
120 changes: 120 additions & 0 deletions src/components/feedback-form/feedback-form.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
@use '../../styles/variables' as colors;

@keyframes fadeIn {
from {
opacity: 0;
}

to {
opacity: 1;
}
}

.kui-theme--dark {
--feedback-form-bg: #{colors.$white-0};
--feedback-form-content: #{colors.$slate-0};
--feedback-form-title: #{colors.$black-900};
--feedback-form--text-area--background: #{colors.$slate-200};
--feedback-form--text-area-placeholder--color: #{colors.$black-200};
}

.kui-theme--light {
--feedback-form-bg: #{colors.$black-900};
--feedback-form-content: #{colors.$white-0};
--feedback-form-title: #{colors.$white-0};
--feedback-form--text-area--background: #{colors.$white-0};
--feedback-form--text-area-placeholder--color: #{colors.$black-0};
}

.feedback-form--wrapper {
animation: fadeIn 0.5s ease-in;
background-color: var(--feedback-form-bg);
border-radius: 8px 0 0 8px;
min-width: 312px;
padding: 24px 24px 36px;
position: fixed;
right: 0;
top: 320px;

.button__btn {
margin-top: 12px;
}
}

.feedback-form--wrapper-no-text-area {
padding-bottom: 68px;
}

.feedback-form--text-area::placeholder {
color: var(--feedback-form--text-area-placeholder--color);
margin: auto; /* Centers the placeholder text vertically */
text-align: center;
font-family: Inter, sans-serif;
}

.feedback-form--text-area {
align-items: center;
background-color: transparent;
border: 1px solid grey;
color: var(--feedback-form-title);
display: flex;
font-size: 14px;
font-family: Inter, sans-serif;
height: 104px;
margin-top: 68px;
padding: 8px 12px;
resize: none;
text-align: left;
width: 364px;
}

.feedback-form--title {
color: var(--feedback-form-title);
font-size: 18px;
font-style: normal;
font-weight: 400;
line-height: 28px;
margin-top: 12px;
text-align: center;
margin-bottom: 24px;
}

.feedback-form--close-icon {
cursor: pointer;
height: 24px;
margin-left: auto;
width: 24px;

path {
fill: var(--feedback-form-title);
}
}

.feedback-form {
align-items: center;
display: flex;
flex-direction: column;
justify-content: center;

.button__btn {
border: 1px solid var(--feedback-form-title);
color: var(--feedback-form-title);
margin-top: 36px;
padding: 8px 12px;

&:hover {
background-color: var(--feedback-form-title);
color: var(--feedback-form-bg);
}
}
}

.feedback-form--message {
color: var(--feedback-form-title);
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px;
padding: 24px 36px;
width: auto;
}
43 changes: 41 additions & 2 deletions src/components/flowchart/flowchart.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ import { getDataTestAttribute } from '../../utils/get-data-test-attribute';
import Tooltip from '../ui/tooltip';
import { SlicedPipelineActionBar } from '../sliced-pipeline-action-bar/sliced-pipeline-action-bar';
import { SlicedPipelineNotification } from '../sliced-pipeline-notification/sliced-pipeline-notification';
import { FeedbackButton } from '../feedback-button/feedback-button';
import { FeedbackForm } from '../feedback-form/feedback-form';
import { localStorageFeedbackSeen, feedbacks } from '../../config';
import { loadLocalStorage } from '../../store/helpers';

import './styles/flowchart.scss';

/**
Expand All @@ -64,6 +69,8 @@ export class FlowChart extends Component {
range: [],
},
showSlicingNotification: false,
resetSlicingPipelineBtnClicked: false,
showFeedbackForm: false,
};
this.onViewChange = this.onViewChange.bind(this);
this.onViewChangeEnd = this.onViewChangeEnd.bind(this);
Expand Down Expand Up @@ -804,12 +811,24 @@ export class FlowChart extends Component {
visibleSlicing,
} = this.props;
const { outerWidth = 0, outerHeight = 0 } = chartSize;
const { showSlicingNotification } = this.state;
const {
showSlicingNotification,
resetSlicingPipelineBtnClicked,
showFeedbackForm,
} = this.state;

// Counts the nodes in the slicedPipeline array, excludes any modularPipeline Id
const numberOfNodesInSlicedPipeline = slicedPipeline.filter(
(id) => !modularPipelineIds.includes(id)
).length;

const isFirstTimeFeedbackAfterResetSlicing =
resetSlicingPipelineBtnClicked &&
loadLocalStorage(localStorageFeedbackSeen)['slicing-pipeline'] ===
undefined;

const seenSlicingFeedbackBefore =
loadLocalStorage(localStorageFeedbackSeen)['slicing-pipeline'] === false;
return (
<div
className="pipeline-flowchart kedro"
Expand Down Expand Up @@ -871,6 +890,22 @@ export class FlowChart extends Component {
})}
ref={this.layerNamesRef}
/>
<FeedbackButton
onClick={() => this.setState({ showFeedbackForm: true })}
title={feedbacks.slicingPipeline.buttonTittle}
visible={
isSlicingPipelineApplied &&
seenSlicingFeedbackBefore &&
!showFeedbackForm
}
/>
{(isFirstTimeFeedbackAfterResetSlicing || showFeedbackForm) && (
<FeedbackForm
hideForm={() => this.setState({ showFeedbackForm: false })}
title={feedbacks.slicingPipeline.formTitle}
usageContext={feedbacks.slicingPipeline.usageContext}
/>
)}
{showSlicingNotification && visibleSlicing && (
<SlicedPipelineNotification
notification={
Expand All @@ -879,14 +914,18 @@ export class FlowChart extends Component {
visibleSidebar={visibleSidebar}
/>
)}

{numberOfNodesInSlicedPipeline > 0 && runCommand.length > 0 && (
<div ref={this.slicedPipelineActionBarRef}>
<SlicedPipelineActionBar
chartSize={chartSize}
displayMetadataPanel={Boolean(clickedNode)}
isSlicingPipelineApplied={isSlicingPipelineApplied}
onApplySlicingPipeline={() => onApplySlice(true)}
onResetSlicingPipeline={this.resetSlicedPipeline}
onResetSlicingPipeline={() => {
this.resetSlicedPipeline();
this.setState({ resetSlicingPipelineBtnClicked: true });
}}
ref={this.slicedPipelineActionBarRef}
runCommand={runCommand}
slicedPipelineLength={numberOfNodesInSlicedPipeline}
Expand Down
13 changes: 13 additions & 0 deletions src/components/icons/mood-dissatisfied.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions src/components/icons/mood-neutral.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading