diff --git a/apps/src/templates/projects/PersonalProjectsTable.jsx b/apps/src/templates/projects/PersonalProjectsTable.jsx
index 38d88b2dc1002..6f0a88a85746b 100644
--- a/apps/src/templates/projects/PersonalProjectsTable.jsx
+++ b/apps/src/templates/projects/PersonalProjectsTable.jsx
@@ -11,9 +11,8 @@ import {
personalProjectDataPropType,
FEATURED_PROJECT_TYPE_MAP,
} from './projectConstants';
-import QuickActionsCell from '../tables/QuickActionsCell';
import {tableLayoutStyles, sortableOptions} from "../tables/tableConstants";
-import PopUpMenu, {MenuBreak} from "@cdo/apps/lib/ui/PopUpMenu";
+import PersonalProjectsTableActionsCell from './PersonalProjectsTableActionsCell';
const PROJECT_DEFAULT_IMAGE = '/blockly/media/projects/project_default.png';
@@ -69,9 +68,6 @@ export const styles = {
justifyContent: 'center',
alignItems: 'center',
},
- xIcon: {
- paddingRight: 5,
- },
};
// Cell formatters.
@@ -96,40 +92,11 @@ const nameFormatter = (projectName, {rowData}) => {
const actionsFormatter = (actions, {rowData}) => {
return (
-
- console.log("Rename was clicked")}
- >
- {i18n.rename()}
-
- console.log("Remix was clicked")}
- >
- {i18n.remix()}
-
- {!!rowData.isPublished && (
- console.log("Unpublish was clicked")}
- >
- {i18n.unpublish()}
-
- )}
- {!rowData.isPublished && (
- console.log("Publish was clicked")}
- >
- {i18n.publish()}
-
- )}
-
- console.log("Delete was clicked")}
- color={color.red}
- >
-
- {i18n.delete()}
-
-
+
);
};
@@ -148,7 +115,7 @@ const publishedAtFormatter = (publishedAt) => {
class PersonalProjectsTable extends React.Component {
static propTypes = {
- personalProjectsList: PropTypes.arrayOf(personalProjectDataPropType).isRequired
+ personalProjectsList: PropTypes.arrayOf(personalProjectDataPropType).isRequired,
};
state = {
diff --git a/apps/src/templates/projects/PersonalProjectsTable.story.jsx b/apps/src/templates/projects/PersonalProjectsTable.story.jsx
index 6b3414364d828..2a5db47af3a1d 100644
--- a/apps/src/templates/projects/PersonalProjectsTable.story.jsx
+++ b/apps/src/templates/projects/PersonalProjectsTable.story.jsx
@@ -5,6 +5,7 @@ import {stubFakePersonalProjectData} from './generateFakeProjects';
export default storybook => {
storybook
.storiesOf('Projects/PersonalProjectsTable', module)
+ .withReduxStore()
.addStoryTable([
{
name: 'Personal Project Table',
diff --git a/apps/src/templates/projects/PersonalProjectsTableActionsCell.jsx b/apps/src/templates/projects/PersonalProjectsTableActionsCell.jsx
new file mode 100644
index 0000000000000..3a6088479a5e5
--- /dev/null
+++ b/apps/src/templates/projects/PersonalProjectsTableActionsCell.jsx
@@ -0,0 +1,80 @@
+import React, {Component, PropTypes} from 'react';
+import {connect} from 'react-redux';
+import QuickActionsCell from "../tables/QuickActionsCell";
+import PopUpMenu, {MenuBreak} from "@cdo/apps/lib/ui/PopUpMenu";
+import color from "../../util/color";
+import FontAwesome from '../FontAwesome';
+import i18n from '@cdo/locale';
+import {showPublishDialog} from './publishDialog/publishDialogRedux';
+
+export const styles = {
+ xIcon: {
+ paddingRight: 5,
+ },
+};
+
+class PersonalProjectsTableActionsCell extends Component {
+ static propTypes = {
+ isPublished: PropTypes.bool.isRequired,
+ projectId: PropTypes.string.isRequired,
+ projectType: PropTypes.string.isRequired,
+ showPublishDialog: PropTypes.func.isRequired,
+ };
+
+ state = {
+ deleting: false,
+ publishing: false,
+ unpublishing: false,
+ renaming: false,
+ remixing: false
+ };
+
+ onPublish = () => {
+ this.props.showPublishDialog(this.props.projectId, this.props.projectType);
+ };
+
+ render() {
+ return (
+
+ console.log("Rename was clicked")}
+ >
+ {i18n.rename()}
+
+ console.log("Remix was clicked")}
+ >
+ {i18n.remix()}
+
+ {this.props.isPublished && (
+ console.log("Unpublish was clicked")}
+ >
+ {i18n.unpublish()}
+
+ )}
+ {!this.props.isPublished && (
+
+ {i18n.publish()}
+
+ )}
+
+ console.log("Delete was clicked")}
+ color={color.red}
+ >
+
+ {i18n.delete()}
+
+
+ );
+ }
+}
+
+export default connect(state => ({}), dispatch => ({
+ showPublishDialog(projectId, projectType) {
+ dispatch(showPublishDialog(projectId, projectType));
+ },
+}))(PersonalProjectsTableActionsCell);
diff --git a/apps/src/templates/projects/projectsRedux.js b/apps/src/templates/projects/projectsRedux.js
index 41b0bf4c4ec17..2681c24867d2a 100644
--- a/apps/src/templates/projects/projectsRedux.js
+++ b/apps/src/templates/projects/projectsRedux.js
@@ -2,7 +2,7 @@
import { combineReducers } from 'redux';
import _ from 'lodash';
import { Galleries } from './projectConstants';
-
+import {PUBLISH_SUCCESS} from './publishDialog/publishDialogRedux';
// Action types
const TOGGLE_GALLERY = 'projects/TOGGLE_GALLERY';
@@ -92,6 +92,18 @@ function personalProjectsList(state = initialPersonalProjectsList, action) {
...state,
projects: action.personalProjectsList,
};
+ case PUBLISH_SUCCESS:
+ var channelOfInterest = action.lastPublishedProjectData.channel;
+
+ var publishedProjectIndex = state.projects.findIndex(project => project.channel === channelOfInterest);
+
+ var updatedProjects = [...state.projects];
+ updatedProjects[publishedProjectIndex].publishedAt = action.lastPublishedAt;
+
+ return {
+ ...state,
+ projects: updatedProjects
+ };
default:
return state;
}
@@ -151,3 +163,8 @@ export function setHasOlderProjects(hasOlderProjects, projectType) {
export function setPersonalProjectsList(personalProjectsList) {
return {type: SET_PERSONAL_PROJECTS_LIST, personalProjectsList};
}
+
+export function publishSuccess(lastPublishedAt, lastPublishedProjectData) {
+ return {type: PUBLISH_SUCCESS, lastPublishedAt,
+ lastPublishedProjectData};
+}
diff --git a/apps/src/templates/projects/publishDialog/publishDialogRedux.js b/apps/src/templates/projects/publishDialog/publishDialogRedux.js
index fb20c3f6e3b53..9db4eb75e820d 100644
--- a/apps/src/templates/projects/publishDialog/publishDialogRedux.js
+++ b/apps/src/templates/projects/publishDialog/publishDialogRedux.js
@@ -6,9 +6,9 @@ import { AllPublishableProjectTypes } from '../../../util/sharedConstants';
const SHOW_PUBLISH_DIALOG = 'publishDialog/SHOW_PUBLISH_DIALOG';
const HIDE_PUBLISH_DIALOG = 'publishDialog/HIDE_PUBLISH_DIALOG';
-export const PUBLISH_REQUEST = 'shareDialog/PUBLISH_REQUEST';
-export const PUBLISH_SUCCESS = 'shareDialog/PUBLISH_SUCCESS';
-export const PUBLISH_FAILURE = 'shareDialog/PUBLISH_FAILURE';
+export const PUBLISH_REQUEST = 'publishDialog/PUBLISH_REQUEST';
+export const PUBLISH_SUCCESS = 'publishDialog/PUBLISH_SUCCESS';
+export const PUBLISH_FAILURE = 'publishDialog/PUBLISH_FAILURE';
// Reducer
diff --git a/apps/test/unit/templates/projects/PersonalProjectsTableTest.js b/apps/test/unit/templates/projects/PersonalProjectsTableTest.js
index 8cc9ce2536127..f0126c487e062 100644
--- a/apps/test/unit/templates/projects/PersonalProjectsTableTest.js
+++ b/apps/test/unit/templates/projects/PersonalProjectsTableTest.js
@@ -1,27 +1,31 @@
import React from 'react';
import {mount} from 'enzyme';
import {expect} from '../../../util/configuredChai';
+import {Provider} from 'react-redux';
+import {getStore} from '@cdo/apps/redux';
import {UnconnectedPersonalProjectsTable as PersonalProjectsTable} from '@cdo/apps/templates/projects/PersonalProjectsTable';
import {stubFakePersonalProjectData} from '@cdo/apps/templates/projects/generateFakeProjects';
describe('PersonalProjectsTable', () => {
it('renders a table', () => {
const wrapper = mount(
-
+
+
+
);
-
expect(wrapper.find('table').exists()).to.be.true;
});
it('renders projects as table rows', () => {
const wrapper = mount(
-
+
+
+
);
-
const projectRows = wrapper.find('tbody').find('tr');
expect(projectRows).to.have.length(stubFakePersonalProjectData.length);
});
diff --git a/apps/test/unit/templates/projects/projectsReduxTest.js b/apps/test/unit/templates/projects/projectsReduxTest.js
index 56655523f8b9c..e39c67aaf1a2d 100644
--- a/apps/test/unit/templates/projects/projectsReduxTest.js
+++ b/apps/test/unit/templates/projects/projectsReduxTest.js
@@ -1,6 +1,7 @@
import { assert } from '../../../util/configuredChai';
import projects, {
setPersonalProjectsList,
+ publishSuccess,
} from '@cdo/apps/templates/projects/projectsRedux';
import {stubFakePersonalProjectData} from '@cdo/apps/templates/projects/generateFakeProjects';
@@ -15,4 +16,14 @@ describe('projectsRedux', () => {
});
});
+ describe('publishSuccess', () => {
+ it('sets the publishedAt field for the recently published project', () => {
+ const action = setPersonalProjectsList(stubFakePersonalProjectData);
+ const nextState = projects(initialState, action);
+ const nextAction = publishSuccess('2016-11-30T23:59:59.999-08:00', {channel: 'abcd2'});
+ const nextNextState = projects(nextState, nextAction);
+ assert.deepEqual(nextNextState.personalProjectsList.projects[1].channel, 'abcd2');
+ assert.deepEqual(nextNextState.personalProjectsList.projects[1].publishedAt, '2016-11-30T23:59:59.999-08:00');
+ });
+ });
});
diff --git a/dashboard/db/schema.rb b/dashboard/db/schema.rb
index d6d01f31feace..85c473ec9c5d0 100644
--- a/dashboard/db/schema.rb
+++ b/dashboard/db/schema.rb
@@ -89,13 +89,13 @@
end
create_table "blocks", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci" do |t|
- t.string "name", null: false
- t.string "pool", null: false
+ t.string "name", null: false
+ t.string "pool", default: "", null: false
t.string "category"
t.text "config", limit: 65535
t.text "helper_code", limit: 65535
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.datetime "deleted_at"
t.index ["deleted_at"], name: "index_blocks_on_deleted_at", using: :btree
t.index ["pool", "name"], name: "index_blocks_on_pool_and_name", unique: true, using: :btree
diff --git a/pegasus/sites.v3/code.org/public/circuitplayground.md b/pegasus/sites.v3/code.org/public/circuitplayground.md
index 4d1e1acbe65bc..6250e756447ba 100644
--- a/pegasus/sites.v3/code.org/public/circuitplayground.md
+++ b/pegasus/sites.v3/code.org/public/circuitplayground.md
@@ -76,7 +76,7 @@ If you meet **all** of the eligibility requirements, you will qualify for a subs
* **For teachers in schools with 40% or greater free/reduced price meals,** the classroom kit will be 100% subsidized, resulting in no cost to the teacher/school, including shipping.
* **For teachers at schools with less than 40% free/reduced price meals,** the classroom kit will not be subsidized. Teachers will be expected to pay for the full cost of the kit (approx. $350), though this price will be reduced by a 10% discount for educators to an approximate total of $315. To get the educator discount, teachers must apply the code ADAEDU at checkout.
-If a teacher has a smaller class size and does not qualify for or need a full 15 board kit (which supports 30 students), they may purchase a Code.org Circuit Playground Individual Kit. The Individual Kit is designed for a single student or share-pair, costs $29.95, and is also eligible for the 10% educator discount.
+If a teacher has a smaller class size and does not qualify for or need a full 15 board kit (which supports 30 students), they may purchase a Code.org Circuit Playground Individual Kit. The Individual Kit is designed for a single student or share-pair, costs $29.95.
**In January 2019,** teachers will receive an email from us with more information about how to request a subsidy for the Adafruit Circuit Playground classroom kit on our website. In the meantime, qualified teachers should make sure they're on track in the 2018-19 school year to complete the first semester of CS Discoveries (Units 1-3) with their students.
diff --git a/pegasus/sites.v3/hourofcode.com/public/international-partners.md b/pegasus/sites.v3/hourofcode.com/public/international-partners.md
index 2ad8c37c74165..0758903772b88 100644
--- a/pegasus/sites.v3/hourofcode.com/public/international-partners.md
+++ b/pegasus/sites.v3/hourofcode.com/public/international-partners.md
@@ -32,9 +32,9 @@ You, too, can play a leading role to get more people in your country involved! I
| Bangladesh | CodeLab | Enayet Chowdhury | www.codelab-online.com |
| Brazil | Programaê! - Fundaçao Lemann | | http://programae.org.br/horadocodigo |
| Cameroon | Big IT Company Ltd | | |
-| Canada | Brilliant Labs Inc. | | https://www.brilliantlabs.ca/ |
+| Canada | Brilliant Labs Inc. | | https://www.brilliantlabs.ca |
| Canada | Hatch Canada | | www.hatchcanada.com |
-| Canada | Canada Learning Code | Carolyn Van | https://www.canadalearningcode.ca/ |
+| Canada | Canada Learning Code | Carolyn Van | https://www.canadalearningcode.ca |
| Canada | Actua | Tracy Ross | www.actua.ca |
| Canada | Kids & Code | | www.kidsandcode.org
hello@kidsandcode.org |
| Canada | Kids Code Jeunesse | Bry LeBlanc | http://kidscodejeunesse.org
contact@kidscodejeunesse.org |
@@ -43,17 +43,17 @@ You, too, can play a leading role to get more people in your country involved! I
| Canada | Sault Ste. Marie innovation Centre | | https://ssmic.com/ |
| Chile | Fundación Kodea | Claudia Jaña | http://horadelcodigo.cl
cjana@kodea.org |
| China | 码趣学院CodingMarch | Delia Wu | www.codingmarch.com
delia.wu@codingmarch.com |
-| China | Classroom Aid, Inc. | | http://classroom-aid.com/CS4Good/ |
-| Colombia (also Brazil, Mexico, Spain) | World Tech Makers | Ilana Milkes | http://worldtechmakers.com/
ilana@worldtechmakers.com |
-| Czech Republic | Czechitas | Pavla Randakova | https://czechitas.cz/en/
paja@czechitas.cz |
+| China | Classroom Aid, Inc. | | http://classroom-aid.com/CS4Good |
+| Colombia (also Brazil, Mexico, Spain) | World Tech Makers | Ilana Milkes | http://worldtechmakers.com
ilana@worldtechmakers.com |
+| Czech Republic | Czechitas | Pavla Randakova | https://czechitas.cz
paja@czechitas.cz |
| Egypt | Q-STEAM Club | Tamer Ragab | http://q-steam.com
learn@q-steam.com |
-| Estonia | Vaata Maailma SA | Kristi Kivilo | http://www.vaatamaailma.ee/
kristi@vaatamaailma.ee |
-| Georgia | Educare Georgia | George Jibladze
Razmik Badalyan | http://www.educaregeorgia.org/
gjibladze@educaregeorgia.com
rbadalyan@educaregeorgia.com |
+| Estonia | Vaata Maailma SA | Kristi Kivilo | http://www.vaatamaailma.ee
kristi@vaatamaailma.ee |
+| Georgia | Educare Georgia | George Jibladze
Razmik Badalyan | http://www.educaregeorgia.org
gjibladze@educaregeorgia.com
rbadalyan@educaregeorgia.com |
| Ghana | Ghana Code Club | Ernestina Edem Appiah | www.ghanacodeclub.org
tinasupport@gmail.com |
| Hong Kong | Idea Maker HK | Henry Lee | www.ideamakerhk.com
henrylee@i3dprinter.com.hk |
| Hong Kong | IAMAI Academy (Hong Kong) Ltd | Johnson Chu | www.iamai.hk
johnson.chu@iamai.hk |
| India | CodeTigers | Sandeep Sheokand | sandeep.sheokand@gmail.com |
-| India | Mozilla Indore | Mrinal Jain | http://www.mozillaindore.org/
jain.mrinal140@gmail.com |
+| India | Mozilla Indore | Mrinal Jain | http://www.mozillaindore.org
jain.mrinal140@gmail.com |
| India | RIshs International School | | www.rishsinternationalschool.com
principal@rishsinternationalschool.com |
| India | Be Cre8v | | www.becre8v.com
sandeep@becre8v.com |
| Ireland | Cybersmarties.com | Diarmuid Hudner | www.cybersmarties.com
diarmuid@cybersmarties.com |
@@ -61,40 +61,41 @@ You, too, can play a leading role to get more people in your country involved! I
| Japan | 特定非営利活動法人みんなのコード (Code for Everyone) | 利根川 裕太 (Yuta Tonegawa) | info@code.or.jp |
| Japan | 湘南ゼミナール (Shonan Seminar) | Team Hour of Code | https://shozemi.com |
| Kazakhstan | Love to Code | Alyona Tkachenko | alyona@lovetocode.kz |
-| Kenya | Uzima Aid | Nicholas Juma | http://www.uzimaid.org/
nicholasjuma@uzimaid.org |
-| Malaysia | Malaysia Digital Economy Corporation (MDEC) | Mohamad Zulfadli Mohd Amin | https://www.mdec.my/
zulfadli.amin@mdec.com.my |
+| Kenya | Uzima Aid | Nicholas Juma | http://www.uzimaid.org
nicholasjuma@uzimaid.org |
+| Malaysia | Malaysia Digital Economy Corporation (MDEC) | Mohamad Zulfadli Mohd Amin | https://www.mdec.my
zulfadli.amin@mdec.com.my |
| Malaysia | Telebort Technologies Sdn Bhd | | www.telebort.com |
| Mexico | Cuantrix - Fundación Televisa | Nomara Parra | www.cuantrix.mx
cuantrix@fundaciontelevisa.org |
| Morocco | S.T.E.M ROBOTICS AGADIR | Dr. Isha Daramy | www.stemagadir.com
Stemagadir@gmail.com |
| New Zealand | Ara Institute of Canterbury | Amitrajit Sarkar | www.ara.ac.nz
sarkara@cpit.ac.nz |
| New Zealand | Google | Sally-Ann Williams | https://www.google.com/edu/cs |
+| New Zealand | OMGTech! | Vivian Chandra | https://omgtech.co.nz
viv@omgtech.co.nz
| Nigeria | CODE4KT- coding for kids & teens | Mayokun Odusote | www.code4kt.com
odusotemayokun@gmail.com |
-| Nigeria | Dev's District Nigeria | Emmanuel Odunlade | http://devsdistrictnigeria.com/
E.odunlade@devsdistrictnigeria.com |
+| Nigeria | Dev's District Nigeria | Emmanuel Odunlade | http://devsdistrictnigeria.com
E.odunlade@devsdistrictnigeria.com |
| Nigeria | Odyssey Educational Foundation | Stella Uzochukwu-Denis | www.odysseyedufoundation.org
ifywayne@gmail.com |
| Nigeria | KodeHauz | Glory Agatevure | http://www.kodehauz.com |
| Nigeria | The Zariah Elizabeth Foundation | Akindayo Akindolani | www.tzefoundation.org
dayo@tzefoundation.org |
| Norway | Lær Kidsa Koding | Line Moseng | https://kidsakoder.no |
| Oman | Engineering Village | | www.ev-center.com |
-| Pakistan | KnowledgeJump | Nasir Farhat Khan | http://www.knowledgejump.net/
nasir@knowledgejump.net |
+| Pakistan | KnowledgeJump | Nasir Farhat Khan | http://www.knowledgejump.net
nasir@knowledgejump.net |
| Pakistan | TechValley | Dr. Waqar S. Qureshi | |
-| Peru | Code en mi Cole | Renzo Sousa | http://codenmicole.com/ |
-| Philippines | The Startup Deck Balanga | Mark Colentava | www.techinbataan.com
mark@colentava.com |
+| Peru | Code en mi Cole | Renzo Sousa | http://codenmicole.com |
+| Philippines | The Startup Deck Balanga | Mark Colentava | http://www.startupbataan.com
mark@colentava.com |
| Poland | UMK Toruń | Maciej M. Sysło | http://godzinakodowania.pl
syslo@ii.uni.wroc.pl |
-| Portugal | Colégio EFANOR | | http://www.colegioefanor.pt/pt/ |
+| Portugal | Colégio EFANOR | | http://www.colegioefanor.pt/pt |
| Portugal | Gabinete de Modernização das Tecnologias Educativas | Rodolfo Pinto | http://www02.madeira-edu.pt/dre/main.aspx |
| Romania | ADFABER | Alin Chiriac | alin@adfaber.org |
-| Singapore | Infocomm Media Development Authority of Singapore | | https://www.imda.gov.sg/ |
-| South Korea | Korea Information Science Education Federation | | http://kcode.kr/
hwankim92@gmail.com |
+| Singapore | Infocomm Media Development Authority of Singapore | | https://www.imda.gov.sg |
+| South Korea | Korea Information Science Education Federation | | http://kcode.kr
hwankim92@gmail.com |
| Spain | Acludi | Juana Martínez | www.acludi.blogspot.com
acludi@yahoo.com |
| Spain | CSTA Spain | Santiago Fernández-Cabaleiro | www.aapri.es
santiagocabaleiro@gmail.com |
| Spain | Informatics Faculty - University of the Basque Country (UPV/EHU) | Edurne Larraza Mendiluze | https://www.ehu.eus/en/web/informatika-fakultatea/home
edurne.larraza@ehu.eus |
| Sri Lanka | XiCigny | Dileepa Rajapaksa | dileepa@xicigny.com |
| Sweden | Edvira | | http://edvira.com
hoc@edvira.com |
-| Taiwan | Girls in Tech Taiwan | Jane Shih | https://facebook.com/girlsintechtaiwan/
Jane.shih@girlsintech.org |
+| Taiwan | Girls in Tech Taiwan | Jane Shih | https://facebook.com/girlsintechtaiwan
Jane.shih@girlsintech.org |
| Taiwan | Women Who Code Taipei | Jane Shih | https://www.womenwhocode.com/taipei
Janeshih@womenwhocode.com |
| Thailand | Aksorn Education PLC | Weena Naowaprateep | www.aksorn.com
weena@aksorn.com |
| Turkey | RobinCode | Gözde Erbaz | www.robincode.org
gozde@robincode.org |
-| UK | Computing At School (CAS) | Abi Edwards | http://www.computingatschool.org.uk/
noe@bcs.uk |
+| UK | Computing At School (CAS) | Abi Edwards | http://www.computingatschool.org.uk
noe@bcs.uk |
| Vietnam | Microsoft Vietnam | Nhi Le | https://www.microsoft.com/vi-vn
nhile@microsoft.com |
<%= view :signup_button %>