Skip to content

Commit 39f8ae2

Browse files
pwjablonskioutoftime
authored andcommitted
Archive projects (#1485)
* update package lock * delete package lock * archive projects first pass reorder projects and add sticky button fix css unarchive archived project on project selection updates update changeCurrentProject update changeCurrentProject update tests update with project saved indicator update ui state fix tests update project picker and tests add i18next to projectpreview update to yarn * add /* eslint-disable complexity */ * remove else and destructure object * update tests and project picker * update project picker * update tests * update tests
1 parent 73328fa commit 39f8ae2

File tree

21 files changed

+332
-26
lines changed

21 files changed

+332
-26
lines changed

.vscode/launch.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "chrome",
9+
"request": "launch",
10+
"name": "Launch Chrome against localhost",
11+
"url": "http://localhost:8080",
12+
"webRoot": "${workspaceFolder}"
13+
}
14+
]
15+
}

locales/en/translation.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@
3232
"log-in-prompt": "Log in to save",
3333
"log-out-prompt": "Log out",
3434
"log-in-github": "Log in with GitHub"
35-
}
35+
},
36+
"hide-projects": "Hide Archived Projects",
37+
"show-projects": "Show Archived Projects",
38+
"project-archived": "Archived"
3639
},
3740
"editors": {
3841
"help-text": "Type in your $t(languages.{{language}}) code here."

src/actions/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
updateProjectSource,
2525
updateProjectInstructions,
2626
projectSuccessfullySaved,
27+
archiveProject,
2728
} from './projects';
2829

