Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
30f1f1f
Remove block error list as an experiment
thsparks Apr 4, 2025
233a237
Some block error list refactoring
thsparks Apr 7, 2025
ba54683
Show runtime exceptions in blocks error panel
thsparks Apr 16, 2025
070a58a
Refactor checkpoint. Still some issues, notably grouping errors and d…
thsparks Apr 17, 2025
74327f9
Fix up display of errors with stack frames
thsparks Apr 17, 2025
5fdc636
Fix when "debug this project" is shown
thsparks Apr 17, 2025
2e342cd
Remove errorListRef file, committed by mistake
thsparks Apr 17, 2025
7cbc806
Remove unused variable
thsparks Apr 18, 2025
f0ba3f5
Pass errors in as props rather than using a listener function
thsparks Apr 18, 2025
abf27c7
Simplified key for errors
thsparks Apr 21, 2025
822135f
Error key adjustment
thsparks Apr 21, 2025
e422def
Remove to do items. These functions end up being fairly specific, so …
thsparks Apr 21, 2025
8a2c192
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks Apr 21, 2025
33f4fda
More readable block stacks, with ability to focus on blocks in the stack
thsparks Apr 22, 2025
40fefaa
Some cleanup
thsparks Apr 22, 2025
154aed5
More code tidying
thsparks Apr 22, 2025
116f4f8
Clear errors when unloading a file
thsparks Apr 22, 2025
972cef4
Move getBlockText to pxtblocks for easier reuse
thsparks Apr 23, 2025
bb7dded
Hacking together editor tour for error help
thsparks Apr 25, 2025
0f92986
Update webapp/src/blocks.tsx
thsparks Apr 25, 2025
9e6a105
Merge branch 'thsparks/err_helper/blocks_problem_window' of https://g…
thsparks Apr 25, 2025
cdb30df
Remove redundant check
thsparks Apr 25, 2025
01b6bc4
Some refactoring of the error list item
thsparks Apr 26, 2025
1e05bcd
Button for item row when it's interactive
thsparks Apr 28, 2025
7b277ab
Wrap message in span (and button content in div)
thsparks Apr 28, 2025
16dee9e
Combine error counter elements, add missing span
thsparks Apr 28, 2025
0960d49
Adding getFieldDescription API, still need to improve the getBlockTex…
thsparks Apr 30, 2025
491e6a0
Hide expand / shrink buttons from display text
thsparks Apr 30, 2025
b0ac1e2
Fix display text for ifElse
thsparks Apr 30, 2025
07f34ef
Hide hidden fields from block display string
thsparks Apr 30, 2025
333feb9
Adjust melody representation
thsparks Apr 30, 2025
bdc032a
Do not show blocks inside the 'mouth' when getting block text.
thsparks May 1, 2025
f94e3ba
Use correct function (and truncate strings) in getDisplayInfoForExcep…
thsparks May 1, 2025
6678c90
Fix a few more image fields that shouldn't have display text
thsparks May 1, 2025
5fca6e2
Remove test code
thsparks May 1, 2025
2c7afdd
Make getFieldDescription optional
thsparks May 1, 2025
5ad568e
Consistent way of highlighting and centering on blocks when clicking …
thsparks May 1, 2025
e5e0794
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 1, 2025
2a307a5
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 1, 2025
501b8ff
Merge branch 'thsparks/err_helper/blocks_problem_window' into thspark…
thsparks May 1, 2025
385cbb5
Update code fence removal
thsparks May 2, 2025
6467395
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 2, 2025
0f618ea
Allow for unset targetQueries in editor tour
thsparks May 6, 2025
cdf1e42
Basic help button styling
thsparks May 6, 2025
d0ee6fd
Update content sent to AI
thsparks May 6, 2025
1ebb6f7
Allow errors to contain metadata like the block id
thsparks May 6, 2025
f4836bd
Basic (temporary) text display. Response handling needs significant c…
thsparks May 7, 2025
55864e9
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 9, 2025
ccdc493
Beginning some code cleanup/refactoring, still in progress...
thsparks May 12, 2025
4a1b731
Some more refactoring
thsparks May 12, 2025
6bc9dda
Remove class from errorHelp, just use functions
thsparks May 13, 2025
0bff911
Refactor so most of the blocks/text specific checks are happening in …
thsparks May 13, 2025
945769a
Allow different tour styles & configurations. Kept style at the bubbl…
thsparks May 14, 2025
4804168
Require sign-in. May decide to move this check into the ErrorList, no…
thsparks May 14, 2025
6316303
Move login check to errorList and remove errorHelpButton (it's just a…
thsparks May 14, 2025
2ee9974
Loading display (simple for now)
thsparks May 14, 2025
114213c
Delete todo about removing metadata. This is used when sending to AI …
thsparks May 14, 2025
ebf0b6b
Add front-end feature flag
thsparks May 15, 2025
153ff4d
Minor styling adjustments
thsparks May 15, 2025
1a2593a
Handle errors
thsparks May 15, 2025
1f0c7b9
Allow for including final step in tour counter. This involved some re…
thsparks May 15, 2025
7699c4a
After experimenting, preserve json formatting for errors.
thsparks May 15, 2025
d572b99
Add tick events
thsparks May 15, 2025
a23be84
Remove to do items that won't be done for this PR
thsparks May 15, 2025
76928f2
Formatting
thsparks May 15, 2025
fb03851
Remove function that is no longer needed
thsparks May 15, 2025
5cd0ed4
Change some styling (and class name) for the errorList note.
thsparks May 15, 2025
b55e5f2
Clear errorListNote when errors change
thsparks May 15, 2025
39edfe4
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 15, 2025
00e6dc7
AI Disclaimer for blocks tour
thsparks May 15, 2025
95bfaf2
Add AI disclaimer to text response.
thsparks May 15, 2025
9a0a3e5
Preserve newlines in text explanation
thsparks May 15, 2025
5b7822b
Merge branch 'thsparks/err_helper/tour_explanation_experiment' of htt…
thsparks May 15, 2025
1a71c18
Feedback for editor tour (still needs proper testing)
thsparks May 16, 2025
fc09f68
Disclaimer & feedback for text-based responses
thsparks May 16, 2025
cdffd99
Use ThumbsFeedback for tour as well
thsparks May 16, 2025
e243b83
Slight redesign on tour bubble disclaimer
thsparks May 16, 2025
ca82467
Only show feedback when config feedback is set
thsparks May 19, 2025
404f468
Add continuation has for login, so it returns you to the editor inste…
thsparks May 19, 2025
79af659
Question mark icon instead of robot
thsparks May 19, 2025
84a161a
Merge branch 'thsparks/err_helper/tour_explanation_experiment' of htt…
thsparks May 19, 2025
9a70892
Smaller disclaimer in the bubble
thsparks May 19, 2025
debbaa1
Subtler disclaimer
thsparks May 19, 2025
6c4387f
Remove unused variables
thsparks May 19, 2025
263fa58
Update webapp/src/blocks.tsx
thsparks May 19, 2025
08f0c9e
Merge branch 'thsparks/err_helper/tour_explanation_experiment' of htt…
thsparks May 19, 2025
ad6bd20
Add comment to serializeBlocks
thsparks May 19, 2025
d9475cf
Check step.elementId is set before attempting to use it
thsparks May 19, 2025
3ec8c45
Update wording for disclaimer to match teams, copilot
thsparks May 19, 2025
025ebce
Trim mutations from xml before sending to AI.
thsparks May 19, 2025
95f80d9
Apply suggestions from code review
thsparks May 19, 2025
355aa61
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 19, 2025
c753de7
More classList updates to avoid unnecessary ternary operators
thsparks May 19, 2025
96a7016
Merge branch 'thsparks/err_helper/tour_explanation_experiment' of htt…
thsparks May 19, 2025
f7dbcb7
Comments for ThumbsFeedback
thsparks May 19, 2025
fffb712
Remove unused variable
thsparks May 19, 2025
9d64bcc
Fix typo
thsparks May 19, 2025
4349e99
Remove unused css
thsparks May 20, 2025
7a8f534
Formatting and undo old const/let change
thsparks May 20, 2025
8fc683f
Comment updates
thsparks May 20, 2025
772c604
Fix build
thsparks May 20, 2025
a43d174
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 20, 2025
5b87e03
Unify AI footers and move below navigation buttons in tour bubble
thsparks May 20, 2025
7d96ad0
Remove need for negative margins
thsparks May 20, 2025
ef404d5
Lock ai feedback in tour after selected. Trying to support changing t…
thsparks May 20, 2025
d8f3faf
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 23, 2025
3994e52
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 23, 2025
a7301ed
Merge branch 'master' of https://github.com/microsoft/pxt into thspar…
thsparks May 23, 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
1 change: 1 addition & 0 deletions localtypings/pxtarget.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1354,6 +1354,7 @@ declare namespace pxt.tour {
steps: BubbleStep[];
showConfetti?: boolean;
numberFinalStep?: boolean; // The last step will only be included in the step count if this is true.
footer?: string | JSX.Element;
}
const enum BubbleLocation {
Above,
Expand Down
24 changes: 24 additions & 0 deletions react-common/components/controls/AIFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { classList } from "../util";
import { ThumbsFeedback } from "./Feedback/ThumbsFeedback";

interface AIFooterProps {
className?: string; // Optional class name to add to the footer
onFeedbackSelected: (positive: boolean | undefined) => void; // Callback function to handle feedback selection
}

/**
* A component containing a standard AI disclaimer and feedback buttons.
*/
export const AIFooter = (props: AIFooterProps) => {
const {
className,
onFeedbackSelected
} = props;

return (
<div className={classList("ai-footer", className)}>
<div className="ai-footer-text">{lf("AI generated content may be incorrect.")}</div>
<ThumbsFeedback lockOnSelect={true} onFeedbackSelected={onFeedbackSelected} />
</div>
);
};
68 changes: 68 additions & 0 deletions react-common/components/controls/Feedback/ThumbsFeedback.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import * as React from "react";
import { classList } from "../../util";
import { Button } from "../Button";

interface ThumbsFeedbackProps {
onFeedbackSelected: (positive: boolean | undefined) => void; // Callback function to handle feedback selection
lockOnSelect?: boolean; // If true, the user cannot change their selection once made
positiveFeedbackText?: string; // Tooltip text for the thumbs up button (not displayed)
negativeFeedbackText?: string; // Tooltip text for the thumbs down button (not displayed)
rootClassName?: string; // Optional class name to add to the root element
positiveClassName?: string; // Optional class name to add to the thumbs up button
negativeClassName?: string; // Optional class name to add to the thumbs down button
}

/**
* A component for gathering simple thumbs up/down feedback.
*/
export const ThumbsFeedback = (props: ThumbsFeedbackProps) => {
const {
lockOnSelect,
onFeedbackSelected,
positiveFeedbackText,
negativeFeedbackText,
rootClassName,
positiveClassName,
negativeClassName,
} = props;
const [selectedFeedback, setSelectedFeedback] = React.useState<boolean | undefined>(undefined);

const handleFeedbackSelected = (positive: boolean) => {
if (positive === selectedFeedback) {
// If the user clicks the same feedback button again, reset it
setSelectedFeedback(undefined);
onFeedbackSelected(undefined);
} else {
setSelectedFeedback(positive);
onFeedbackSelected(positive);
}
};

const positiveText = positiveFeedbackText || lf("Helpful");
const negativeText = negativeFeedbackText || lf("Not Helpful");
const lockButtons = lockOnSelect && selectedFeedback !== undefined;
return (
<div className={classList("feedback-buttons", rootClassName)}>
<Button
className={classList("feedback-button", positiveClassName, selectedFeedback ? "selected" : undefined)}
onClick={() => handleFeedbackSelected(true)}
title={positiveText}
ariaLabel={positiveText}
leftIcon={selectedFeedback ? "fas fa-thumbs-up" : "far fa-thumbs-up"}
disabled={lockButtons}
/>
<Button
className={classList(
"feedback-button",
negativeClassName,
selectedFeedback === false ? "selected" : undefined
)}
onClick={() => handleFeedbackSelected(false)}
title={negativeText}
ariaLabel={negativeText}
leftIcon={selectedFeedback === false ? "fas fa-thumbs-down" : "far fa-thumbs-down"}
disabled={lockButtons}
/>
</div>
);
};
11 changes: 8 additions & 3 deletions react-common/components/controls/TeachingBubble.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface TeachingBubbleProps extends ContainerProps {
onNext: () => void;
onBack: () => void;
onFinish: () => void;
footer?: string | JSX.Element;
}

export const TeachingBubble = (props: TeachingBubbleProps) => {
Expand All @@ -45,6 +46,7 @@ export const TeachingBubble = (props: TeachingBubbleProps) => {
onNext,
onBack,
onFinish,
footer,
stepNumber,
totalSteps,
parentElement,
Expand Down Expand Up @@ -379,14 +381,14 @@ export const TeachingBubble = (props: TeachingBubbleProps) => {
ariaLabel={closeLabel}
rightIcon="fas fa-times-circle"
/>
<div className="teaching-bubble-content">
<div className="teaching-bubble-body">
<strong aria-live="polite">{targetContent.title}</strong>
<p aria-live="polite">{targetContent.description}</p>
<div className={`teaching-bubble-footer ${!hasSteps ? "no-steps" : ""}`}>
<div className={`teaching-bubble-navigation ${!hasSteps ? "no-steps" : ""}`}>
{hasSteps && <div className={classList("teaching-bubble-steps", forceHideSteps && "hidden")} aria-live="polite">
{stepNumber} of {totalSteps}
</div>}
<div className="teaching-bubble-navigation">
<div className="teaching-bubble-navigation-buttons">
{hasPrevious && <Button
className="tertiary tour-button"
onClick={onBack}
Expand All @@ -411,6 +413,9 @@ export const TeachingBubble = (props: TeachingBubbleProps) => {
</div>
</div>
</div>
{footer && <div className="teaching-bubble-footer">
{footer}
</div>}
</div>
</FocusTrap>, parentElement || document.getElementById("root") || document.body)
}
14 changes: 14 additions & 0 deletions react-common/styles/controls/AIFooter.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.ai-footer {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
height: fit-content;
font-size: 14px;
line-height: 14px;

.feedback-button i {
font-size: 14px;
}
}
20 changes: 20 additions & 0 deletions react-common/styles/controls/ThumbsFeedback.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.feedback-buttons {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;

.common-button.feedback-button {
background: none;
padding: 0.1rem 0;
margin: 0 0.2rem 0 0;

i {
margin: 0;
}

&:hover:not(.disabled) {
filter: opacity(0.7);
}
}
}
27 changes: 22 additions & 5 deletions react-common/styles/onboarding/TeachingBubble.less
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
color: var(--teaching-bubble-foreground);
box-shadow: 0 0 0 0.1rem;
border-radius: 0.5rem;
padding: 1rem;
z-index: @modalDimmerZIndex;

.common-button {
Expand Down Expand Up @@ -74,20 +73,25 @@
color: var(--teaching-bubble-foreground);
}

.teaching-bubble-content {
.teaching-bubble-body {
padding: 1rem;
font-size: 1.1rem;

p {
margin: .25rem 0 .5rem;
margin: 0.5rem 0;
}
}

.teaching-bubble-footer {
.teaching-bubble-navigation {
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: space-between;

.common-button.feedback-button {
color: var(--teaching-bubble-foreground);
}

.teaching-bubble-steps {
font-size: .9rem;
color: var(--teaching-bubble-foreground);
Expand Down Expand Up @@ -121,6 +125,19 @@
}
}

.teaching-bubble-footer {
color: var(--pxt-neutral-alpha80);
margin-top: 0.5rem;
margin: 0; // negative margins compensate for the padding on the bubble
padding: 0.5rem 1rem;
border-top: 1px solid var(--pxt-neutral-alpha50);

.ai-footer .feedback-button.disabled {
// Override the default disabled coloring
color: var(--pxt-neutral-alpha80);
}
}

.teaching-bubble-close.common-button {
position: absolute;
right: 0.5rem;
Expand Down Expand Up @@ -148,7 +165,7 @@
color: @highContrastTextColor;
border: solid @highContrastTextColor;

.teaching-bubble-navigation>.common-button {
.teaching-bubble-navigation-buttons>.common-button {
color: @highContrastTextColor;
border: solid @highContrastTextColor;
}
Expand Down
2 changes: 2 additions & 0 deletions react-common/styles/react-common.less
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
@import "controls/Accordion.less";
@import "controls/CarouselNav.less";
@import "controls/Feedback.less";
@import "controls/ThumbsFeedback.less";
@import "controls/AIFooter.less";
@import "theming/base-theme.less";
@import "./react-common-variables.less";
@import "./semantic-ui-overrides.less";
Expand Down
18 changes: 18 additions & 0 deletions theme/ai-error-explanation-text.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.ai-explanation-container {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
width: 100%;
height: 100%;
white-space: pre-line; // Preserve new lines

.ai-footer {
margin-top: 1rem;

.feedback-button.disabled {
// Override the default disabled coloring
color: var(--pxt-neutral1-foreground);
}
}
}
1 change: 1 addition & 0 deletions theme/pxt.less
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
@import 'errorList';
@import 'asset-editor';
@import 'semantic-ui-overrides';
@import 'ai-error-explanation-text';

@import 'light';
@import 'accessibility';
Expand Down
15 changes: 14 additions & 1 deletion webapp/src/blocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { Measurements } from "./constants";
import { flow } from "../../pxtblocks";
import { HIDDEN_CLASS_NAME } from "../../pxtblocks/plugins/flyout/blockInflater";
import { FlyoutButton } from "../../pxtblocks/plugins/flyout/flyoutButton";
import { AIFooter } from "../../react-common/components/controls/AIFooter";

interface CopyDataEntry {
version: 1;
Expand Down Expand Up @@ -1035,6 +1036,7 @@ export class Editor extends toolboxeditor.ToolboxEditor {
const validBlockIds = this.parent.getBlocks().map((b) => b.id);

const tourSteps: pxt.tour.BubbleStep[] = [];
let invalidBlockIdCount = 0;
for (const step of response.explanationSteps) {
const tourStep = {
title: lf("Error Explanation"),
Expand All @@ -1050,17 +1052,28 @@ export class Editor extends toolboxeditor.ToolboxEditor {
} else {
// Do not add the tour target, but keep the step in case it's still helpful.
pxt.tickEvent("errorHelp.invalidBlockId");
invalidBlockIdCount++;
}

tourSteps.push(tourStep);
}
return {
steps: tourSteps,
showConfetti: false,
numberFinalStep: true
numberFinalStep: true,
footer: <AIFooter onFeedbackSelected={positive => this.handleErrorHelpFeedback(positive, {
type: "tour",
tourStepCount: response.explanationSteps.length,
errorCount: this.errors.length,
invalidBlockIdCount: invalidBlockIdCount,
})} />
};
}

private handleErrorHelpFeedback(positive: boolean, responseData: any) {
pxt.tickEvent("errorHelp.feedback", { ...responseData, positive: positive + "" });
}

getBlocksAreaDiv() {
return document.getElementById('blocksArea');
}
Expand Down
24 changes: 24 additions & 0 deletions webapp/src/components/AIErrorExplanationText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { AIFooter } from "../../../react-common/components/controls/AIFooter";

interface AIErrorExplanationTextProps {
explanation: string;
onFeedbackSelected: (positive: boolean) => void;
}

/**
* A simple component to encapsulate how we display paragraph-form AI generated error explanations.
* Mostly exists to encapsulate the disclaimer and feedback footer.
*/
export const AIErrorExplanationText = (props: AIErrorExplanationTextProps) => {
const {
explanation,
onFeedbackSelected,
} = props;

return (
<div className="ai-explanation-container">
<div className="explanation">{explanation}</div>
<AIFooter onFeedbackSelected={onFeedbackSelected} />
</div>
);
};
3 changes: 2 additions & 1 deletion webapp/src/components/onboarding/Tour.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface TourProps {

export const Tour = (props: TourProps) => {
const { onClose, config } = props;
const { steps } = config;
const { steps, footer } = config;
const [currentStep, setCurrentStep] = useState(0);
const tourStartTime = useRef(Date.now());
const stepStartTime = useRef(Date.now());
Expand Down Expand Up @@ -69,5 +69,6 @@ export const Tour = (props: TourProps) => {
onFinish={onFinish}
showConfetti={confetti}
forceHideSteps={hideSteps}
footer={footer}
/>
};
2 changes: 1 addition & 1 deletion webapp/src/errorList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export type ErrorDisplayInfo = {
export interface ErrorListProps {
onSizeChange?: (state: pxt.editor.ErrorListState) => void;
errors: ErrorDisplayInfo[];
note?: string;
note?: string | JSX.Element;
startDebugger?: () => void;
getErrorHelp?: () => Promise<void>; // Should return a promise that resolves when the help is loaded
showLoginDialog?: (
Expand Down
Loading