gwchq-textjam 0.2.19 → 0.2.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -68344,8 +68344,8 @@ __webpack_require__.r(__webpack_exports__);
68344
68344
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
68345
68345
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
68346
68346
  /* harmony export */ });
68347
- /* harmony import */ var C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(89379);
68348
- /* harmony import */ var C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectWithoutProperties_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(53986);
68347
+ /* harmony import */ var D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(89379);
68348
+ /* harmony import */ var D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectWithoutProperties_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(53986);
68349
68349
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(51649);
68350
68350
  /* harmony import */ var _hello_pangea_dnd__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(98850);
68351
68351
  /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(14062);
@@ -68369,7 +68369,7 @@ var DraggableTab = _ref => {
68369
68369
  panelIndex,
68370
68370
  fileIndex
68371
68371
  } = _ref,
68372
- otherProps = (0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectWithoutProperties_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)(_ref, _excluded);
68372
+ otherProps = (0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectWithoutProperties_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)(_ref, _excluded);
68373
68373
  var openFiles = (0,react_redux__WEBPACK_IMPORTED_MODULE_1__.useSelector)(state => state.editor.openedFiles);
68374
68374
  var openFilesCount = openFiles[panelIndex].length;
68375
68375
  var dispatch = (0,react_redux__WEBPACK_IMPORTED_MODULE_1__.useDispatch)();
@@ -68386,7 +68386,7 @@ var DraggableTab = _ref => {
68386
68386
  switchToFileTab(panelIndex, (fileIndex + openFilesCount - 1) % openFilesCount);
68387
68387
  }
68388
68388
  };
