Compare commits
No commits in common. "9e9491e064f20916fb075b9f67707126b986d176" and "447f76e80742ea70fa6a7c651fc214bb2f508dd6" have entirely different histories.
9e9491e064
...
447f76e807
@ -42,15 +42,15 @@ def users(user, params):
|
|||||||
u['avatarUrl'] = uploads.get_presigned_url('users/{0}/{1}'.format(u['_id'], u['avatar']))
|
u['avatarUrl'] = uploads.get_presigned_url('users/{0}/{1}'.format(u['_id'], u['avatar']))
|
||||||
return {'users': users}
|
return {'users': users}
|
||||||
|
|
||||||
def discover(user, count = 3):
|
def discover(user):
|
||||||
|
if not user: raise util.errors.Forbidden('You need to be logged in')
|
||||||
|
|
||||||
db = database.get_db()
|
db = database.get_db()
|
||||||
projects = []
|
projects = []
|
||||||
users = []
|
users = []
|
||||||
|
count = 3
|
||||||
|
|
||||||
all_projects_query = {'name': {'$not': re.compile('my new project', re.IGNORECASE)}, 'visibility': 'public'}
|
all_projects = list(db.projects.find({'name': {'$not': re.compile('my new project', re.IGNORECASE)}, 'visibility': 'public', 'user': {'$ne': user['_id']}}, {'name': 1, 'path': 1, 'user': 1}))
|
||||||
if user and user.get('_id'):
|
|
||||||
all_projects_query['user'] = {'$ne': user['_id']}
|
|
||||||
all_projects = list(db.projects.find(all_projects_query, {'name': 1, 'path': 1, 'user': 1}))
|
|
||||||
random.shuffle(all_projects)
|
random.shuffle(all_projects)
|
||||||
for p in all_projects:
|
for p in all_projects:
|
||||||
if db.objects.find_one({'project': p['_id'], 'name': {'$ne': 'Untitled pattern'}}):
|
if db.objects.find_one({'project': p['_id'], 'name': {'$ne': 'Untitled pattern'}}):
|
||||||
@ -60,10 +60,7 @@ def discover(user, count = 3):
|
|||||||
if len(projects) >= count: break
|
if len(projects) >= count: break
|
||||||
|
|
||||||
interest_fields = ['bio', 'avatar', 'website', 'facebook', 'twitter', 'instagram', 'location']
|
interest_fields = ['bio', 'avatar', 'website', 'facebook', 'twitter', 'instagram', 'location']
|
||||||
all_users_query = {'$or': list(map(lambda f: {f: {'$exists': True}}, interest_fields))}
|
all_users = list(db.users.find({'_id': {'$ne': user['_id']}, '$or': list(map(lambda f: {f: {'$exists': True}}, interest_fields))}, {'username': 1, 'avatar': 1, 'isSilverSupporter': 1, 'isGoldSupporter': 1}))
|
||||||
if user and user.get('_id'):
|
|
||||||
all_users_query['_id'] = {'$ne': user['_id']}
|
|
||||||
all_users = list(db.users.find(all_users_query, {'username': 1, 'avatar': 1, 'isSilverSupporter': 1, 'isGoldSupporter': 1}))
|
|
||||||
random.shuffle(all_users)
|
random.shuffle(all_users)
|
||||||
for u in all_users:
|
for u in all_users:
|
||||||
if 'avatar' in u:
|
if 'avatar' in u:
|
||||||
@ -76,17 +73,16 @@ def discover(user, count = 3):
|
|||||||
'highlightUsers': users,
|
'highlightUsers': users,
|
||||||
}
|
}
|
||||||
|
|
||||||
def explore(page = 1):
|
def explore():
|
||||||
db = database.get_db()
|
db = database.get_db()
|
||||||
per_page = 10
|
|
||||||
|
|
||||||
project_map = {}
|
project_map = {}
|
||||||
user_map = {}
|
user_map = {}
|
||||||
|
|
||||||
all_public_projects = list(db.projects.find({'name': {'$not': re.compile('my new project', re.IGNORECASE)}, 'visibility': 'public'}, {'name': 1, 'path': 1, 'user': 1}))
|
all_public_projects = list(db.projects.find({'name': {'$not': re.compile('my new project', re.IGNORECASE)}, 'visibility': 'public'}, {'name': 1, 'path': 1, 'user': 1}))
|
||||||
all_public_project_ids = list(map(lambda p: p['_id'], all_public_projects))
|
all_public_project_ids = list(map(lambda p: p['_id'], all_public_projects))
|
||||||
for project in all_public_projects:
|
for project in all_public_projects:
|
||||||
project_map[project['_id']] = project
|
project_map[project['_id']] = project
|
||||||
objects = list(db.objects.find({'project': {'$in': all_public_project_ids}, 'name': {'$not': re.compile('untitled pattern', re.IGNORECASE)}, 'preview': {'$exists': True}}, {'project': 1, 'name': 1, 'createdAt': 1, 'preview': 1}).sort('createdAt', pymongo.DESCENDING).skip((page - 1) * per_page).limit(per_page))
|
objects = list(db.objects.find({'project': {'$in': all_public_project_ids}, 'name': {'$not': re.compile('untitled pattern', re.IGNORECASE)}, 'preview': {'$exists': True}}, {'project': 1, 'name': 1, 'createdAt': 1, 'preview': 1}).sort('createdAt', pymongo.DESCENDING).limit(20))
|
||||||
for object in objects:
|
for object in objects:
|
||||||
object['projectObject'] = project_map.get(object['project'])
|
object['projectObject'] = project_map.get(object['project'])
|
||||||
authors = list(db.users.find({'_id': {'$in': list(map(lambda o: o.get('projectObject', {}).get('user'), objects))}}, {'username': 1, 'avatar': 1}))
|
authors = list(db.users.find({'_id': {'$in': list(map(lambda o: o.get('projectObject', {}).get('user'), objects))}}, {'username': 1, 'avatar': 1}))
|
||||||
@ -96,6 +92,5 @@ def explore(page = 1):
|
|||||||
user_map[a['_id']] = a
|
user_map[a['_id']] = a
|
||||||
for object in objects:
|
for object in objects:
|
||||||
object['userObject'] = user_map.get(object.get('projectObject', {}).get('user'))
|
object['userObject'] = user_map.get(object.get('projectObject', {}).get('user'))
|
||||||
|
|
||||||
return {'objects': objects}
|
return {'objects': objects}
|
||||||
|
|
@ -265,15 +265,11 @@ def search_users():
|
|||||||
|
|
||||||
@app.route('/search/discover', methods=['GET'])
|
@app.route('/search/discover', methods=['GET'])
|
||||||
def search_discover():
|
def search_discover():
|
||||||
count = request.args.get('count', 3)
|
return util.jsonify(search.discover(util.get_user(required=True)))
|
||||||
if count: count = int(count)
|
|
||||||
return util.jsonify(search.discover(util.get_user(required=False), count=count))
|
|
||||||
|
|
||||||
@app.route('/search/explore', methods=['GET'])
|
@app.route('/search/explore', methods=['GET'])
|
||||||
def search_explore():
|
def search_explore():
|
||||||
page = request.args.get('page', 1)
|
return util.jsonify(search.explore())
|
||||||
if page: page = int(page)
|
|
||||||
return util.jsonify(search.explore(page=page))
|
|
||||||
|
|
||||||
# INVITATIONS
|
# INVITATIONS
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ export default {
|
|||||||
|
|
||||||
RECEIVE_OBJECTS: 'RECEIVE_OBJECTS',
|
RECEIVE_OBJECTS: 'RECEIVE_OBJECTS',
|
||||||
RECEIVE_OBJECT: 'RECEIVE_OBJECT',
|
RECEIVE_OBJECT: 'RECEIVE_OBJECT',
|
||||||
RECEIVE_EXPLORE_OBJECTS: 'RECEIVE_EXPLORE_OBJECTS',
|
|
||||||
CREATE_OBJECT: 'CREATE_OBJECT',
|
CREATE_OBJECT: 'CREATE_OBJECT',
|
||||||
UPDATE_OBJECT: 'UPDATE_OBJECT',
|
UPDATE_OBJECT: 'UPDATE_OBJECT',
|
||||||
DELETE_OBJECT: 'DELETE_OBJECT',
|
DELETE_OBJECT: 'DELETE_OBJECT',
|
||||||
@ -19,10 +18,6 @@ export default {
|
|||||||
return { type: this.RECEIVE_OBJECT, object };
|
return { type: this.RECEIVE_OBJECT, object };
|
||||||
},
|
},
|
||||||
|
|
||||||
receiveExplore(objects) {
|
|
||||||
return { type: this.RECEIVE_EXPLORE_OBJECTS, objects };
|
|
||||||
},
|
|
||||||
|
|
||||||
create(object) {
|
create(object) {
|
||||||
return { type: this.CREATE_OBJECT, object };
|
return { type: this.CREATE_OBJECT, object };
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,6 @@ export default {
|
|||||||
REQUEST_USERS: 'REQUEST_USERS',
|
REQUEST_USERS: 'REQUEST_USERS',
|
||||||
REQUEST_FAILED: 'REQUEST_FAILED',
|
REQUEST_FAILED: 'REQUEST_FAILED',
|
||||||
RECEIVE_USER: 'RECEIVE_USERS',
|
RECEIVE_USER: 'RECEIVE_USERS',
|
||||||
RECEIVE_EXPLORE: 'RECEIVE_EXPLORE',
|
|
||||||
UPDATE_USER: 'UPDATE_USER',
|
UPDATE_USER: 'UPDATE_USER',
|
||||||
UPDATE_USERNAME: 'UPDATE_USERNAME',
|
UPDATE_USERNAME: 'UPDATE_USERNAME',
|
||||||
JOIN_GROUP: 'JOIN_GROUP',
|
JOIN_GROUP: 'JOIN_GROUP',
|
||||||
@ -35,10 +34,6 @@ export default {
|
|||||||
return { type: this.RECEIVE_USER, user };
|
return { type: this.RECEIVE_USER, user };
|
||||||
},
|
},
|
||||||
|
|
||||||
receiveExplore(users) {
|
|
||||||
return { type: this.RECEIVE_EXPLORE, users };
|
|
||||||
},
|
|
||||||
|
|
||||||
update(id, data) {
|
update(id, data) {
|
||||||
return { type: this.UPDATE_USER, id, data };
|
return { type: this.UPDATE_USER, id, data };
|
||||||
},
|
},
|
||||||
|
@ -7,10 +7,10 @@ export const search = {
|
|||||||
users(username, success, fail) {
|
users(username, success, fail) {
|
||||||
api.authenticatedRequest('GET', `/search/users?username=${username}`, null, data => success && success(data.users), fail);
|
api.authenticatedRequest('GET', `/search/users?username=${username}`, null, data => success && success(data.users), fail);
|
||||||
},
|
},
|
||||||
discover(count, success, fail) {
|
discover(success, fail) {
|
||||||
api.authenticatedRequest('GET', `/search/discover?count=${count || 3}`, null, data => success && success(data), fail);
|
api.authenticatedRequest('GET', `/search/discover`, null, data => success && success(data), fail);
|
||||||
},
|
},
|
||||||
explore(page, success, fail) {
|
explore(success, fail) {
|
||||||
api.unauthenticatedRequest('GET', `/search/explore?page=${page || 1}`, null, data => success && success(data), fail);
|
api.unauthenticatedRequest('GET', `/search/explore`, null, data => success && success(data), fail);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -79,12 +79,6 @@ function App() {
|
|||||||
api.auth.autoLogin(token => dispatch(actions.auth.receiveLogin(token)));
|
api.auth.autoLogin(token => dispatch(actions.auth.receiveLogin(token)));
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
api.search.explore(1, data => { // Page is always 1 on app-load
|
|
||||||
dispatch(actions.objects.receiveExplore(data.objects));
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loggedInUserId) return;
|
if (!loggedInUserId) return;
|
||||||
api.users.getMyProjects(p => dispatch(actions.projects.receiveProjects(p)));
|
api.users.getMyProjects(p => dispatch(actions.projects.receiveProjects(p)));
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import { Card, List } from 'semantic-ui-react';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import UserChip from './UserChip';
|
|
||||||
import api from '../../api';
|
|
||||||
import utils from '../../utils/utils.js';
|
|
||||||
|
|
||||||
export default function ExploreCard({ count }) {
|
|
||||||
const [highlightProjects, setHighlightProjects] = useState([]);
|
|
||||||
const [highlightUsers, setHighlightUsers] = useState([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
api.search.discover(count || 3, ({ highlightProjects, highlightUsers }) => {
|
|
||||||
setHighlightProjects(highlightProjects);
|
|
||||||
setHighlightUsers(highlightUsers);
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if ((highlightProjects?.length === 0 || highlightUsers?.length === 0)) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card fluid>
|
|
||||||
<Card.Content>
|
|
||||||
{highlightProjects?.length > 0 && <>
|
|
||||||
<h4>Discover a project</h4>
|
|
||||||
<List relaxed>
|
|
||||||
{highlightProjects.map(p =>
|
|
||||||
<List.Item key={p._id}>
|
|
||||||
<List.Icon name='book' size='large' verticalAlign='middle' />
|
|
||||||
<List.Content>
|
|
||||||
<List.Header className='umami--click--discover-project' as={Link} to={`/${p.fullName}`}>{p.name}</List.Header>
|
|
||||||
</List.Content>
|
|
||||||
</List.Item>
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
</>}
|
|
||||||
|
|
||||||
{highlightUsers?.length > 0 && <>
|
|
||||||
<h4>Find others on {utils.appName()}</h4>
|
|
||||||
<List relaxed>
|
|
||||||
{highlightUsers.map(u =>
|
|
||||||
<List.Item key={u._id}>
|
|
||||||
<List.Content>
|
|
||||||
<UserChip user={u} className='umami--click--discover-user'/>
|
|
||||||
</List.Content>
|
|
||||||
</List.Item>
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
</>}
|
|
||||||
</Card.Content>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
@ -12,10 +12,11 @@ import UserChip from '../includes/UserChip';
|
|||||||
import HelpLink from '../includes/HelpLink';
|
import HelpLink from '../includes/HelpLink';
|
||||||
import ProjectCard from '../includes/ProjectCard';
|
import ProjectCard from '../includes/ProjectCard';
|
||||||
import Tour from '../includes/Tour';
|
import Tour from '../includes/Tour';
|
||||||
import DiscoverCard from '../includes/DiscoverCard';
|
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
const [runJoyride, setRunJoyride] = useState(false);
|
const [runJoyride, setRunJoyride] = useState(false);
|
||||||
|
const [highlightProjects, setHighlightProjects] = useState([]);
|
||||||
|
const [highlightUsers, setHighlightUsers] = useState([]);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { user, projects, groups, invitations, loadingProjects } = useSelector(state => {
|
const { user, projects, groups, invitations, loadingProjects } = useSelector(state => {
|
||||||
const user = state.users.users.filter(u => state.auth.currentUserId === u._id)[0];
|
const user = state.users.users.filter(u => state.auth.currentUserId === u._id)[0];
|
||||||
@ -29,6 +30,10 @@ function Home() {
|
|||||||
api.invitations.get(({ invitations, sentInvitations}) => {
|
api.invitations.get(({ invitations, sentInvitations}) => {
|
||||||
dispatch(actions.invitations.receiveInvitations(invitations.concat(sentInvitations)));
|
dispatch(actions.invitations.receiveInvitations(invitations.concat(sentInvitations)));
|
||||||
});
|
});
|
||||||
|
api.search.discover(({ highlightProjects, highlightUsers }) => {
|
||||||
|
setHighlightProjects(highlightProjects);
|
||||||
|
setHighlightUsers(highlightUsers);
|
||||||
|
});
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api.users.getMyProjects(p => dispatch(actions.projects.receiveProjects(p)));
|
api.users.getMyProjects(p => dispatch(actions.projects.receiveProjects(p)));
|
||||||
@ -87,7 +92,38 @@ function Home() {
|
|||||||
|
|
||||||
<h2><span role="img" aria-label="wave">👋</span> {greeting}{user && <span>, {user.username}</span>}</h2>
|
<h2><span role="img" aria-label="wave">👋</span> {greeting}{user && <span>, {user.username}</span>}</h2>
|
||||||
|
|
||||||
<DiscoverCard count={3} />
|
{(highlightProjects?.length > 0 || highlightUsers?.length > 0) &&
|
||||||
|
<Card fluid>
|
||||||
|
<Card.Content>
|
||||||
|
{highlightProjects?.length > 0 && <>
|
||||||
|
<h4>Discover public projects</h4>
|
||||||
|
<List relaxed>
|
||||||
|
{highlightProjects.map(p =>
|
||||||
|
<List.Item key={p._id}>
|
||||||
|
<List.Icon name='book' size='large' verticalAlign='middle' />
|
||||||
|
<List.Content>
|
||||||
|
<List.Header className='umami--click--discover-project' as={Link} to={p.fullName}>{p.name}</List.Header>
|
||||||
|
</List.Content>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</>}
|
||||||
|
|
||||||
|
{highlightUsers?.length > 0 && <>
|
||||||
|
<h4>Find others on {utils.appName()}</h4>
|
||||||
|
<List relaxed>
|
||||||
|
{highlightUsers.map(u =>
|
||||||
|
<List.Item key={u._id}>
|
||||||
|
<List.Content>
|
||||||
|
<UserChip user={u} className='umami--click--discover-user'/>
|
||||||
|
</List.Content>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</>}
|
||||||
|
</Card.Content>
|
||||||
|
</Card>
|
||||||
|
}
|
||||||
|
|
||||||
{(groups && groups.length) ?
|
{(groups && groups.length) ?
|
||||||
<Card fluid className='joyride-groups' style={{opacity: 0.8}}>
|
<Card fluid className='joyride-groups' style={{opacity: 0.8}}>
|
||||||
|
@ -1,45 +1,28 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Container, Card, Grid, Button } from 'semantic-ui-react';
|
import { Container, Card } from 'semantic-ui-react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
|
||||||
import actions from '../../../actions';
|
|
||||||
import api from '../../../api';
|
import api from '../../../api';
|
||||||
import utils from '../../../utils/utils.js';
|
import utils from '../../../utils/utils.js';
|
||||||
|
|
||||||
import UserChip from '../../includes/UserChip';
|
import UserChip from '../../includes/UserChip';
|
||||||
import DiscoverCard from '../../includes/DiscoverCard';
|
|
||||||
import DraftPreview from '../projects/objects/DraftPreview';
|
import DraftPreview from '../projects/objects/DraftPreview';
|
||||||
|
|
||||||
export default function Explore() {
|
export default function Explore() {
|
||||||
|
const [objects, setObjects] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const dispatch = useDispatch();
|
|
||||||
|
|
||||||
const { objects, page } = useSelector(state => {
|
|
||||||
return { objects: state.objects.exploreObjects, page: state.objects.explorePage };
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (page < 2) loadMoreExplore();
|
api.search.explore(data => {
|
||||||
}, []);
|
setObjects(data.objects);
|
||||||
|
|
||||||
function loadMoreExplore() {
|
|
||||||
setLoading(true);
|
|
||||||
api.search.explore(page + 1, data => {
|
|
||||||
dispatch(actions.objects.receiveExplore(data.objects));
|
|
||||||
setLoading(false);
|
|
||||||
});
|
});
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container style={{ marginTop: '40px' }}>
|
<Container style={{ marginTop: '40px' }}>
|
||||||
<Grid stackable>
|
<h1>Explore {utils.appName()}</h1>
|
||||||
<Grid.Column computer={5} tablet={8}>
|
|
||||||
<DiscoverCard count={7} />
|
<Card.Group stackable doubling itemsPerRow={4}>
|
||||||
</Grid.Column>
|
|
||||||
<Grid.Column computer={11} tablet={8}>
|
|
||||||
<h1>Recent patterns on {utils.appName()}</h1>
|
|
||||||
|
|
||||||
<Card.Group stackable doubling itemsPerRow={3} style={{marginTop: 30}}>
|
|
||||||
{objects?.filter(o => o.projectObject && o.userObject).map(object =>
|
{objects?.filter(o => o.projectObject && o.userObject).map(object =>
|
||||||
<Card raised key={object._id} style={{ cursor: 'pointer' }} as={Link} to={`/${object.userObject?.username}/${object.projectObject?.path}/${object._id}`}>
|
<Card raised key={object._id} style={{ cursor: 'pointer' }} as={Link} to={`/${object.userObject?.username}/${object.projectObject?.path}/${object._id}`}>
|
||||||
<div style={{ height: 200, backgroundImage: `url(${object.preview})`, backgroundSize: 'cover', backgroundPosition: 'top right', position: 'relative' }}>
|
<div style={{ height: 200, backgroundImage: `url(${object.preview})`, backgroundSize: 'cover', backgroundPosition: 'top right', position: 'relative' }}>
|
||||||
@ -58,11 +41,7 @@ export default function Explore() {
|
|||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
</Card.Group>
|
</Card.Group>
|
||||||
<div style={{display: 'flex', justifyContent: 'center', marginTop: 30}}>
|
|
||||||
<Button loading={loading} onClick={loadMoreExplore}>Load more</Button>
|
|
||||||
</div>
|
|
||||||
</Grid.Column>
|
|
||||||
</Grid>
|
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -119,7 +119,7 @@ function ObjectViewer() {
|
|||||||
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'end' }}>
|
<div style={{ display: 'flex', justifyContent: 'end' }}>
|
||||||
{object.type === 'pattern' && (project.user === (user && user._id) || project.openSource || object.preview) && <>
|
{object.type === 'pattern' && (project.user === (user && user._id) || project.openSource || object.preview) && <>
|
||||||
<Dropdown direction='left' icon={null} trigger={<Button size='small' secondary icon='download' content='Download pattern' loading={downloading} disabled={downloading}/>}>
|
<Dropdown icon={null} trigger={<Button size='small' secondary icon='download' content='Download pattern' loading={downloading} disabled={downloading}/>}>
|
||||||
<Dropdown.Menu>
|
<Dropdown.Menu>
|
||||||
{object.preview &&
|
{object.preview &&
|
||||||
<Dropdown.Item onClick={e => downloadDrawdownImage(object)} content='Download drawdown as an image' icon='file outline' />
|
<Dropdown.Item onClick={e => downloadDrawdownImage(object)} content='Download drawdown as an image' icon='file outline' />
|
||||||
@ -136,14 +136,12 @@ function ObjectViewer() {
|
|||||||
</Dropdown.Menu>
|
</Dropdown.Menu>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
{user &&
|
|
||||||
<Dropdown icon={null} trigger={<Button size="small" icon="copy" secondary content="Copy to.." />}>
|
<Dropdown icon={null} trigger={<Button size="small" icon="copy" secondary content="Copy to.." />}>
|
||||||
<Dropdown.Menu>
|
<Dropdown.Menu>
|
||||||
<Dropdown.Header>Select a project to copy this pattern to</Dropdown.Header>
|
<Dropdown.Header>Select a project to copy this pattern to</Dropdown.Header>
|
||||||
{myProjects?.map(myProject => <Dropdown.Item content={myProject.name} onClick={e => copyPattern(myProject)} />)}
|
{myProjects?.map(myProject => <Dropdown.Item content={myProject.name} onClick={e => copyPattern(myProject)} />)}
|
||||||
</Dropdown.Menu>
|
</Dropdown.Menu>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
}
|
|
||||||
</>}
|
</>}
|
||||||
|
|
||||||
{utils.canEditProject(user, project) &&
|
{utils.canEditProject(user, project) &&
|
||||||
|
@ -3,8 +3,6 @@ import actions from '../actions';
|
|||||||
const initialState = {
|
const initialState = {
|
||||||
loading: false,
|
loading: false,
|
||||||
objects: [],
|
objects: [],
|
||||||
exploreObjects: [],
|
|
||||||
explorePage: 1,
|
|
||||||
comments: [],
|
comments: [],
|
||||||
selected: null,
|
selected: null,
|
||||||
editor: { tool: 'straight', colour: 'orange', view: 'interlacement' },
|
editor: { tool: 'straight', colour: 'orange', view: 'interlacement' },
|
||||||
@ -38,10 +36,6 @@ function objects(state = initialState, action) {
|
|||||||
});
|
});
|
||||||
if (!found) objects.push(action.object);
|
if (!found) objects.push(action.object);
|
||||||
return Object.assign({}, state, { loading: false, objects });
|
return Object.assign({}, state, { loading: false, objects });
|
||||||
case actions.objects.RECEIVE_EXPLORE_OBJECTS:
|
|
||||||
const newObjects = Object.assign([], state.exploreObjects);
|
|
||||||
action.objects?.forEach(o => newObjects.push(o));
|
|
||||||
return Object.assign({}, state, { exploreObjects: newObjects, explorePage: state.explorePage + 1 });
|
|
||||||
case actions.objects.CREATE_OBJECT:
|
case actions.objects.CREATE_OBJECT:
|
||||||
const objectList = state.objects;
|
const objectList = state.objects;
|
||||||
objectList.push(action.object);
|
objectList.push(action.object);
|
||||||
|
Loading…
Reference in New Issue
Block a user