diff --git a/smart-hut/src/components/SceneModal.js b/smart-hut/src/components/SceneModal.js
index 2219a80..be03283 100644
--- a/smart-hut/src/components/SceneModal.js
+++ b/smart-hut/src/components/SceneModal.js
@@ -7,6 +7,7 @@ import {
Responsive,
Form,
Input,
+ Dropdown,
} from "semantic-ui-react";
import SelectIcons from "./SelectIcons";
import { connect } from "react-redux";
@@ -22,6 +23,15 @@ class SceneModal extends Component {
this.modifySceneModal = this.modifySceneModal.bind(this);
this.deleteScene = this.deleteScene.bind(this);
this.updateIcon = this.updateIcon.bind(this);
+ this.setCopyFrom = this.setCopyFrom.bind(this);
+ }
+
+ componentDidUpdate(oldProps) {
+ // this might bug out since we are just checking the length
+ // to see if the elements inside this.props.scenes are changing
+ if (this.props.scenes.length !== oldProps.scenes.length) {
+ this.setState({ ...this.state, scenes: this.scenes });
+ }
}
get initialState() {
@@ -29,9 +39,19 @@ class SceneModal extends Component {
name: this.type === "new" ? "New Scene" : this.props.scene.name,
openModal: false,
selectedIcon: "home",
+ scenes: this.scenes,
+ copyFrom: null,
};
}
+ get scenes() {
+ return this.props.scenes.map((s) => ({
+ key: s.id,
+ text: s.name,
+ value: s.id,
+ }));
+ }
+
setInitialState() {
this.setState(this.initialState);
}
@@ -47,7 +67,7 @@ class SceneModal extends Component {
};
this.props
- .saveScene(data, null)
+ .saveScene(data, null, this.state.copyFrom)
.then(() => {
this.setInitialState();
this.closeModal();
@@ -95,6 +115,10 @@ class SceneModal extends Component {
this.setState({ selectedIcon: e });
}
+ setCopyFrom(_, copyFrom) {
+ this.setState({ ...this.state, copyFrom: copyFrom.value });
+ }
+
render() {
const spaceDiv = {
background: "#f4f4f4",
@@ -155,6 +179,7 @@ class SceneModal extends Component {
Insert the name of the scene:
-
Select an icon:
+
+ {this.type === "new" && (
+
+
+
+
+ )}
{this.type === "modify" ? (
@@ -215,6 +253,7 @@ const setActiveScene = (activeScene) => {
const mapStateToProps = (state, ownProps) => ({
scene: ownProps.id ? state.scenes[ownProps.id] : null,
+ scenes: Object.values(state.scenes),
});
const SceneModalContainer = connect(
mapStateToProps,
diff --git a/smart-hut/src/components/dashboard/devices/Videocam.js b/smart-hut/src/components/dashboard/devices/Videocam.js
index 610fb28..de77219 100644
--- a/smart-hut/src/components/dashboard/devices/Videocam.js
+++ b/smart-hut/src/components/dashboard/devices/Videocam.js
@@ -40,8 +40,8 @@ class Videocam extends Component {
.catch((err) => console.error("videocamera update error", err));
} else {
this.props.updateState(
- { id: this.props.state.id, on: turn },
- this.props.state.kind
+ { id: this.props.stateOrDevice.id, on: turn },
+ this.props.stateOrDevice.kind
);
}
}
@@ -72,11 +72,7 @@ class Videocam extends Component {
this.setOnOff(val.checked)}
/>
diff --git a/smart-hut/src/remote.js b/smart-hut/src/remote.js
index 695e347..666910b 100644
--- a/smart-hut/src/remote.js
+++ b/smart-hut/src/remote.js
@@ -447,11 +447,14 @@ export const RemoteService = {
* Creates/Updates a scene with the given data
* @param {String} data.name the scene's name,
* @param {Number|null} sceneId the scene's id if update, null for creation
+ * @param {Number|null} copyFrom the id of the scene from which the states must be copied from.
+ * (ignored for updates)
* @returns {Promise} promise that resolves to void and rejects
* with user-fiendly errors as a RemoteError
*/
- saveScene: (data, sceneId = null) => {
+ saveScene: (data, sceneId = null, copyFrom = null) => {
return (dispatch) => {
+ copyFrom = sceneId === null ? copyFrom : null;
data = {
name: data.name,
icon: data.icon,
@@ -461,12 +464,31 @@ export const RemoteService = {
? Endpoint.put(`/scene/${sceneId}`, {}, data)
: Endpoint.post(`/scene`, {}, data)
)
- .then((res) => void dispatch(actions.sceneSave(res.data)))
+ .then(async (res) => {
+ let states = [];
+
+ if (copyFrom) {
+ const sceneId = res.data.id;
+ try {
+ const res = await Endpoint.post(
+ `/scene/${sceneId}/copyFrom/${copyFrom}`
+ );
+ states = res.data;
+ } catch (e) {
+ console.warn("Error in state cloning from scene " + copyFrom, e);
+ throw new RemoteError(["Network error"]);
+ }
+ }
+
+ dispatch(actions.sceneSave(res.data));
+ if (states.length > 0) {
+ dispatch(actions.statesUpdate(sceneId, states));
+ }
+ })
.catch(parseValidationErrors);
};
},
- //
updateState: (data, type) => {
return (dispatch) => {
let url;
diff --git a/smart-hut/src/store.js b/smart-hut/src/store.js
index 6af48ed..5583473 100644
--- a/smart-hut/src/store.js
+++ b/smart-hut/src/store.js
@@ -3,7 +3,6 @@ import thunk from "redux-thunk";
import update from "immutability-helper";
import reduxWebSocket, { connect } from "@giantmachines/redux-websocket";
import { socketURL } from "./endpoint";
-import actions from "./storeActions";
function reducer(previousState, action) {
let newState, change;
@@ -125,9 +124,9 @@ function reducer(previousState, action) {
//console.log(action.sceneStates);
change = null;
- // if room is given, delete all devices in that room
- // and remove any join between that room and deleted
- // devices
+ // if scene is given, delete all sceneStates in that scene
+ // and remove any join between that scene and deleted
+ // sceneStates
change = {
scenes: { [action.sceneId]: { sceneStates: { $set: new Set() } } },
sceneStates: { $unset: [] },
@@ -431,7 +430,7 @@ function reducer(previousState, action) {
// This update does not ensure the consistent update of switchId/dimmerId properties
// on output devices connected to an input device in this room. Please manually request
// all devices again if consistent update is desired
- change = { states: { $unset: [] } };
+ change = { sceneStates: { $unset: [] } };
for (const id of previousState.scenes[action.sceneId].sceneStates) {
change.sceneStates.$unset.push(id);