mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2024-11-26 17:16:11 -05:00
Merge pull request #2404 from rschamp/mod-panel-phase-1
Admin panel for the project page
This commit is contained in:
commit
8e75b8c6cf
7 changed files with 165 additions and 123 deletions
|
@ -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
|
||||
>
|
||||
</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}
|
||||
>
|
||||
>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -88,6 +60,7 @@ class AdminPanel extends React.Component {
|
|||
|
||||
AdminPanel.propTypes = {
|
||||
children: PropTypes.node,
|
||||
className: PropTypes.string,
|
||||
isAdmin: PropTypes.bool
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue