From 0c03d2c0747e2a95fe5c0154676c36142c3425ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Istv=C3=A1n=20So=C3=B3s?= Date: Mon, 6 May 2024 16:13:18 +0200 Subject: [PATCH] Folding report page sections. (#7690) --- app/lib/admin/models.dart | 2 + app/lib/frontend/templates/report.dart | 183 ++++++++++++++++++---- pkg/pub_integration/test/report_test.dart | 1 + pkg/web_app/lib/src/foldable.dart | 5 +- pkg/web_css/lib/src/_report.scss | 34 ++++ 5 files changed, 190 insertions(+), 35 deletions(-) diff --git a/app/lib/admin/models.dart b/app/lib/admin/models.dart index 3b3d94750..dd26aaef5 100644 --- a/app/lib/admin/models.dart +++ b/app/lib/admin/models.dart @@ -202,6 +202,8 @@ class ModerationSubject { } late final fqn = '$kind:$localName'; + bool get isPackage => package != null; + bool get isPublisher => publisherId != null; } class ModerationSubjectKind { diff --git a/app/lib/frontend/templates/report.dart b/app/lib/frontend/templates/report.dart index 29988de82..7dc367b89 100644 --- a/app/lib/frontend/templates/report.dart +++ b/app/lib/frontend/templates/report.dart @@ -2,6 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. +import 'package:pub_dev/frontend/static_files.dart'; + import '../../account/models.dart'; import '../../admin/models.dart'; import '../dom/dom.dart' as d; @@ -9,16 +11,26 @@ import '../dom/material.dart' as material; import 'layout.dart'; const _subjectKindLabels = { - ModerationSubjectKind.package: 'Package: ', - ModerationSubjectKind.packageVersion: 'Package version: ', - ModerationSubjectKind.publisher: 'Publisher: ', + ModerationSubjectKind.package: 'package', + ModerationSubjectKind.packageVersion: 'package version', + ModerationSubjectKind.publisher: 'publisher', }; /// Renders the create publisher page. String renderReportPage({ SessionData? sessionData, - ModerationSubject? subject, + required ModerationSubject subject, }) { + final kindLabel = _subjectKindLabels[subject.kind] ?? 'about'; + // TODO: also add `url` + final lcpsDeepLink = + Uri.parse('https://reportcontent.google.com/troubleshooter').replace( + queryParameters: { + 'product': 'dart_pub', + 'content_id': + subject.fqn, // TODO: Use subject.canonicalUrl, also add canonicalUrl + }, + ); return renderLayoutPage( PageType.standalone, d.div( @@ -30,38 +42,109 @@ String renderReportPage({ }, children: [ d.h1(text: 'Report a problem'), - if (!(sessionData?.isAuthenticated ?? false)) - d.fragment([ - d.p(text: 'Contact information:'), - material.textField( - id: 'report-email', - name: 'email', - label: 'Email', + d.p(children: [ + d.text('Why do you wish to report $kindLabel '), + d.code(text: subject.localName), + d.text('?'), + ]), + d.input(type: 'hidden', name: 'subject', value: subject.fqn), + d.p(text: ''), + // illegal content + if (subject.isPackage) + _block( + title: 'I believe the package contains illegal content.', + children: [ + d.markdown('Please report illegal content through the ' + '[illegal content reporting form here]($lcpsDeepLink).') + ], + ) + else if (subject.isPublisher) + _block( + title: 'I believe the publisher contains illegal content.', + children: [ + d.markdown('Please report illegal content through the ' + '[illegal content reporting form here]($lcpsDeepLink).') + ], + ), + + // contact + if (subject.isPackage) + _block( + title: + 'I have found a bug in the package / I need help using the package.', + children: [ + d.markdown( + 'Please consult the package page: `pub.dev/packages/${subject.package}`'), + d.p( + text: + 'Many packages have issue trackers, support discussion boards or chat rooms. ' + 'Often these are discoverable from the package source code repository.'), + d.p( + text: + 'Many packages are freely available and package authors ' + 'are not required to provide support.'), + d.markdown( + 'And the Dart team cannot provide support for all packages on pub.dev, ' + 'but it is often possible to get help and talk to other Dart developers through ' + '[community channels](https://dart.dev/community).') + ], + ) + else if (subject.isPublisher) + _block( + title: 'I want to contact the publisher.', + children: [ + d.markdown( + 'Please consult the publisher page: `pub.dev/publishers/`'), + d.p( + text: 'All publishers have a contact email. ' + 'Publishers do not have to provide support and may not respond to your inquiries.'), + ], + ), + + // direct report + _block( + classes: ['report-page-direct-report'], + title: 'I believe the $kindLabel violates pub.dev/policy.', + children: [ + if (!(sessionData?.isAuthenticated ?? false)) + d.fragment([ + d.p(text: 'Contact information:'), + material.textField( + id: 'report-email', + name: 'email', + label: 'Email', + ), + ]), + d.p(text: 'Please describe the issue you want to report:'), + material.textArea( + id: 'report-message', + name: 'message', + label: 'Message', + rows: 10, + cols: 60, + maxLength: 8192, ), - ]), - if (subject != null) - d.fragment([ - d.input(type: 'hidden', name: 'subject', value: subject.fqn), - d.p(children: [ - d.text(_subjectKindLabels[subject.kind] ?? ''), - d.code(text: subject.localName), - ]), - ]), - d.p(text: 'Please describe the issue you want to report:'), - material.textArea( - id: 'report-message', - name: 'message', - label: 'Message', - rows: 10, - cols: 60, - maxLength: 8192, + material.raisedButton( + label: 'Submit', + id: 'report-submit', + attributes: { + 'data-form-api-button': 'submit', + }, + ), + ], ), - material.raisedButton( - label: 'Submit', - id: 'report-submit', - attributes: { - 'data-form-api-button': 'submit', - }, + + // problem with pub.dev + _block( + title: 'I have a problem with the pub.dev website.', + children: [ + d.markdown('Security vulnerabilities may be reported through ' + '[goo.gl/vulnz](https://goo.gl/vulnz)'), + d.markdown('Bugs on the pub.dev website may be reported at ' + '[github.com/dart-lang/pub-dev/issues](https://github.com/dart-lang/pub-dev/issues)'), + d.markdown( + 'Issues with specific accounts may be directed to `support@pub.dev`.'), + ], ), ], ), @@ -70,3 +153,35 @@ String renderReportPage({ noIndex: true, // no need to index, may contain session-specific content ); } + +d.Node _block({ + required String title, + required Iterable children, + List? classes, +}) { + return d.div( + classes: ['report-page-section', 'foldable', ...?classes], + children: [ + d.div( + classes: ['report-page-section-title', 'foldable-button'], + children: [ + d.img( + classes: ['foldable-icon'], + image: d.Image( + src: staticUrls + .getAssetUrl('/static/img/report-foldable-icon.svg'), + alt: 'trigger folding of the section', + width: 13, + height: 6, + ), + ), + d.text(title), + ], + ), + d.div( + classes: ['report-page-section-body', 'foldable-content'], + children: children, + ) + ], + ); +} diff --git a/pkg/pub_integration/test/report_test.dart b/pkg/pub_integration/test/report_test.dart index 70d6d4aec..3dc88270d 100644 --- a/pkg/pub_integration/test/report_test.dart +++ b/pkg/pub_integration/test/report_test.dart @@ -50,6 +50,7 @@ void main() { await Future.delayed(Duration(seconds: 1)); await page.gotoOrigin('/report?subject=package:oxygen'); + await page.waitAndClick('.report-page-direct-report'); await page.waitFocusAndType('#report-email', 'user@pub.dev'); await page.waitFocusAndType( '#report-message', 'Huston, we have a problem.'); diff --git a/pkg/web_app/lib/src/foldable.dart b/pkg/web_app/lib/src/foldable.dart index 224eb8037..9243bf9ad 100644 --- a/pkg/web_app/lib/src/foldable.dart +++ b/pkg/web_app/lib/src/foldable.dart @@ -59,7 +59,10 @@ void _setEventForFoldable() { } } - h.querySelector('.foldable-icon')!.attributes['tabindex'] = '0'; + final foldableIcon = h.querySelector('.foldable-icon'); + if (foldableIcon != null) { + foldableIcon.attributes['tabindex'] = '0'; + } // listen on trigger events h.onClick.listen((e) async { diff --git a/pkg/web_css/lib/src/_report.scss b/pkg/web_css/lib/src/_report.scss index d5edc0dbc..c69a97f3e 100644 --- a/pkg/web_css/lib/src/_report.scss +++ b/pkg/web_css/lib/src/_report.scss @@ -10,4 +10,38 @@ width: 100%; margin-bottom: 12px; } + + .report-page-section { + border-top: 1px solid #eee; + margin: 12px 0px; + } + + .report-page-section-title { + font-size: 18px; + font-weight: 500; + padding: 8px 0px; + cursor: pointer; + + &:hover { + background: #f0f0f0; + } + } + + .report-page-section-body { + padding-left: 16px; + } + + .foldable-icon { + margin: 0px 8px 3px 8px; + width: 12px; + + transform: rotate(90deg); + transition: transform .3s linear; + } + + .foldable.-active { + .foldable-icon { + transform: rotate(180deg); + } + } }