68389
- var InnerTab = () => /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__.jsx)(react_tabs__WEBPACK_IMPORTED_MODULE_2__.Tab, (0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)((0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)({
68389
+ var InnerTab = () => /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__.jsx)(react_tabs__WEBPACK_IMPORTED_MODULE_2__.Tab, (0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)((0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)({
68390
68390
  onClick: e => {
68391
68391
  e.stopPropagation();
68392
68392
  switchToFileTab(panelIndex, fileIndex);
@@ -68404,7 +68404,7 @@ var DraggableTab = _ref => {
68404
68404
  draggableProps,
68405
68405
  dragHandleProps
68406
68406
  } = _ref2;
68407
- return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__.jsx)("div", (0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)((0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)((0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)({
68407
+ return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__.jsx)("div", (0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)((0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)((0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)({
68408
68408
  className: "draggable-tab",
68409
68409
  ref: innerRef
68410
68410
  }, draggableProps), dragHandleProps), {}, {
@@ -68426,8 +68426,8 @@ __webpack_require__.r(__webpack_exports__);
68426
68426
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
68427
68427
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
68428
68428
  /* harmony export */ });
68429
- /* harmony import */ var C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(89379);
68430
- /* harmony import */ var C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectWithoutProperties_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(53986);
68429
+ /* harmony import */ var D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(89379);
68430
+ /* harmony import */ var D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectWithoutProperties_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(53986);
68431
68431
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(51649);
68432
68432
  /* harmony import */ var _hello_pangea_dnd__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(98850);
68433
68433
  /* harmony import */ var react_tabs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(39243);
@@ -68446,8 +68446,8 @@ var DroppableTabList = _ref => {
68446
68446
  children: _children,
68447
68447
  index
68448
68448
  } = _ref,
68449
- otherProps = (0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectWithoutProperties_js__WEBPACK_IMPORTED_MODULE_4__/* ["default"] */ .A)(_ref, _excluded);
68450
- return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_3__.jsx)(react_tabs__WEBPACK_IMPORTED_MODULE_1__.TabList, (0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)((0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)({}, otherProps), {}, {
68449
+ otherProps = (0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectWithoutProperties_js__WEBPACK_IMPORTED_MODULE_4__/* ["default"] */ .A)(_ref, _excluded);
68450
+ return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_3__.jsx)(react_tabs__WEBPACK_IMPORTED_MODULE_1__.TabList, (0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)((0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)({}, otherProps), {}, {
68451
68451
  children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_3__.jsx)(_hello_pangea_dnd__WEBPACK_IMPORTED_MODULE_6__.Droppable, {
68452
68452
  direction: "horizontal",
68453
68453
  droppableId: index.toString(),
@@ -68457,7 +68457,7 @@ var DroppableTabList = _ref => {
68457
68457
  droppableProps,
68458
68458
  placeholder
68459
68459
  } = _ref2;
68460
- return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxs)("div", (0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)((0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)({
68460
+ return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_3__.jsxs)("div", (0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)((0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_5__/* ["default"] */ .A)({
68461
68461
  className: "droppable-tab-list"
68462
68462
  }, droppableProps), {}, {
68463
68463
  ref: innerRef,
@@ -103011,7 +103011,7 @@ __webpack_require__.r(__webpack_exports__);
103011
103011
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
103012
103012
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
103013
103013
  /* harmony export */ });
103014
- /* harmony import */ var C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(89379);
103014
+ /* harmony import */ var D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(89379);
103015
103015
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(51649);
103016
103016
  /* harmony import */ var react_redux__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(14062);
103017
103017
  /* harmony import */ var _redux_EditorSlice__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(68512);
@@ -103091,7 +103091,7 @@ var ProjectName = _ref => {
103091
103091
  id: "project_name_label",
103092
103092
  className: _styles_module_scss__WEBPACK_IMPORTED_MODULE_3__["default"].projectLabel,
103093
103093
  children: "Project Name"
103094
- }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxs)("div", (0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)((0,C_Project_source_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)({
103094
+ }), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxs)("div", (0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)((0,D_gwc2_gwchq_textjam_node_modules_babel_runtime_helpers_esm_objectSpread2_js__WEBPACK_IMPORTED_MODULE_7__/* ["default"] */ .A)({
103095
103095
  className: classnames__WEBPACK_IMPORTED_MODULE_2___default()(_styles_module_scss__WEBPACK_IMPORTED_MODULE_3__["default"].projectName, className)
103096
103096
  }, hoverProps), {}, {
103097
103097
  children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_4__.jsx)((components_Tooltip_Tooltip__WEBPACK_IMPORTED_MODULE_8___default()), {
@@ -103392,9 +103392,16 @@ var types = __webpack_require__(92932);
103392
103392
  var SpinnerDotted = __webpack_require__(79458);
103393
103393
  ;// ./src/components/SaveButton/styles.module.scss
103394
103394
  // extracted by mini-css-extract-plugin
103395
- /* harmony default export */ const styles_module = ({"grey-rpi-grey-15":"#d5d7dc","grey-rpi-grey-40":"#9497a4","grey-rpi-grey-5":"#f1f2f3","grey-rpi-grey-70":"#4a4d59","grey-rpf-white":"#fff","content":"styles-module__content--Cgvxl","icon":"styles-module__icon--y9Z7a"});
103395
+ /* harmony default export */ const styles_module = ({"grey-rpi-grey-15":"#d5d7dc","grey-rpi-grey-40":"#9497a4","grey-rpi-grey-5":"#f1f2f3","grey-rpi-grey-70":"#4a4d59","grey-rpf-white":"#fff","wrapper":"styles-module__wrapper--U1NAt","content":"styles-module__content--Cgvxl","icon":"styles-module__icon--y9Z7a"});
103396
103396
  // EXTERNAL MODULE: ./src/components/shared/SvgIcon/index.tsx
103397
103397
  var SvgIcon = __webpack_require__(82917);
103398
+ // EXTERNAL MODULE: ./src/components/Tooltip/Tooltip.tsx
103399
+ var Tooltip = __webpack_require__(26982);
103400
+ var Tooltip_default = /*#__PURE__*/__webpack_require__.n(Tooltip);
103401
+ // EXTERNAL MODULE: ./src/hooks/useHover.ts
103402
+ var useHover = __webpack_require__(78556);
103403
+ // EXTERNAL MODULE: ./src/redux/selectors.ts
103404
+ var selectors = __webpack_require__(43551);
103398
103405
  // EXTERNAL MODULE: ./node_modules/react/jsx-runtime.js
103399
103406
  var jsx_runtime = __webpack_require__(74848);
103400
103407
  ;// ./src/components/SaveButton/SaveButton.jsx
@@ -103410,14 +103417,26 @@ var jsx_runtime = __webpack_require__(74848);
103410
103417
 
103411
103418
 
103412
103419
 
103420
+
103421
+
103422
+
103423
+ var NO_CHANGES_TO_SAVE_MESSAGE = "No new changes to save!";
103413
103424
  var SaveButton = props => {
103414
103425
  var dispatch = (0,external_react_redux_.useDispatch)();
103426
+ var {
103427
+ hovered,
103428
+ hoverProps
103429
+ } = (0,useHover.useHover)();
103415
103430
  var loading = (0,external_react_redux_.useSelector)(state => state.editor.loading);
103416
103431
  var saving = (0,external_react_redux_.useSelector)(state => state.editor.saving);
103432
+ var hasContentChanges = (0,external_react_redux_.useSelector)(selectors.selectProjectHasContentChanges);
103433
+ var hasNameChanges = (0,external_react_redux_.useSelector)(selectors.selectProjectHasNameChanges);
103417
103434
  var onClickSave = (0,external_react_.useCallback)(/*#__PURE__*/_asyncToGenerator(function* () {
103418
103435
  dispatch((0,EditorSlice.setSaveTriggered)(true));
103419
103436
  }), [dispatch]);
103420
103437
  var isSaving = saving === types.SavingState.PROCESS;
103438
+ var hasChangesToSave = hasContentChanges || hasNameChanges;
103439
+ var isDisabled = isSaving || !hasChangesToSave;
103421
103440
  var buttonIcon = isSaving ? null : () => /*#__PURE__*/(0,jsx_runtime.jsx)(SvgIcon.SvgIcon, {
103422
103441
  size: 24,
103423
103442
  SvgElement: save["default"],
@@ -103427,14 +103446,22 @@ var SaveButton = props => {
103427
103446
  className: styles_module.content,
103428
103447
  children: [/*#__PURE__*/(0,jsx_runtime.jsx)(SpinnerDotted.SpinnerDotted, {}), " Saving..."]
103429
103448
  }) : "Save";
103430
- return loading === types.LoadingState.SUCCESS && /*#__PURE__*/(0,jsx_runtime.jsx)(Button["default"], (0,objectSpread2/* default */.A)({
103431
- buttonText: buttonText,
103432
- ButtonIcon: buttonIcon,
103433
- buttonIconPosition: "left",
103434
- variant: "secondary",
103435
- onClickHandler: onClickSave,
103436
- disabled: saving === types.SavingState.PROCESS
103437
- }, props));
103449
+ return loading === types.LoadingState.SUCCESS && /*#__PURE__*/(0,jsx_runtime.jsxs)("span", (0,objectSpread2/* default */.A)((0,objectSpread2/* default */.A)({
103450
+ className: styles_module.wrapper
103451
+ }, hoverProps), {}, {
103452
+ children: [/*#__PURE__*/(0,jsx_runtime.jsx)((Tooltip_default()), {
103453
+ message: NO_CHANGES_TO_SAVE_MESSAGE,
103454
+ visible: !hasChangesToSave && hovered,
103455
+ position: "bottom"
103456
+ }), /*#__PURE__*/(0,jsx_runtime.jsx)(Button["default"], (0,objectSpread2/* default */.A)({
103457
+ buttonText: buttonText,
103458
+ ButtonIcon: buttonIcon,
103459
+ buttonIconPosition: "left",
103460
+ variant: "secondary",
103461
+ onClickHandler: onClickSave,
103462
+ disabled: isDisabled
103463
+ }, props))]
103464
+ }));
103438
103465
  };
103439
103466
  /* harmony default export */ const SaveButton_SaveButton = (SaveButton);
103440
103467
 
@@ -373618,10 +373645,8 @@ const useProject = ({ projectData, projectContent = null, isContentLoaded = null
373618
373645
  dispatch((0, EditorSlice_1.setCommits)({ commits: projectData?.commits ?? [] }));
373619
373646
  return;
373620
373647
  }
373621
- const isSaveInProgressOrSettling = saveTriggered ||
373622
- savingState === types_1.SavingState.PROCESS ||
373623
- savingState === types_1.SavingState.SUCCESS;
373624
- if (isSaveInProgressOrSettling) {
373648
+ const isSaveInProgress = saveTriggered || savingState === types_1.SavingState.PROCESS;
373649
+ if (isSaveInProgress) {
373625
373650
  return;
373626
373651
  }
373627
373652
  // if no local data found or cache should not be used, and commitId provided, try to load from commit
@@ -373834,6 +373859,7 @@ const sendToast_1 = __webpack_require__(50068);
373834
373859
  const projectTabSync_1 = __webpack_require__(48235);
373835
373860
  const LeaveFlowSlice_1 = __webpack_require__(52990);
373836
373861
  const buildProjectSnapshot_1 = __webpack_require__(10533);
373862
+ const selectors_1 = __webpack_require__(43551);
373837
373863
  const AUTO_SAVE_INTERVAL = 2000;
373838
373864
  const useProjectPersistence = ({ user, projectData, hasShownSavePrompt, saveProject, isShared, }) => {
373839
373865
  const project = (0, stores_1.useAppSelector)((state) => state.editor.project);
@@ -373843,13 +373869,35 @@ const useProjectPersistence = ({ user, projectData, hasShownSavePrompt, saveProj
373843
373869
  const leaveFlow = (0, stores_1.useAppSelector)((state) => state.leaveFlow);
373844
373870
  const codeRunTriggered = (0, stores_1.useAppSelector)((state) => state.editor.codeRunTriggered);
373845
373871
  const existingCommits = (0, stores_1.useAppSelector)((state) => state.editor.commits);
373872
+ const hasContentChanges = (0, stores_1.useAppSelector)(selectors_1.selectProjectHasContentChanges);
373873
+ const hasNameChanges = (0, stores_1.useAppSelector)(selectors_1.selectProjectHasNameChanges);
373846
373874
  const dispatch = (0, react_redux_1.useDispatch)();
373847
373875
  const { deleteValueFromCache, upsertCacheValue } = (0, useProjectCache_1.useProjectCache)();
373848
373876
  const handleSave = (0, react_1.useCallback)(async () => {
373849
373877
  if (!project?.components?.length)
373850
373878
  return;
373851
- dispatch((0, EditorSlice_1.setSaving)(types_1.SavingState.PROCESS));
373852
373879
  try {
373880
+ const isInitialSave = !project.commitId;
373881
+ // Nothing to persist. The save button is disabled in this state,
373882
+ // but keep this guard for programmatic save triggers.
373883
+ if (!hasContentChanges && !hasNameChanges && !isInitialSave) {
373884
+ dispatch((0, EditorSlice_1.setSaveTriggered)(false));
373885
+ dispatch((0, EditorSlice_1.setSaving)(types_1.SavingState.IDLE));
373886
+ console.warn("No changes detected. Save won't be processed.");
373887
+ return;
373888
+ }
373889
+ // Name-only save: patch repository name, but do not create/upload a new commit.
373890
+ // Do not set PROCESS here because no archive is being created.
373891
+ if (!hasContentChanges && hasNameChanges && !isInitialSave) {
373892
+ await saveProject?.({
373893
+ project,
373894
+ commitBlob: null,
373895
+ hasContentChanges: false,
373896
+ hasNameChanges: true,
373897
+ });
373898
+ return;
373899
+ }
373900
+ dispatch((0, EditorSlice_1.setSaving)(types_1.SavingState.PROCESS));
373853
373901
  const { zipBlob, unzipSize } = await (0, createProjectArchive_1.createProjectArchive)(project);
373854
373902
  if (unzipSize > constants_1.MAX_PROJECT_TOTAL_SIZE_MB * 1024 * 1024) {
373855
373903
  (0, sendToast_1.showError)(`The project exceeds the ${constants_1.MAX_PROJECT_TOTAL_SIZE_MB} MB maximum allowed size. Please reduce the project size to save successfully.`);
@@ -373859,7 +373907,13 @@ const useProjectPersistence = ({ user, projectData, hasShownSavePrompt, saveProj
373859
373907
  }
373860
373908
  // should skip redirect to project on the first save to avoid conflicts with leave flow
373861
373909
  const skipRedirect = project?.commits?.length === 0;
373862
- await saveProject?.(project, zipBlob, skipRedirect);
373910
+ await saveProject?.({
373911
+ project,
373912
+ commitBlob: zipBlob,
373913
+ hasContentChanges: true,
373914
+ hasNameChanges,
373915
+ skipRedirect,
373916
+ });
373863
373917
  }
373864
373918
  catch (e) {
373865
373919
  console.error(e);
@@ -373874,6 +373928,8 @@ const useProjectPersistence = ({ user, projectData, hasShownSavePrompt, saveProj
373874
373928
  project.name,
373875
373929
  project.commitId,
373876
373930
  project.identifier,
373931
+ hasContentChanges,
373932
+ hasNameChanges,
373877
373933
  ]);
373878
373934
  // finish the process if save failed
373879
373935
  (0, react_1.useEffect)(() => {
@@ -373889,12 +373945,9 @@ const useProjectPersistence = ({ user, projectData, hasShownSavePrompt, saveProj
373889
373945
  }, [dispatch, leaveFlow.requestId, leaveFlow.status, saving]);
373890
373946
  // handle successful saving update
373891
373947
  (0, react_1.useEffect)(() => {
373892
- if (!projectData?.commitId ||
373893
- projectData.commitId === project.commitId ||
373894
- !saveTriggered ||
373895
- saving !== types_1.SavingState.SUCCESS)
373948
+ if (!saveTriggered || saving !== types_1.SavingState.SUCCESS)
373896
373949
  return;
373897
- const incomingCommits = projectData.commits ?? [];
373950
+ const incomingCommits = projectData?.commits ?? [];
373898
373951
  const commitsById = new Map();
373899
373952
  [...existingCommits, ...incomingCommits].forEach((commit) => {
373900
373953
  if (!commit?.id)
@@ -373909,18 +373962,25 @@ const useProjectPersistence = ({ user, projectData, hasShownSavePrompt, saveProj
373909
373962
  const bTime = new Date(b.createdAt || 0).getTime();
373910
373963
  return bTime - aTime;
373911
373964
  });
373965
+ const incomingCommitId = projectData?.commitId;
373966
+ const incomingIdentifier = projectData?.identifier;
373967
+ if (!incomingIdentifier)
373968
+ return;
373912
373969
  // first save: new commitId incoming, but no commitId were set before
373913
- const isFirstSave = commits.length === 1 && !project.commitId && projectData.commitId;
373970
+ const isFirstSave = commits.length === 1 && !project.commitId && projectData?.commitId;
373914
373971
  // commit different: new commitId incoming, but another commitId is set before
373915
- const isCommitDifferent = projectData.commitId &&
373972
+ const isCommitDifferent = projectData?.commitId &&
373916
373973
  project.commitId &&
373917
373974
  project.commitId !== projectData.commitId;
373918
- if (!isFirstSave && !isCommitDifferent)
373919
- return;
373920
- dispatch((0, EditorSlice_1.updateProjectCommits)({ commitId: projectData.commitId, commits }));
373975
+ if ((isFirstSave || isCommitDifferent) && projectData?.commitId) {
373976
+ dispatch((0, EditorSlice_1.updateProjectCommits)({
373977
+ commitId: projectData.commitId,
373978
+ commits,
373979
+ }));
373980
+ }
373921
373981
  // remove old cached project on the first save
373922
373982
  if (isFirstSave &&
373923
- projectData.identifier &&
373983
+ projectData?.identifier &&
373924
373984
  project.identifier !== projectData.identifier) {
373925
373985
  dispatch((0, EditorSlice_1.updateProjectIdentifier)(projectData.identifier));
373926
373986
  deleteValueFromCache(project.identifier);
@@ -373935,8 +373995,8 @@ const useProjectPersistence = ({ user, projectData, hasShownSavePrompt, saveProj
373935
373995
  ...project,
373936
373996
  hasStructureChanges: false,
373937
373997
  components: cleanedComponents,
373938
- identifier: projectData.identifier,
373939
- commitId: projectData.commitId,
373998
+ identifier: incomingIdentifier,
373999
+ commitId: incomingCommitId ?? project.commitId,
373940
374000
  commits,
373941
374001
  };
373942
374002
  const newLastSavedSnapshot = (0, buildProjectSnapshot_1.buildProjectSnapshot)(cleanedProject);
@@ -373944,7 +374004,7 @@ const useProjectPersistence = ({ user, projectData, hasShownSavePrompt, saveProj
373944
374004
  components: cleanedComponents,
373945
374005
  hasStructureChanges: false,
373946
374006
  lastSavedSnapshot: newLastSavedSnapshot,
373947
- identifier: projectData.identifier,
374007
+ identifier: incomingIdentifier,
373948
374008
  };
373949
374009
  dispatch((0, EditorSlice_1.updateProjectSnapshot)(updatedProjectSnapshot));
373950
374010
  upsertCacheValue(cleanedProject.identifier, {
@@ -374045,9 +374105,14 @@ const useProjectRemix = ({ projectData, saveProject, }) => {
374045
374105
  const remixName = `Remix of ${project.name}`;
374046
374106
  const { zipBlob } = await (0, createProjectArchive_1.createProjectArchive)(project);
374047
374107
  await saveProject?.({
374048
- ...project,
374049
- name: remixName,
374050
- }, zipBlob);
374108
+ project: {
374109
+ ...project,
374110
+ name: remixName,
374111
+ },
374112
+ commitBlob: zipBlob,
374113
+ hasContentChanges: true,
374114
+ hasNameChanges: false,
374115
+ });
374051
374116
  }
374052
374117
  catch (e) {
374053
374118
  console.error(e);
@@ -374867,20 +374932,26 @@ exports.startAppListening = exports.listenerMiddleware.startListening;
374867
374932
 
374868
374933
 
374869
374934
  Object.defineProperty(exports, "__esModule", ({ value: true }));
374870
- exports.selectProjectDirtyState = void 0;
374935
+ exports.selectProjectDirtyState = exports.selectProjectHasNameChanges = exports.selectProjectHasContentChanges = void 0;
374871
374936
  const toolkit_1 = __webpack_require__(12069);
374872
- exports.selectProjectDirtyState = (0, toolkit_1.createSelector)([
374937
+ exports.selectProjectHasContentChanges = (0, toolkit_1.createSelector)([
374873
374938
  (state) => state.editor.project?.hasStructureChanges,
374874
- (state) => state.editor.project?.name,
374875
- (state) => state.editor.project?.lastSavedSnapshot?.name,
374876
374939
  (state) => state.editor.project?.components,
374877
374940
  (state) => state.editor.commits,
374878
- ], (hasStructureChanges, projectName, snapshotName, components, commits) => {
374941
+ ], (hasStructureChanges, components, commits) => {
374879
374942
  return (Boolean(hasStructureChanges) ||
374880
- (Boolean(snapshotName) && projectName !== snapshotName) ||
374881
- (components?.some((c) => c.isDirty) ?? false) ||
374943
+ (components?.some((component) => component.isDirty) ?? false) ||
374882
374944
  commits.length === 0);
374883
374945
  });
374946
+ exports.selectProjectHasNameChanges = (0, toolkit_1.createSelector)([
374947
+ (state) => state.editor.project?.name,
374948
+ (state) => state.editor.project?.lastSavedSnapshot?.name,
374949
+ ], (projectName, snapshotName) => {
374950
+ return Boolean(snapshotName) && projectName !== snapshotName;
374951
+ });
374952
+ exports.selectProjectDirtyState = (0, toolkit_1.createSelector)([exports.selectProjectHasContentChanges, exports.selectProjectHasNameChanges], (hasContentChanges, hasNameChanges) => {
374953
+ return hasContentChanges || hasNameChanges;
374954
+ });
374884
374955
 
374885
374956
 
374886
374957
  /***/ }),
package/dist/style.css CHANGED
@@ -682,7 +682,7 @@
682
682
  :root{--rpf-white: #ffffff}.styles-module__tooltip--7XFyr{position:absolute;background-color:#242424;color:#e5e5e5;padding:calc(.25rem*var(--scale-factor, 1)) calc(.5rem*var(--scale-factor, 1));border-radius:calc(.25rem*var(--scale-factor, 1));font-size:calc(.75rem*var(--scale-factor, 1));line-height:calc(1rem*var(--scale-factor, 1));min-inline-size:calc(10.25rem*var(--scale-factor, 1));z-index:650;pointer-events:none;white-space:pre-wrap;opacity:0;visibility:hidden;transition:opacity .2s ease,transform .2s ease}.styles-module__tooltip--7XFyr.styles-module__visible--wGPCM{opacity:1;visibility:visible}.styles-module__position-bottom--Lwi\+l{inset-block-start:100%;inset-inline-end:0;margin-block-start:calc(.25rem*var(--scale-factor, 1))}.styles-module__position-fixed--t8yrP{position:fixed;margin-top:calc(.625rem*var(--scale-factor, 1));margin-right:calc(2rem*var(--scale-factor, 1))}
683
683
  :root{--rpf-white: #ffffff}.styles-module__btn--0Px6W{align-items:center;border-radius:calc(.75rem*var(--scale-factor, 1));border:0;box-sizing:border-box;padding:calc(.75rem*var(--scale-factor, 1)) calc(1.25rem*var(--scale-factor, 1));color:#003046;cursor:pointer;display:inline-flex;font-family:var(--wc-font-family-sans-serif);font-size:inherit;font-weight:500;gap:calc(.5rem*var(--scale-factor, 1));justify-content:center;position:relative;text-align:center;text-decoration:none;transition:all .2s ease}.styles-module__btn--0Px6W:disabled{background-color:#4a4d59;color:#69746d;cursor:default}.styles-module__btn--0Px6W:focus-visible{border:3px solid #cd2356;outline:none}.styles-module__btn--primary--k7oQ0{background-color:var(--rpf-button-primary-background-color);border-radius:calc(.5rem*var(--scale-factor, 1));color:var(--rpf-button-primary-text-color)}.styles-module__btn--primary--k7oQ0 svg{fill:var(--rpf-button-primary-text-color)}.styles-module__btn--primary--k7oQ0:active,.styles-module__btn-outer--4KgkG:active .styles-module__btn--primary--k7oQ0{background-color:var(--rpf-button-primary-background-color-active)}.styles-module__btn--primary--k7oQ0:focus-visible,.styles-module__btn-outer--4KgkG:focus-visible .styles-module__btn--primary--k7oQ0{background-color:var(--rpf-button-primary-background-color-focus)}.styles-module__btn--primary--k7oQ0:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--primary--k7oQ0{background-color:var(--rpf-button-primary-background-color-hover);border-radius:calc(.5rem*var(--scale-factor, 1))}.styles-module__btn--primary--k7oQ0:disabled{background-color:var(--rpf-button-primary-background-color-disabled);color:var(--rpf-button-primary-color-disabled)}.styles-module__btn--primary--k7oQ0:disabled svg{fill:var(--rpf-button-primary-color-disabled)}.styles-module__btn--primary--k7oQ0:disabled:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--primary--k7oQ0:disabled{background-color:var(--rpf-button-primary-background-color-disabled)}.styles-module__btn--secondary--tK09f{background-color:inherit;color:var(--rpf-button-secondary-text-color);border:2px solid var(--rpf-button-primary-background-color)}.styles-module__btn--secondary--tK09f svg{fill:var(--rpf-button-secondary-text-color)}.styles-module__btn--secondary--tK09f:active,.styles-module__btn-outer--4KgkG:active .styles-module__btn--secondary--tK09f{background-color:inherit}.styles-module__btn--secondary--tK09f:focus-visible,.styles-module__btn-outer--4KgkG:focus-visible .styles-module__btn--secondary--tK09f{background-color:inherit}.styles-module__btn--secondary--tK09f:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--secondary--tK09f{background-color:inherit}.styles-module__btn--secondary--tK09f:disabled{background-color:var(--rpf-button-secondary-background-color-disabled);color:var(--rpf-button-secondary-background-color-active)}.styles-module__btn--secondary--tK09f:disabled svg{fill:var(--rpf-button-secondary-background-color-active)}.styles-module__btn--secondary--tK09f:disabled:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--secondary--tK09f:disabled{background-color:var(--rpf-button-secondary-background-color-disabled)}.styles-module__btn--secondary--tK09f:active{border:2px solid var(--rpf-button-secondary-background-color-active)}.styles-module__btn--secondary--tK09f:hover{background-color:var(--rpf-button-secondary-background-color-hover);color:var(--rpf-button-secondary-text-color-hover);border-color:var(--rpf-button-secondary-border-color-hover) !important}.styles-module__btn--secondary--tK09f:hover svg{fill:var(--rpf-button-secondary-text-color-hover)}.styles-module__btn--secondary--tK09f:focus-visible{outline:3px solid var(--rpf-button-secondary-background-color-focus)}.styles-module__btn--tertiary--jf5po{background-color:inherit;color:inherit}.styles-module__btn--tertiary--jf5po:active,.styles-module__btn-outer--4KgkG:active .styles-module__btn--tertiary--jf5po{background-color:inherit}.styles-module__btn--tertiary--jf5po:focus-visible,.styles-module__btn-outer--4KgkG:focus-visible .styles-module__btn--tertiary--jf5po{background-color:inherit}.styles-module__btn--tertiary--jf5po:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--tertiary--jf5po{background-color:inherit}.styles-module__btn--tertiary--jf5po:disabled{background-color:inherit;color:#4a4d59}.styles-module__btn--tertiary--jf5po:disabled svg{fill:#4a4d59}.styles-module__btn--tertiary--jf5po:disabled:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--tertiary--jf5po:disabled{background-color:inherit}.styles-module__btn--tertiary--jf5po:active{color:#0e857a}.styles-module__btn--tertiary--jf5po:active svg{fill:#0e857a}.styles-module__btn--tertiary--jf5po:hover{color:var(--rpf-button-tertiary-text-color-hover)}.styles-module__btn--tertiary--jf5po:hover svg{fill:var(--rpf-button-tertiary-text-color-hover)}.styles-module__btn--tertiaryGray--gFHKt{background-color:inherit;color:inherit}.styles-module__btn--tertiaryGray--gFHKt:active,.styles-module__btn-outer--4KgkG:active .styles-module__btn--tertiaryGray--gFHKt{background-color:inherit}.styles-module__btn--tertiaryGray--gFHKt:focus-visible,.styles-module__btn-outer--4KgkG:focus-visible .styles-module__btn--tertiaryGray--gFHKt{background-color:inherit}.styles-module__btn--tertiaryGray--gFHKt:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--tertiaryGray--gFHKt{background-color:inherit}.styles-module__btn--tertiaryGray--gFHKt:disabled{background-color:inherit;color:#4a4d59}.styles-module__btn--tertiaryGray--gFHKt:disabled svg{fill:#4a4d59}.styles-module__btn--tertiaryGray--gFHKt:disabled:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--tertiaryGray--gFHKt:disabled{background-color:inherit}.styles-module__btn--tertiaryGray--gFHKt:active{color:#43d6b9}.styles-module__btn--tertiaryGray--gFHKt:active svg{fill:#43d6b9}.styles-module__btn--tertiaryGray--gFHKt:hover{color:var(#4a4d59)}.styles-module__btn--tertiaryGray--gFHKt:hover svg{fill:var(#4a4d59)}.styles-module__btn--danger--SmsoX{background-color:#9e0a0a;color:#fff}.styles-module__btn--danger--SmsoX svg{fill:#fff}.styles-module__btn--danger--SmsoX:active,.styles-module__btn-outer--4KgkG:active .styles-module__btn--danger--SmsoX{background-color:#9e0a0a}.styles-module__btn--danger--SmsoX:focus-visible,.styles-module__btn-outer--4KgkG:focus-visible .styles-module__btn--danger--SmsoX{background-color:#9e0a0a}.styles-module__btn--danger--SmsoX:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--danger--SmsoX{background-color:#86151e}.styles-module__btn--danger--SmsoX:disabled{background-color:#9e0a0a;color:#fff}.styles-module__btn--danger--SmsoX:disabled svg{fill:#fff}.styles-module__btn--danger--SmsoX:disabled:hover,.styles-module__btn-outer--4KgkG:hover .styles-module__btn--danger--SmsoX:disabled{background-color:#9e0a0a}.styles-module__btn--danger--SmsoX:focus-visible{background-clip:padding-box;border:2px solid rgba(0,0,0,0);outline:3px solid #cd2356}.styles-module__btn--small--cJ2bM{min-block-size:unset;min-inline-size:unset;padding:calc(.25rem*var(--scale-factor, 1))}.styles-module__btnOuter--ip64U{background:rgba(0,0,0,0);border-radius:calc(.5rem*var(--scale-factor, 1));cursor:pointer;padding:calc(.5rem*var(--scale-factor, 1)) 0;display:flex;align-items:center;justify-content:center}.styles-module__btnOuter--ip64U:focus-visible{outline:none}.styles-module__btnOuter--ip64U:focus-visible .styles-module__btn--0Px6W{border:3px solid #cd2356}.styles-module__btnOuter--ip64U:has(.styles-module__btn--0Px6W:disabled){cursor:default}.styles-module__svgOnly--eXeyf{background-color:#43d6b9}.styles-module__svgOnly--eXeyf svg{margin:0}.styles-module__primary--AeI1M{background:#fde246}.styles-module__primary--AeI1M:hover{background:#edce22}.styles-module__primary--AeI1M:active{background:#fff;border:1px solid #003046}.styles-module__primary--AeI1M:disabled{background:#fffbe3;color:#69746d}.styles-module__secondary--tAMJR{background:linear-gradient(139deg, rgba(185, 230, 238, 0.8) 9.38%, rgba(113, 235, 188, 0.8) 45.1%, rgba(113, 235, 188, 0.8) 59.39%, rgba(185, 230, 238, 0.8) 88.77%),#fff;border:none}.styles-module__secondary--tAMJR:hover{background:linear-gradient(0deg, hsla(0, 0%, 34%, 0.15), hsla(0, 0%, 34%, 0.15)),linear-gradient(320deg, #B9E6EE 17.77%, #71EBBC 47.58%, #71EBBC 59.5%, #B9E6EE 84%)}.styles-module__secondary--tAMJR:active{background:#fff;border:1px solid #003046}.styles-module__secondary--tAMJR:disabled{background:linear-gradient(135deg, #B9E6EE, #71EBBC, #71EBBC, #B9E6EE),linear-gradient(139deg, #B9E6EE 9.38%, #71EBBC 45.1%, #71EBBC 59.39%, #B9E6EE 88.77%),#fff}.styles-module__tertiary--Kr5w9{background:#43d6b9;color:#003046}.styles-module__tertiary--Kr5w9:hover{background:#cbcbcb}.styles-module__tertiary--Kr5w9:active{background:#fff}.styles-module__tertiary--Kr5w9:disabled{background:#e5e5e5;color:#69746d}.styles-module__tertiaryGray--gVUq6{background:#e5e5e5;color:#33625e}.styles-module__tertiaryGray--gVUq6:hover{background:#cbcbcb}.styles-module__tertiaryGray--gVUq6:disabled{background:#d5d7dc;color:#69746d}.styles-module__iconed--AMs-c{padding-top:10px;padding-bottom:10px}.styles-module__icon--C2jj1{padding:0px}
684
684
  :root{--rpf-white: #ffffff}.styles-module__spinnerDotted--tTFFI{position:relative;inline-size:1.125rem;block-size:1.125rem}.styles-module__spinnerDotted--tTFFI span{position:absolute;inset-block-start:40%;inset-inline-start:25%;inline-size:.225rem;block-size:.225rem;background-color:#69746d;border-radius:50%;transform-origin:center;transform:rotate(var(--angle)) translateY(-0.5625rem);opacity:.2;animation:styles-module__fade--jNeB5 1s linear infinite;--angle: calc(var(--itemIndex) * 45deg);animation-delay:calc(var(--itemIndex)*.125s)}@keyframes styles-module__fade--jNeB5{0%{opacity:1}100%{opacity:.2}}
685
- :root{--rpf-white: #ffffff}.styles-module__content--Cgvxl{display:flex;gap:calc(.5rem*var(--scale-factor, 1))}.styles-module__icon--y9Z7a{color:#003046}
685
+ :root{--rpf-white: #ffffff}.styles-module__wrapper--U1NAt{display:inline-flex;position:relative}.styles-module__content--Cgvxl{display:flex;gap:calc(.5rem*var(--scale-factor, 1))}.styles-module__icon--y9Z7a{color:#003046}
686
686
  .styles-module__shareButtonWrapper--wEN8e{position:relative}
687
687
  :root{--rpf-white: #ffffff}.styles-module__historyActive--aOVxD{background-color:#fff}.styles-module__historyButton--LInbn{color:#003046}.styles-module__commitHoverElement--foGWE{color:#33625e;display:flex;align-items:center;gap:calc(.25rem*var(--scale-factor, 1))}.styles-module__btnContainer--OlkJ2{position:relative}
688
688
  :root{--rpf-white: #ffffff}.styles-module__contextMenu--HNX6Z{list-style-type:none;padding:0;margin-inline:calc(.5rem*var(--scale-factor, 1)) 0;margin-block:0;border-radius:calc(.25rem*var(--scale-factor, 1));display:flex;flex-direction:column;background-color:#fff;border:1px solid #e5e5e5;box-shadow:0 calc(.25rem*var(--scale-factor, 1)) calc(.5rem*var(--scale-factor, 1)) 0 rgba(0,0,0,.25);overflow:auto;z-index:700}.styles-module__contextMenu--HNX6Z .styles-module__hoverElement--GLCJ0{visibility:hidden;margin-left:calc(1rem*var(--scale-factor, 1))}.styles-module__contextMenu--HNX6Z .styles-module__contextItem--9nzMH{display:flex;justify-content:space-between;font-size:calc(.875rem*var(--scale-factor, 1));line-height:calc(1.25rem*var(--scale-factor, 1));color:#69746d;padding:calc(1rem*var(--scale-factor, 1));white-space:nowrap;inline-size:100%;gap:calc(.5rem*var(--scale-factor, 1));transition:all .2s ease}.styles-module__contextMenu--HNX6Z .styles-module__contextItem--9nzMH .styles-module__optionContent--3E8Zt{display:flex;align-items:center;gap:calc(.5rem*var(--scale-factor, 1));justify-items:start}.styles-module__contextMenu--HNX6Z .styles-module__contextItem--9nzMH:hover{background-color:#e5f6f1;cursor:pointer;color:#003046}.styles-module__contextMenu--HNX6Z .styles-module__contextItem--9nzMH:hover .styles-module__hoverElement--GLCJ0{visibility:visible}.styles-module__contextMenu--HNX6Z .styles-module__contextItemActive--KkppO{background-color:#c5ffe8;color:#003046}.styles-module__contextMenu--HNX6Z .styles-module__contextHeader--jA59O{font-size:calc(.625rem*var(--scale-factor, 1));line-height:calc(1rem*var(--scale-factor, 1));font-weight:500;padding:calc(.5rem*var(--scale-factor, 1)) calc(1rem*var(--scale-factor, 1)) calc(.25rem*var(--scale-factor, 1));color:#33625e}.styles-module__contextMenu--HNX6Z svg{inline-size:calc(1.125rem*var(--scale-factor, 1))}.styles-module__contextMenu--HNX6Z .styles-module__withDivider--X54Sw{border-bottom:1px solid #e5e5e5}.styles-module__visibleScrollbar--PEea9::-webkit-scrollbar{width:calc(.25rem*var(--scale-factor, 1));display:block}.styles-module__visibleScrollbar--PEea9::-webkit-scrollbar-thumb{background-color:HSL(0, 0%, 14%, 10%);border-radius:calc(1.125rem*var(--scale-factor, 1))}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gwchq-textjam",
3
3
  "description": "Embeddable React editor used in Raspberry Pi text-based projects.",
4
- "version": "0.2.19",
4
+ "version": "0.2.20",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/GirlsFirst/gwchq-textjam",
7
7
  "author": "Girls Who Code HQ",