2930
import {
@@ -46,6 +47,7 @@ import {
4647
closeAssignmentCreator,
4748
coursesLoaded,
4849
coursesFullyLoaded,
50+
toggleArchivedView,
4951
} from './ui';
5052

5153
import {
@@ -143,4 +145,6 @@ export {
143145
closeAssignmentCreator,
144146
coursesLoaded,
145147
coursesFullyLoaded,
148+
archiveProject,
149+
toggleArchivedView,
146150
};

src/actions/projects.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,8 @@ export const projectsLoaded = createAction('PROJECTS_LOADED');
7777

7878
export const projectSuccessfullySaved =
7979
createAction('PROJECT_SUCCESSFULLY_SAVED');
80+
81+
export const archiveProject = createAction(
82+
'ARCHIVE_PROJECT',
83+
projectKey => ({projectKey}),
84+
);

src/actions/ui.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,7 @@ export const coursesLoaded = createAction(
8585
export const coursesFullyLoaded = createAction(
8686
'COURSES_FULLY_LOADED',
8787
);
88+
89+
export const toggleArchivedView = createAction(
90+
'TOGGLE_ARCHIVED_VIEW',
91+
);

src/components/ProjectPreview.jsx

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,56 @@
1+
import {faArchive} from '@fortawesome/free-solid-svg-icons';
2+
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
3+
import classnames from 'classnames';
14
import React from 'react';
25
import PropTypes from 'prop-types';
36
import moment from 'moment';
7+
import {t} from 'i18next';
48

59
const MAX_LENGTH = 50;
610

7-
export default function ProjectPreview({preview, project}) {
11+
export default function ProjectPreview({
12+
isCurrentProject,
13+
preview,
14+
project,
15+
onProjectArchived,
16+
}) {
817
return (
918
<div>
10-
<div className="project-preview__label">
11-
{preview.slice(0, MAX_LENGTH)}
19+
<div className="project-preview">
20+
<div
21+
className={classnames('project-preview__label', {
22+
'project-preview__label_archived': project.isArchived,
23+
})}
24+
>
25+
{preview.slice(0, MAX_LENGTH)}
26+
</div>
27+
{
28+
(function showArchived() {
29+
if (isCurrentProject) {
30+
return null;
31+
}
32+
if (project.isArchived) {
33+
return (
34+
<div
35+
className="project-preview__archived"
36+
>
37+
{t('top-bar.project-archived')}
38+
</div>
39+
);
40+
}
41+
return (
42+
<div
43+
className="project-preview__archive"
44+
onClick={(e) => {
45+
e.stopPropagation();
46+
onProjectArchived();
47+
}}
48+
>
49+
<FontAwesomeIcon icon={faArchive} />
50+
</div>
51+
);
52+
}())
53+
}
1254
</div>
1355
{project.updatedAt && (
1456
<div className="project-preview__timestamp">
@@ -20,6 +62,8 @@ export default function ProjectPreview({preview, project}) {
2062
}
2163

2264
ProjectPreview.propTypes = {
65+
isCurrentProject: PropTypes.bool.isRequired,
2366
preview: PropTypes.string.isRequired,
2467
project: PropTypes.object.isRequired,
68+
onProjectArchived: PropTypes.func.isRequired,
2569
};

src/components/TopBar/ProjectPicker.jsx

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import classnames from 'classnames';
12
import isEmpty from 'lodash-es/isEmpty';
3+
import some from 'lodash-es/some';
4+
import filter from 'lodash-es/filter';
25
import map from 'lodash-es/map';
36
import partial from 'lodash-es/partial';
47
import PropTypes from 'prop-types';
58
import React from 'react';
9+
import {t} from 'i18next';
610

711
import ProjectPreview from '../../containers/ProjectPreview';
812

@@ -23,8 +27,17 @@ const ProjectPicker = createMenu({
2327
isUserAuthenticated;
2428
},
2529

26-
renderItems({currentProjectKey, projectKeys, onChangeCurrentProject}) {
27-
return map(projectKeys, projectKey => (
30+
renderItems({
31+
currentProjectKey,
32+
projects,
33+
shouldShowArchivedProjects,
34+
onChangeCurrentProject,
35+
onToggleViewArchived,
36+
}) {
37+
const visibleProjects = shouldShowArchivedProjects ?
38+
projects :
39+
filter(projects, ({isArchived}) => !isArchived);
40+
const items = map(visibleProjects, ({projectKey}) => (
2841
<MenuItem
2942
isActive={projectKey === currentProjectKey}
3043
key={projectKey}
@@ -33,12 +46,37 @@ const ProjectPicker = createMenu({
3346
<ProjectPreview projectKey={projectKey} />
3447
</MenuItem>
3548
));
49+
50+
if (some(projects, 'isArchived')) {
51+
items.push(
52+
<div
53+
className={classnames(
54+
'top-bar__menu-item',
55+
'top-bar__menu-item_toggle-archived-projects-button',
56+
)}
57+
key="toggleShowArchivedProjects"
58+
onClick={onToggleViewArchived}
59+
>
60+
<div>
61+
{
62+
shouldShowArchivedProjects ?
63+
t('top-bar.hide-projects') :
64+
t('top-bar.show-projects')
65+
}
66+
</div>
67+
</div>,
68+
);
69+
}
70+
71+
return items;
3672
},
3773
})(ProjectPickerButton);
3874

3975
ProjectPicker.propTypes = {
4076
currentProjectKey: PropTypes.string,
41-
projectKeys: PropTypes.arrayOf(PropTypes.string).isRequired,
77+
projects: PropTypes.array.isRequired,
78+
shouldShowArchivedProjects: PropTypes.bool.isRequired,
79+
onToggleViewArchived: PropTypes.func.isRequired,
4280
};
4381

4482
ProjectPicker.defaultProps = {

src/components/TopBar/index.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ export default function TopBar({
5151
openMenu,
5252
projectKeys,
5353
shouldShowSavedIndicator,
54+
projects,
55+
shouldShowArchivedProjects,
5456
validationState,
5557
onChangeCurrentProject,
5658
onClickMenu,
@@ -68,6 +70,7 @@ export default function TopBar({
6870
onStartEditingInstructions,
6971
onToggleLibrary,
7072
onToggleTextSize,
73+
onToggleViewArchived,
7174
onUnlinkGitHub,
7275
onUpdateRepo,
7376
}) {
@@ -114,8 +117,11 @@ export default function TopBar({
114117
currentProjectKey={currentProjectKey}
115118
isUserAuthenticated={isUserAuthenticated}
116119
projectKeys={projectKeys}
120+
projects={projects}
121+
shouldShowArchivedProjects={shouldShowArchivedProjects}
117122
shouldShowSavedIndicator={shouldShowSavedIndicator}
118123
onChangeCurrentProject={onChangeCurrentProject}
124+
onToggleViewArchived={onToggleViewArchived}
119125
/>
120126
<CurrentUser
121127
isLoginAvailable={isGapiReady}
@@ -166,6 +172,8 @@ TopBar.propTypes = {
166172
isUserTyping: PropTypes.bool.isRequired,
167173
openMenu: PropTypes.string,
168174
projectKeys: PropTypes.arrayOf(PropTypes.string).isRequired,
175+
projects: PropTypes.array.isRequired,
176+
shouldShowArchivedProjects: PropTypes.bool.isRequired,
169177
shouldShowSavedIndicator: PropTypes.bool.isRequired,
170178
validationState: PropTypes.string.isRequired,
171179
onChangeCurrentProject: PropTypes.func.isRequired,
@@ -184,6 +192,7 @@ TopBar.propTypes = {
184192
onStartGoogleLogIn: PropTypes.func.isRequired,
185193
onToggleLibrary: PropTypes.func.isRequired,
186194
onToggleTextSize: PropTypes.func.isRequired,
195+
onToggleViewArchived: PropTypes.func.isRequired,
187196
onUnlinkGitHub: PropTypes.func.isRequired,
188197
onUpdateRepo: PropTypes.func.isRequired,
189198
};

src/containers/ProjectPreview.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import {connect} from 'react-redux';
22

33
import ProjectPreview from '../components/ProjectPreview';
4-
import {changeCurrentProject} from '../actions';
4+
import {
5+
archiveProject,
6+
changeCurrentProject,
7+
} from '../actions';
58
import {
69
makeGetProjectPreview,
710
getCurrentProjectKey,
@@ -14,7 +17,7 @@ function makeMapStateToProps() {
1417
return function mapStateToProps(state, {projectKey}) {
1518
return {
1619
preview: getProjectPreview(state, {projectKey}),
17-
isSelected: projectKey === getCurrentProjectKey(state),
20+
isCurrentProject: projectKey === getCurrentProjectKey(state),
1821
project: getProject(state, {projectKey}),
1922
};
2023
};
@@ -25,6 +28,9 @@ function mapDispatchToProps(dispatch, {projectKey}) {
2528
onProjectSelected() {
2629
dispatch(changeCurrentProject(projectKey));
2730
},
31+
onProjectArchived() {
32+
dispatch(archiveProject(projectKey));
33+
},
2834
};
2935
}
3036

src/containers/TopBar.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
getEnabledLibraries,
1111
getOpenTopBarMenu,
1212
getAllProjectKeys,
13+
getAllProjects,
14+
isArchivedViewOpen,
1315
isEditingInstructions,
1416
isExperimental,
1517
isGapiReady,
@@ -39,6 +41,7 @@ import {
3941
toggleEditorTextSize,
4042
toggleLibrary,
4143
toggleTopBarMenu,
44+
toggleArchivedView,
4245
logIn,
4346
logOut,
4447
} from '../actions';
@@ -50,6 +53,7 @@ function mapStateToProps(state) {
5053
enabledLibraries: getEnabledLibraries(state),
5154
hasInstructions: Boolean(getCurrentProjectInstructions(state)),
5255
hasExportedRepo: Boolean(getCurrentProjectExportedRepoName(state)),
56+
shouldShowArchivedProjects: isArchivedViewOpen(state),
5357
isEditingInstructions: isEditingInstructions(state),
5458
isExperimental: isExperimental(state),
5559
isGapiReady: isGapiReady(state),
@@ -66,6 +70,7 @@ function mapStateToProps(state) {
6670
isUserTyping: isUserTyping(state),
6771
openMenu: getOpenTopBarMenu(state),
6872
projectKeys: getAllProjectKeys(state),
73+
projects: getAllProjects(state),
6974
validationState: getCurrentValidationState(state),
7075
};
7176
}
@@ -147,6 +152,11 @@ function mapDispatchToProps(dispatch) {
147152
onToggleTextSize() {
148153
dispatch(toggleEditorTextSize());
149154
},
155+
156+
onToggleViewArchived() {
157+
dispatch(toggleArchivedView());
158+
},
159+
150160
};
151161
}
152162

0 commit comments

Comments
 (0)