mirror of
https://github.com/HeyPuter/puter.git
synced 2026-08-24 15:07:17 +00:00
feat: enable app feedback by default in Dev Center
New apps created in Dev Center now have feedbackEnabled set on creation, so users can send the developer feedback without any extra setup. A "User Feedback" toggle in the app's settings lets developers turn it off (and back on); it's wired into the save payload, the dirty-state tracking, and the reset-to-original path like the neighboring toggles. The Save update omits feedbackEnabled unless the toggle is present, and the backend leaves an omitted field untouched, so the default survives the create-then-save flow Dev Center runs. Add an SDK apps-suite guard covering that round-trip (create-on -> unrelated update keeps it -> can be turned off).
This commit is contained in:
@@ -191,6 +191,9 @@ async function create_app (title, source_path = null, items = null) {
|
||||
maximizeOnStart: false,
|
||||
background: false,
|
||||
dedupeName: true,
|
||||
// New apps accept user feedback by default; developers can turn this
|
||||
// off in the app's settings (the "User Feedback" toggle).
|
||||
feedbackEnabled: true,
|
||||
metadata: {
|
||||
window_resizable: true,
|
||||
fullpage_on_landing: true,
|
||||
@@ -509,6 +512,12 @@ function generate_edit_app_section (app) {
|
||||
</div>
|
||||
|
||||
<h3 style="font-size: 23px; border-bottom: 1px solid #EEE; margin-top: 50px; margin-bottom: 0px;">Misc</h3>
|
||||
<div style="margin-top:30px;">
|
||||
<input type="checkbox" id="edit-app-user-feedback" name="edit-app-user-feedback" value="true" ${app.feedback_enabled ? 'checked' : ''}>
|
||||
<label for="edit-app-user-feedback" style="display: inline;">User Feedback</label>
|
||||
<p>When enabled, users can send you feedback about this app from within Puter. Feedback is delivered to your account's email address.</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:30px;">
|
||||
<input type="checkbox" id="edit-app-locked" name="edit-app-locked" value="true" ${app.metadata?.locked ? 'checked' : ''}>
|
||||
<label for="edit-app-locked" style="display: inline;">Delete Protection${lock_svg}</label>
|
||||
@@ -586,6 +595,7 @@ function trackOriginalValues () {
|
||||
locked: $('#edit-app-locked').is(':checked'),
|
||||
fullPageOnLanding: $('#edit-app-fullpage-on-landing').is(':checked'),
|
||||
setTitleToFile: $('#edit-app-set-title-to-file').is(':checked'),
|
||||
userFeedback: $('#edit-app-user-feedback').is(':checked'),
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -626,7 +636,8 @@ function hasChanges () {
|
||||
$('#edit-app-hide-titlebar').is(':checked') !== originalValues.checkboxes.hideTitleBar ||
|
||||
$('#edit-app-locked').is(':checked') !== originalValues.checkboxes.locked ||
|
||||
$('#edit-app-fullpage-on-landing').is(':checked') !== originalValues.checkboxes.fullPageOnLanding ||
|
||||
$('#edit-app-set-title-to-file').is(':checked') !== originalValues.checkboxes.setTitleToFile
|
||||
$('#edit-app-set-title-to-file').is(':checked') !== originalValues.checkboxes.setTitleToFile ||
|
||||
$('#edit-app-user-feedback').is(':checked') !== originalValues.checkboxes.userFeedback
|
||||
);
|
||||
}
|
||||
|
||||
@@ -674,6 +685,7 @@ function resetToOriginalValues () {
|
||||
$('#edit-app-locked').prop('checked', originalValues.checkboxes.locked);
|
||||
$('#edit-app-fullpage-on-landing').prop('checked', originalValues.checkboxes.fullPageOnLanding);
|
||||
$('#edit-app-set-title-to-file').prop('checked', originalValues.checkboxes.setTitleToFile);
|
||||
$('#edit-app-user-feedback').prop('checked', originalValues.checkboxes.userFeedback);
|
||||
|
||||
if ( originalValues.icon ) {
|
||||
$('#edit-app-icon').css('background-image', `url(${originalValues.icon})`);
|
||||
@@ -1284,6 +1296,7 @@ async function saveEditedApp (mode) {
|
||||
description: description,
|
||||
maximizeOnStart: $('#edit-app-maximize-on-start').is(':checked'),
|
||||
background: $('#edit-app-background').is(':checked'),
|
||||
feedbackEnabled: $('#edit-app-user-feedback').is(':checked'),
|
||||
metadata: {
|
||||
fullpage_on_landing: $('#edit-app-fullpage-on-landing').is(':checked'),
|
||||
social_image: socialImageUrl,
|
||||
|
||||
@@ -144,6 +144,28 @@ export default suite('apps', {
|
||||
t.assert.equal(updated.description, 'New description');
|
||||
},
|
||||
|
||||
'feedbackEnabled round-trips on create and survives an unrelated update':
|
||||
async (t) => {
|
||||
// Mirrors Dev Center: create with feedback on, then a Save-style
|
||||
// update that omits feedbackEnabled must not clear it.
|
||||
const created = await t.puter.apps.create({
|
||||
name: 'apps-suite-feedback',
|
||||
indexURL: 'https://example.com/feedback',
|
||||
feedbackEnabled: true,
|
||||
});
|
||||
t.assert.equal(Boolean(created.feedback_enabled), true);
|
||||
|
||||
const updated = await t.puter.apps.update('apps-suite-feedback', {
|
||||
title: 'Feedback App',
|
||||
});
|
||||
t.assert.equal(Boolean(updated.feedback_enabled), true);
|
||||
|
||||
const disabled = await t.puter.apps.update('apps-suite-feedback', {
|
||||
feedbackEnabled: false,
|
||||
});
|
||||
t.assert.equal(Boolean(disabled.feedback_enabled), false);
|
||||
},
|
||||
|
||||
'get of an unknown app rejects': async (t) => {
|
||||
await t.assert.rejects(
|
||||
() => t.puter.apps.get('apps-suite-does-not-exist'),
|
||||
|
||||
Reference in New Issue
Block a user