From c29e9f26233c8ebf8ebded9f78b96e065f602e7a Mon Sep 17 00:00:00 2001 From: Craig Hawker Date: Thu, 1 Dec 2022 11:21:52 +0000 Subject: [PATCH 01/50] UI to edit text and numeric properties done. --- .../Configuration/Configuration.cs | 15 +-- .../app/dashboard/dashboard.css | 28 +++-- .../app/scripts/renderers/objectrenderer.js | 55 ++++++++- .../renderers/propertyvaluerenderer.js | 107 ++++++++++++++++-- 4 files changed, 173 insertions(+), 32 deletions(-) diff --git a/src/UIHelpers/Modules/ViewAllMetadata/Configuration/Configuration.cs b/src/UIHelpers/Modules/ViewAllMetadata/Configuration/Configuration.cs index 59da8d7..0849b5f 100644 --- a/src/UIHelpers/Modules/ViewAllMetadata/Configuration/Configuration.cs +++ b/src/UIHelpers/Modules/ViewAllMetadata/Configuration/Configuration.cs @@ -1,3 +1,4 @@ +using MFiles.VAF.Configuration; using System.Runtime.Serialization; using UIHelpers.Modules.Base; @@ -9,13 +10,13 @@ namespace UIHelpers.Modules.ViewAllMetadata public class Configuration : ConfigurationBase { - // TODO: Editing - //[DataMember] - //[JsonConfEditor - //( - // Label = ResourceMarker.Id + nameof(Resources.Configuration.EnableEditing_Label), - // DefaultValue = false - //)] + [DataMember] + [JsonConfEditor + ( + Label = ResourceMarker.Id + nameof(Resources.Configuration.EnableEditing_Label), + DefaultValue = false, + Hidden = true + )] public bool EnableEditing { get; set; } } } \ No newline at end of file diff --git a/src/ViewAllMetadata.UIX/app/dashboard/dashboard.css b/src/ViewAllMetadata.UIX/app/dashboard/dashboard.css index 2d65fd5..5902aab 100644 --- a/src/ViewAllMetadata.UIX/app/dashboard/dashboard.css +++ b/src/ViewAllMetadata.UIX/app/dashboard/dashboard.css @@ -33,12 +33,11 @@ ol.properties { margin: 10px 0px; } ol.properties li { - padding: 5px; position: relative; padding-left: 195px; break-inside: avoid; padding-right: 20px; - line-height: 21px; + height: 28px; } ol.properties li:hover { background-color: #F4F4F4; @@ -60,6 +59,7 @@ ol.properties label { vertical-align: top; position: absolute; left: 5px; + top: 4px; } ol.properties label.mandatory span::after { @@ -73,6 +73,8 @@ ol.properties li .read-only-value { vertical-align: top; display: inline-block; white-space: pre-line; + position: relative; + top: 4px; } ol.properties li.mfdatatype-13 { min-height: 56px; @@ -102,14 +104,20 @@ ol.properties li.editable.editing .editing-value { display: block; } /* make text, real and integer input boxes full width */ - ol.properties li.mfdatatype-1.editable.editing input, - ol.properties li.mfdatatype-2.editable.editing input, - ol.properties li.mfdatatype-3.editable.editing input { - display: inline-block; - width: 100%; - height: 14px; - border: 1px solid #767676; - } +ol.properties li.mfdatatype-1.editable.editing input, +ol.properties li.mfdatatype-2.editable.editing input, +ol.properties li.mfdatatype-3.editable.editing input { + display: inline-block; + width: 100%; + height: 21px; + border: 1px solid #767676; + position: relative; + top: 2px; +} +ol.properties li.invalid-value input +{ + border-color: red !important; +} /* more columns on wider screens */ diff --git a/src/ViewAllMetadata.UIX/app/scripts/renderers/objectrenderer.js b/src/ViewAllMetadata.UIX/app/scripts/renderers/objectrenderer.js index 89dc59a..1005778 100644 --- a/src/ViewAllMetadata.UIX/app/scripts/renderers/objectrenderer.js +++ b/src/ViewAllMetadata.UIX/app/scripts/renderers/objectrenderer.js @@ -115,13 +115,47 @@ function ObjectRenderer(dashboard) propertyValueRenderers.push(propertyValueRenderer); } } + function canSave() + { + for (var i = 0; i < propertyValueRenderers.length; i++) + { + // Is it valid? + if (!propertyValueRenderers[i].isValidValue()) + return false; + } + return true; + } - // When the body is clicked, undo any editing. - $("body").click(function () + // When the body is clicked, exit editing mode. + var $body = $("body"); + $body.click(function () { + var changedProperties = []; + var erroredProperties = []; for (var i = 0; i < propertyValueRenderers.length; i++) { - propertyValueRenderers[i].exitEditMode(); + // Attempt to exit edit mode. + var renderer = propertyValueRenderers[i]; + renderer.exitEditMode(); + + // Should we enable buttons and things? + if (renderer.hasChanged()) + changedProperties.push(renderer); + if (!renderer.isValidValue()) + erroredProperties.push(renderer); + } + + // Update the body with flags. + $body + .removeClass("changed") + .removeClass("has-errors"); + $("#btnSave").removeAttr("disabled"); + if (changedProperties.length > 0) + $body.addClass("changed"); + if (erroredProperties.length > 0) + { + $body.addClass("errors"); + $("#btnSave").attr("disabled", "disabled"); } }); @@ -134,16 +168,27 @@ function ObjectRenderer(dashboard) dashboard.Window.Close(); }).text(dashboard.CustomData.configuration.ResourceStrings.Buttons_Close || "Close"); + renderer.saveChanges = function () + { + if (!canSave()) + return false; + alert("Save not done yet."); + } + // Configure the save button. $("#btnSave").click(function () { - alert("Save not done yet."); + renderer.saveChanges(); }).text(dashboard.CustomData.configuration.ResourceStrings.Buttons_Save || "Save"); + renderer.discardChanges = function () + { + renderer.render(renderer.originalObject); + } // Configure the discard button. $("#btnDiscard").click(function () { - renderer.render(renderer.originalObject); + renderer.discardChanges(); }).text(dashboard.CustomData.configuration.ResourceStrings.Buttons_Discard || "Discard"); // Configure the locations buttons diff --git a/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js b/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js index 7a0b199..bb7d285 100644 --- a/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js +++ b/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js @@ -2,6 +2,62 @@ { var renderer = this; var $listItem = null; + var originalValue = getCurrentValue(); + renderer.getPropertyDef = function () { return propertyDef; } + function getCurrentValue() + { + switch (propertyDef.DataType) + { + case MFDatatypeText: + return null == $listItem + ? propertyValue.Value.DisplayValue + : $(".auto-select", $listItem).val() + ""; + case MFDatatypeInteger: + case MFDatatypeFloating: + return null == $listItem + ? propertyValue.Value.DisplayValue + : parseFloat($(".auto-select", $listItem).val() + ""); + break; + default: + return propertyValue.Value.DisplayValue; + } + } + renderer.hasChanged = function () + { + switch (propertyDef.DataType) + { + case MFDatatypeText: + case MFDatatypeInteger: + case MFDatatypeFloating: + return getCurrentValue() != originalValue; + break; + default: + return false; + } + } + renderer.isValidValue = function() + { + var currentValue = getCurrentValue(); + + switch (propertyDef.DataType) + { + case MFDatatypeText: + case MFDatatypeMultiLineText: + if ((currentValue + "").length == 0 && isRequired) + return false; + break; + case MFDatatypeInteger: + case MFDatatypeFloating: + if ((currentValue + "").length == 0 && isRequired) + return false; + if (isNaN(parseFloat(currentValue))) + return false; + break; + default: + return true; + } + return true; + } function renderLabel($parent) { @@ -65,11 +121,29 @@ switch (propertyDef.DataType) { case MFDatatypeText: + case MFDatatypeInteger: + case MFDatatypeFloating: var $input = $("").addClass("auto-select"); $input.val(propertyValue.Value.DisplayValue); $input.blur(function () { renderer.exitEditMode(); }); $value.append($input); + + // If it's a number then set the input mode + if (propertyDef.DataType != MFDatatypeText) + { + $input.val(parseFloat(propertyValue.Value.DisplayValue)); + $input.attr("inputmode", "numeric"); + var pattern = "[0-9]*"; // Default to allowing just numbers. + if (propertyDef.DataType == MFDatatypeFloating) + { + pattern = "[0=9\.\,]*"; // Allow decimal separators too. + } + $input.attr("pattern", pattern); + } + break; + default: + return null; } // Add to a parent if we can. @@ -98,10 +172,25 @@ switch (propertyDef.DataType) { case MFDatatypeText: - var value = $(".auto-select", $listItem).val() + ""; + case MFDatatypeInteger: + case MFDatatypeFloating: + // If it's invalid then mark the list item. + if (!renderer.isValidValue()) + { + if (null != $listItem) + $listItem.addClass("invalid-value") + return false; + } + + // We're good. + if (null != $listItem) + $listItem.removeClass("invalid-value") + + // Set the value. + var value = getCurrentValue(); // Update the property value in memory. - propertyValue.Value.SetValue(MFDatatypeText, value); + propertyValue.Value.SetValue(propertyDef.DataType, value); // Update the UI. if (value.length == 0) @@ -110,6 +199,7 @@ break; } $listItem.removeClass("editing"); + return true; } renderer.render = function () @@ -133,15 +223,12 @@ // Is the property editable? if (propertyDef.AutomaticValueType == MFAutomaticValueTypeNone) { - // Mark it as editable. - $listItem.addClass("editable"); - - // For now only deal with text properties, as that's all we support. - if (propertyDef.DataType == 1) + // Attempt to create the editable value. + var $editableValue = renderEditableValue($listItem); + if (null != $editableValue) { - - // Create the editable value. - renderEditableValue($listItem); + // Mark it as editable. + $listItem.addClass("editable"); // Add the handler to allow editing. $listItem.click(function (e) From 2ea7824e46085df5a67268308cd7d69db58c658c Mon Sep 17 00:00:00 2001 From: Craig Hawker Date: Thu, 1 Dec 2022 12:15:44 +0000 Subject: [PATCH 02/50] Editing and saving of single-line-text and numeric properties works. --- src/Common/src/dashboards/base-dashboard.css | 23 ++++++----- src/UIHelpers/install-application.ps1 | 2 +- .../app/dashboard/dashboard.css | 15 ++++--- .../app/scripts/renderers/objectrenderer.js | 39 ++++++++++++++++++- .../renderers/propertyvaluerenderer.js | 19 +++++++-- 5 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/Common/src/dashboards/base-dashboard.css b/src/Common/src/dashboards/base-dashboard.css index d631cf6..f38ea8b 100644 --- a/src/Common/src/dashboards/base-dashboard.css +++ b/src/Common/src/dashboards/base-dashboard.css @@ -72,16 +72,21 @@ button { text-align: center; } - button:hover, button:active, button.save:active, button.save:hover { - border-color: #318CCC; - background-color: #318CCC; - color: white; - } +button:hover, button:active, button.save:active, button.save:hover { + border-color: #318CCC; + background-color: #318CCC; + color: white; +} - button.save { - border-color: #318CCC; - color: #318CCC; - } +button.save { + border-color: #318CCC; + color: #318CCC; +} +button.save:disabled, button.save[disabled] { + color: #CCC; + border-color: #CCC; + cursor: not-allowed; +} .buttonGroup.top { position: fixed; diff --git a/src/UIHelpers/install-application.ps1 b/src/UIHelpers/install-application.ps1 index d39a281..37f18aa 100644 --- a/src/UIHelpers/install-application.ps1 +++ b/src/UIHelpers/install-application.ps1 @@ -1,4 +1,4 @@ -exit; +#exit; param( diff --git a/src/ViewAllMetadata.UIX/app/dashboard/dashboard.css b/src/ViewAllMetadata.UIX/app/dashboard/dashboard.css index 5902aab..135a01f 100644 --- a/src/ViewAllMetadata.UIX/app/dashboard/dashboard.css +++ b/src/ViewAllMetadata.UIX/app/dashboard/dashboard.css @@ -94,19 +94,22 @@ ol.properties li.editable:hover { background-repeat: no-repeat; background-position: 170px 6px; } -ol.properties li.editable .editing-value{ +ol.properties li.editable .editing-value +{ display: none; } -ol.properties li.editable.editing .read-only-value { +ol.properties li.editable.editing .read-only-value, +ol.properties li.invalid-value .read-only-value { display: none; } -ol.properties li.editable.editing .editing-value { +ol.properties li.editable.editing .editing-value, +ol.properties li.invalid-value .editing-value { display: block; } /* make text, real and integer input boxes full width */ -ol.properties li.mfdatatype-1.editable.editing input, -ol.properties li.mfdatatype-2.editable.editing input, -ol.properties li.mfdatatype-3.editable.editing input { +ol.properties li.mfdatatype-1.editable input, +ol.properties li.mfdatatype-2.editable input, +ol.properties li.mfdatatype-3.editable input { display: inline-block; width: 100%; height: 21px; diff --git a/src/ViewAllMetadata.UIX/app/scripts/renderers/objectrenderer.js b/src/ViewAllMetadata.UIX/app/scripts/renderers/objectrenderer.js index 1005778..a819715 100644 --- a/src/ViewAllMetadata.UIX/app/scripts/renderers/objectrenderer.js +++ b/src/ViewAllMetadata.UIX/app/scripts/renderers/objectrenderer.js @@ -172,7 +172,44 @@ function ObjectRenderer(dashboard) { if (!canSave()) return false; - alert("Save not done yet."); + var vault = dashboard.Vault; + + function getPropertyValueFromRenderer(propertyDef) + { + for (var i = 0; i < propertyValueRenderers.length; i++) + { + if (propertyValueRenderers[i].getPropertyDef().ID == propertyDef) + return propertyValueRenderers[i].getPropertyValue(); + } + return null; + + } + + // Gather the properties. + var propertyValues = new MFiles.PropertyValues(); + for (var i = 0; i < renderer.originalObject.Properties.Count; i++) + { + // Get the value for this property. + var pvValue = getPropertyValueFromRenderer(renderer.originalObject.Properties[i].PropertyDef) + || renderer.originalObject.Properties[i]; + + // Add it. + propertyValues.Add(-1, pvValue); + } + + // Update the properties. + try + { + // Set all the properties and update our cache. + renderer.originalObject = vault.ObjectPropertyOperations.SetAllProperties(renderer.originalObject.VersionData.ObjVer, true, propertyValues); + + // By discarding the changes we'll revert to the (new) original object data. + renderer.discardChanges(); + } + catch (e) + { + MFiles.ReportException(e); + } } // Configure the save button. diff --git a/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js b/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js index bb7d285..70af83e 100644 --- a/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js +++ b/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js @@ -22,6 +22,22 @@ return propertyValue.Value.DisplayValue; } } + renderer.getPropertyValue = function () + { + switch (propertyDef.DataType) + { + case MFDatatypeText: + case MFDatatypeInteger: + case MFDatatypeFloating: + var pv = new MFiles.PropertyValue(); + pv.PropertyDef = propertyDef.ID; + pv.Value.SetValue(propertyDef.DataType, getCurrentValue()); + return pv; + break; + default: + return propertyValue; + } + } renderer.hasChanged = function () { switch (propertyDef.DataType) @@ -189,9 +205,6 @@ // Set the value. var value = getCurrentValue(); - // Update the property value in memory. - propertyValue.Value.SetValue(propertyDef.DataType, value); - // Update the UI. if (value.length == 0) value = "---"; From b8007959455ddf330eb06d64bff8fdfbc5cbc770 Mon Sep 17 00:00:00 2001 From: Craig Hawker Date: Thu, 1 Dec 2022 12:17:23 +0000 Subject: [PATCH 03/50] Limited text property entry to 100 chars. --- .../app/scripts/renderers/propertyvaluerenderer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js b/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js index 70af83e..7f10c71 100644 --- a/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js +++ b/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js @@ -139,7 +139,7 @@ case MFDatatypeText: case MFDatatypeInteger: case MFDatatypeFloating: - var $input = $("").addClass("auto-select"); + var $input = $("").addClass("auto-select"); $input.val(propertyValue.Value.DisplayValue); $input.blur(function () { renderer.exitEditMode(); }); $value.append($input); From a60396eb8381fec156e00f0681e0f889b689040d Mon Sep 17 00:00:00 2001 From: Craig Hawker Date: Thu, 1 Dec 2022 12:18:22 +0000 Subject: [PATCH 04/50] Comments. Regex fix. --- .../app/scripts/renderers/propertyvaluerenderer.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js b/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js index 7f10c71..81b3b57 100644 --- a/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js +++ b/src/ViewAllMetadata.UIX/app/scripts/renderers/propertyvaluerenderer.js @@ -144,7 +144,8 @@ $input.blur(function () { renderer.exitEditMode(); }); $value.append($input); - // If it's a number then set the input mode + // If it's a number then set the input mode. + // Note: this doesn't do anything currently, but maybe in the future... if (propertyDef.DataType != MFDatatypeText) { $input.val(parseFloat(propertyValue.Value.DisplayValue)); @@ -152,7 +153,7 @@ var pattern = "[0-9]*"; // Default to allowing just numbers. if (propertyDef.DataType == MFDatatypeFloating) { - pattern = "[0=9\.\,]*"; // Allow decimal separators too. + pattern = "[0-9\.\,]*"; // Allow decimal separators too. } $input.attr("pattern", pattern); } From d6083e780c745e3e03ace83e153fe3de6ec1d247 Mon Sep 17 00:00:00 2001 From: Craig Hawker Date: Thu, 1 Dec 2022 13:27:42 +0000 Subject: [PATCH 05/50] Better UI for when save is disabled. Some alignment changes in UI. --- src/Common/Common.csproj | 10 ++---- src/Common/src/dashboards/base-dashboard.css | 13 +++++--- .../app/dashboard/dashboard.css | 8 +++-- .../renderers/propertyvaluerenderer.js | 31 ++++++++++++++++--- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/Common/Common.csproj b/src/Common/Common.csproj index 982cd12..e03f33c 100644 --- a/src/Common/Common.csproj +++ b/src/Common/Common.csproj @@ -1,4 +1,4 @@ - + <_BundlerMinifierTaskAssembly Condition="'$(MSBuildRuntimeType)' == 'Core'">..\packages\BuildBundlerMinifier.3.2.449\tools\netstandard1.3\BundlerMinifier.dll @@ -59,16 +59,12 @@ - + - + - - - -