Merge pull request #2404 from rschamp/mod-panel-phase-1

Admin panel for the project page
This commit is contained in:
Ray Schamp 2018-12-06 09:33:02 -05:00 committed by GitHub
commit 8e75b8c6cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 165 additions and 123 deletions

View file

@ -1,10 +1,9 @@
const bindAll = require('lodash.bindall');
const classNames = require('classnames');
const connect = require('react-redux').connect;
const PropTypes = require('prop-types');
const React = require('react');
const Button = require('../forms/button.jsx');
require('./adminpanel.scss');
class AdminPanel extends React.Component {
@ -23,64 +22,37 @@ class AdminPanel extends React.Component {
}
render () {
if (!this.props.isAdmin) return false;
if (this.state.showPanel) {
return (
<div
className="visible"
id="admin-panel"
>
return (
<div
className={classNames(
'admin-panel', this.props.className, {
hidden: !this.state.showPanel
}
)}
>
{this.state.showPanel ? (
<React.Fragment>
<span
className="toggle"
onClick={this.handleToggleVisibility}
>
x
</span>
<div className="admin-header">
<h3>Admin Panel</h3>
</div>
<div className="admin-content">
{this.props.children}
</div>
</React.Fragment>
) : (
<span
className="toggle"
onClick={this.handleToggleVisibility}
>
x
&gt;
</span>
<div className="admin-header">
<h3>Admin Panel</h3>
</div>
<div className="admin-content">
<dl>
{this.props.children}
<dt>Page Cache</dt>
<dd>
<ul className="cache-list">
<li>
<form
action="/scratch_admin/page/clear-anon-cache/"
method="post"
>
<input
name="path"
type="hidden"
value="/"
/>
<div className="button-row">
<span>For anonymous users:</span>
<Button type="submit">
<span>Clear</span>
</Button>
</div>
</form>
</li>
</ul>
</dd>
</dl>
</div>
</div>
);
}
return (
<div
className="hidden"
id="admin-panel"
>
<span
className="toggle"
onClick={this.handleToggleVisibility}
>
&gt;
</span>
)}
</div>
);
}
@ -88,6 +60,7 @@ class AdminPanel extends React.Component {
AdminPanel.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
isAdmin: PropTypes.bool
};

View file

@ -1,6 +1,6 @@
@import "../../colors";
#admin-panel {
.admin-panel {
position: fixed;
top: 0;
left: 0;
@ -9,16 +9,11 @@
box-shadow: 0 2px 5px $box-shadow-gray;
background-color: $ui-gray;
padding: 1rem;
width: 230px;
height: 100%;
overflow: scroll;
text-shadow: none;
&.visible {
width: 20%;
min-width: 180px;
max-width: 230px;
}
&.hidden {
width: 10px;
}
@ -28,33 +23,6 @@
cursor: pointer;
}
.admin-content {
dl {
list-style: none;
dt {
margin: 2rem 0 1rem 0;
border-bottom: 1px solid $ui-dark-gray;
font-size: large;
font-weight: 700;
}
dd {
margin-left: 0;
}
}
ul {
padding: 0;
li {
margin: 0;
list-style: none;
}
}
}
.button-row {
display: flex;
font-size: small;

View file

@ -11,6 +11,7 @@ const classNames = require('classnames');
const GUI = require('scratch-gui').default;
const IntlGUI = injectIntl(GUI);
const AdminPanel = require('../../components/adminpanel/adminpanel.jsx');
const decorateText = require('../../lib/decorate-text.jsx');
const FlexRow = require('../../components/flex-row/flex-row.jsx');
const Button = require('../../components/forms/button.jsx');
@ -45,6 +46,7 @@ const onKeyPress = e => {
const PreviewPresentation = ({
addToStudioOpen,
adminModalOpen,
assetHost,
backpackHost,
canAddToStudio,
@ -160,6 +162,18 @@ const PreviewPresentation = ({
return (
<div className="preview">
<AdminPanel
className={classNames('project-admin-panel', {
'modal-open': adminModalOpen
})}
>
<iframe
className={classNames('admin-iframe', {
'modal-open': adminModalOpen
})}
src={`/scratch2/${projectId}/adminpanel/`}
/>
</AdminPanel>
{ projectInfo && projectInfo.author && projectInfo.author.id && (
<React.Fragment>
{banner}
@ -530,6 +544,7 @@ const PreviewPresentation = ({
PreviewPresentation.propTypes = {
addToStudioOpen: PropTypes.bool,
adminModalOpen: PropTypes.bool,
assetHost: PropTypes.string,
backpackHost: PropTypes.string,
canAddToStudio: PropTypes.bool,

View file

@ -35,6 +35,21 @@ $stage-width: 480px;
}
}
.admin-iframe {
position: absolute;
top: 0;
left: 0;
z-index: 100;
width: 252px;
height: 100%;
}
.admin-iframe.modal-open,
.project-admin-panel.modal-open {
background-color: transparent;
width: 100%;
}
.project-title {
font-size: 1.75rem;
font-weight: 500;

View file

@ -45,6 +45,7 @@ class Preview extends React.Component {
'handleFavoriteToggle',
'handleLoadMore',
'handleLoveToggle',
'handleMessage',
'handlePopState',
'handleReportClick',
'handleReportClose',
@ -79,6 +80,7 @@ class Preview extends React.Component {
this.state = {
addToStudioOpen: false,
adminModalOpen: false,
extensions: [],
favoriteCount: 0,
invalidProject: parts.length === 1,
@ -92,10 +94,12 @@ class Preview extends React.Component {
reportOpen: false,
singleCommentId: singleCommentId
};
this.addEventListeners();
/* In the beginning, if user is on mobile and landscape, go to fullscreen */
this.setScreenFromOrientation();
}
componentDidMount () {
this.addEventListeners();
}
componentDidUpdate (prevProps, prevState) {
if (this.state.projectId > 0 &&
((this.props.sessionStatus !== prevProps.sessionStatus &&
@ -139,10 +143,12 @@ class Preview extends React.Component {
addEventListeners () {
window.addEventListener('popstate', this.handlePopState);
window.addEventListener('orientationchange', this.setScreenFromOrientation);
window.addEventListener('message', this.handleMessage);
}
removeEventListeners () {
window.removeEventListener('popstate', this.handlePopState);
window.removeEventListener('orientationchange', this.setScreenFromOrientation);
window.removeEventListener('message', this.handleMessage);
}
fetchCommunityData () {
if (this.props.userPresent) {
@ -258,6 +264,18 @@ class Preview extends React.Component {
handleDeleteComment (id, topLevelCommentId) {
this.props.handleDeleteComment(this.state.projectId, id, topLevelCommentId, this.props.user.token);
}
handleMessage (messageEvent) {
if (messageEvent.data === 'showDialog') {
this.setState({
adminModalOpen: true
});
}
if (messageEvent.data === 'hideDialog') {
this.setState({
adminModalOpen: false
});
}
}
handleReportComment (id, topLevelCommentId) {
this.props.handleReportComment(this.state.projectId, id, topLevelCommentId, this.props.user.token);
}
@ -464,6 +482,7 @@ class Preview extends React.Component {
<Page>
<PreviewPresentation
addToStudioOpen={this.state.addToStudioOpen}
adminModalOpen={this.state.adminModalOpen}
assetHost={this.props.assetHost}
backpackHost={this.props.backpackHost}
canAddToStudio={this.props.canAddToStudio}

View file

@ -529,41 +529,66 @@ class SplashPresentation extends React.Component { // eslint-disable-line react/
>
{featured}
{this.props.isAdmin ? [
<AdminPanel key="admin-panel">
<dt>Tools</dt>
<dd>
<ul>
<li>
<a href="/scratch_admin/tickets">Ticket Queue</a>
</li>
<li>
<a href="/scratch_admin/ip-search/">IP Search</a>
</li>
<li>
<a href="/scratch_admin/email-search/">Email Search</a>
</li>
</ul>
</dd>
<dt>Homepage Cache</dt>
<dd>
<ul className="cache-list">
<li>
<div className="button-row">
<span>Refresh row data:</span>
<Button
className={this.props.refreshCacheStatus.status}
disabled={this.props.refreshCacheStatus.disabled}
onClick={this.props.onRefreshHomepageCache}
{this.props.isAdmin && (
<AdminPanel className="splash-admin-panel">
<dl>
<dt>Tools</dt>
<dd>
<ul>
<li>
<a href="/scratch_admin/tickets">Ticket Queue</a>
</li>
<li>
<a href="/scratch_admin/ip-search/">IP Search</a>
</li>
<li>
<a href="/scratch_admin/email-search/">Email Search</a>
</li>
</ul>
</dd>
<dt>Homepage Cache</dt>
<dd>
<ul className="cache-list">
<li>
<div className="button-row">
<span>Refresh row data:</span>
<Button
className={this.props.refreshCacheStatus.status}
disabled={this.props.refreshCacheStatus.disabled}
onClick={this.props.onRefreshHomepageCache}
>
<span>{this.props.refreshCacheStatus.content}</span>
</Button>
</div>
</li>
</ul>
</dd>
<dt>Page Cache</dt>
<dd>
<ul className="cache-list">
<li>
<form
action="/scratch_admin/page/clear-anon-cache/"
method="post"
>
<span>{this.props.refreshCacheStatus.content}</span>
</Button>
</div>
</li>
</ul>
</dd>
<input
name="path"
type="hidden"
value="/"
/>
<div className="button-row">
<span>For anonymous users:</span>
<Button type="submit">
<span>Clear</span>
</Button>
</div>
</form>
</li>
</ul>
</dd>
</dl>
</AdminPanel>
] : []}
)}
</div>
</div>
);

View file

@ -47,6 +47,33 @@
}
}
.splash-admin-panel {
dl {
list-style: none;
dt {
margin: 2rem 0 1rem 0;
border-bottom: 1px solid $ui-dark-gray;
font-size: large;
font-weight: 700;
}
dd {
margin-left: 0;
}
}
ul {
padding: 0;
li {
margin: 0;
list-style: none;
}
}
}
.modal-content.mod-confirmation {
width: 31.25rem;
}