Compare commits

..

No commits in common. "main" and "development" have entirely different histories.

295 changed files with 5547 additions and 17575 deletions

4
Jenkinsfile vendored
View File

@ -1,7 +1,3 @@
properties([
buildDiscarder(logRotator(numToKeepStr: '20'))
])
def deploy() { def deploy() {
node('ubuntu') { node('ubuntu') {
try { try {

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 72 70" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1.093797,0,0,1.093797,0.640357,-0.002979)">
<path d="M39.703,63.992C33.273,63.965 32.923,63.847 31.428,63.333C28.308,62.274 25.677,60.059 24.093,57.166L23.605,56.273L22.819,56.189C21.521,56.058 19.247,55.63 17.735,55.249C11.032,53.558 6.21,50.355 4.507,46.45C4.352,46.116 4.138,45.39 4.031,44.83C3.459,41.997 4.555,39.068 7.079,36.734C7.626,36.222 7.876,35.877 8.031,35.424C8.138,35.091 8.341,34.638 8.46,34.436C8.686,34.067 8.686,34.055 8.341,33.305C7.4,31.269 7.388,29.197 8.329,27.244L8.686,26.506L8.4,25.947C7.698,24.577 7.436,22.732 7.757,21.386L7.9,20.767L7.103,20.041C4.519,17.636 3.4,14.6 4.066,11.718C4.781,8.539 7.198,5.896 11.389,3.681C15.104,1.728 19.473,0.585 25.236,0.073C26.51,-0.046 31.999,0.109 33.488,0.3C40.929,1.252 46.93,3.824 50.157,7.467C53.669,11.432 53.36,16.338 49.371,20.041L48.573,20.767L48.716,21.386C49.038,22.744 48.776,24.565 48.061,25.97C47.775,26.554 47.775,26.566 48.002,26.935C48.537,27.792 48.799,28.876 48.799,30.245C48.799,30.465 48.795,30.668 48.786,30.858C47.381,30.973 46.02,31.246 44.722,31.661C45.016,31.051 45.191,29.981 45.025,29.697C44.93,29.518 44.858,29.53 44.43,29.828C41.763,31.638 38.048,32.948 33.547,33.65C32.059,33.876 31.285,33.924 28.237,33.924C25.189,33.924 24.415,33.876 22.926,33.65C18.545,32.959 14.878,31.709 12.294,29.995C11.484,29.459 11.496,29.459 11.413,29.804C11.222,30.554 11.639,31.709 12.425,32.686C13.687,34.257 16.783,35.865 20.152,36.734C25.553,38.129 31.889,38.015 36.956,36.571C35.707,37.901 34.654,39.418 33.845,41.075C32.625,41.258 31.365,41.384 30.082,41.449L28.499,41.532L29.237,42.33C29.654,42.771 30.308,43.58 30.689,44.128C31.344,45.069 31.404,45.128 31.785,45.069C31.904,45.049 32.16,45.014 32.465,44.973C32.161,46.294 32,47.67 32,49.083C32,51.584 32.504,53.969 33.415,56.141C33.042,56.019 32.813,55.848 32.404,55.606C31.63,55.141 30.725,54.118 30.344,53.26C30.213,52.963 29.951,52.058 29.749,51.26C28.82,47.45 26.891,44.664 23.688,42.509C22.272,41.556 21.39,41.163 18.414,40.187C15.759,39.306 13.496,38.317 12.294,37.496C11.484,36.948 11.508,36.948 11.413,37.424C11.175,38.71 12.294,40.437 14.223,41.747C15.342,42.497 17.259,43.366 19.176,43.997C21.188,44.652 22.2,45.176 23.224,46.069C24.927,47.545 25.546,48.76 26.189,51.808C26.76,54.522 27.57,56.082 29.213,57.642C30.356,58.725 31.416,59.38 32.797,59.845L33.797,60.19L35.768,60.196C36.883,61.649 38.21,62.93 39.703,63.992ZM10.186,43.271C9.71,42.794 9.115,42.08 8.841,41.675L8.365,40.949L8.019,41.687C7.329,43.175 7.662,44.997 8.889,46.462C10.913,48.867 15.223,50.962 20.152,51.927C22.724,52.427 22.498,52.415 22.414,52.022C22.105,50.605 21.605,49.617 20.926,49.01C20.283,48.45 19.438,48.057 17.366,47.355C16.366,47.009 15.068,46.509 14.497,46.235C13.008,45.545 11.198,44.295 10.186,43.271ZM12.818,23.601C12.187,23.327 11.603,23.065 11.532,23.041C11.425,22.994 11.413,23.089 11.472,23.387C12.079,26.066 16.437,28.649 22.081,29.673C24.224,30.066 25.534,30.173 28.237,30.173C30.94,30.173 32.249,30.066 34.392,29.673C40.036,28.649 44.394,26.066 45.001,23.387C45.061,23.089 45.049,22.994 44.942,23.041C44.87,23.065 44.287,23.327 43.656,23.601C40.751,24.875 37.274,25.744 32.987,26.268C31.261,26.482 25.212,26.482 23.486,26.268C19.2,25.744 15.723,24.875 12.818,23.601ZM31.19,3.872C23.391,3.241 15.259,5.098 10.663,8.563C9.448,9.48 8.71,10.337 8.138,11.48C7.722,12.302 7.674,12.516 7.674,13.361C7.674,14.635 8.138,15.623 9.305,16.85C13.115,20.886 22.414,23.327 31.309,22.613C38.429,22.041 44.287,19.922 47.168,16.85C48.335,15.623 48.799,14.635 48.799,13.361C48.799,12.516 48.752,12.302 48.335,11.48C47.764,10.337 47.025,9.48 45.811,8.563C42.37,5.979 37.345,4.36 31.19,3.872ZM25.796,7.932C29.999,7.265 34.869,8.527 36.595,10.718C37.357,11.694 37.548,12.218 37.548,13.361C37.548,14.516 37.357,15.04 36.595,16.016C34.488,18.683 28.249,19.791 23.677,18.302C21.355,17.54 20.057,16.576 19.223,14.992C18.795,14.183 18.795,12.552 19.223,11.742C20.259,9.765 22.533,8.444 25.796,7.932ZM30.118,11.67C27.32,11.206 23.915,11.873 22.807,13.099C22.581,13.361 22.581,13.373 22.807,13.635C23.605,14.504 26.082,15.242 28.237,15.242C30.392,15.242 32.868,14.504 33.666,13.635C33.892,13.373 33.892,13.361 33.666,13.099C33.083,12.468 31.797,11.944 30.118,11.67Z"/>
</g>
<g transform="matrix(1,0,0,1,35.1075,-13.675)">
<path d="M19.178,83.675L21.86,83.675C22.896,83.675 23.714,83.056 23.949,82.006L24.677,79.011C25.075,78.891 25.513,78.706 25.906,78.51L28.52,80.101C29.389,80.672 30.396,80.644 31.191,79.849L33.035,77.979C33.748,77.216 33.821,76.234 33.251,75.277L31.691,72.637C31.913,72.276 32.021,71.92 32.166,71.528L35.186,70.826C36.217,70.564 36.892,69.747 36.892,68.705L36.892,66.06C36.892,65.038 36.191,64.272 35.186,64.011L32.197,63.289C32.038,62.825 31.867,62.484 31.722,62.148L33.37,59.446C33.904,58.571 33.804,57.481 33.086,56.8L31.18,54.956C30.427,54.209 29.411,54.031 28.562,54.596L25.906,56.269C25.436,56.028 25.075,55.914 24.683,55.769L23.949,52.722C23.714,51.712 22.896,51.042 21.86,51.042L19.178,51.042C18.131,51.042 17.304,51.737 17.063,52.728L16.381,55.737C15.886,55.903 15.519,56.028 15.101,56.269L12.444,54.596C11.633,54.068 10.585,54.204 9.852,54.956L7.997,56.8C7.279,57.501 7.077,58.571 7.642,59.446L9.316,62.148C9.166,62.484 8.981,62.876 8.81,63.289L5.852,64.011C4.841,64.272 4.177,65.064 4.177,66.06L4.177,68.705C4.177,69.747 4.847,70.564 5.852,70.826L8.847,71.528C9.037,71.92 9.182,72.276 9.342,72.637L7.782,75.302C7.211,76.234 7.311,77.267 8.023,77.979L9.847,79.849C10.585,80.638 11.613,80.646 12.487,80.101L15.158,78.51C15.596,78.757 15.989,78.891 16.381,79.011L17.063,82.006C17.299,83.005 18.131,83.675 19.178,83.675ZM20.491,72.507C17.681,72.507 15.371,70.197 15.371,67.387C15.371,64.551 17.681,62.236 20.491,62.236C23.326,62.236 25.642,64.551 25.642,67.387C25.642,70.197 23.326,72.507 20.491,72.507Z" style="fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.989624,0,0,0.989624,3,3.012667)">
<path d="M32.232,55.642C32.232,57.251 30.901,58.583 29.291,58.583C27.682,58.583 26.351,57.251 26.351,55.642C26.351,54.032 27.682,52.701 29.291,52.701C30.901,52.701 32.232,54.032 32.232,55.642ZM32.232,46.867C32.232,48.476 30.901,49.807 29.291,49.807C27.682,49.807 26.351,48.476 26.351,46.867C26.351,45.258 27.682,43.926 29.291,43.926C30.901,43.926 32.232,45.258 32.232,46.867ZM32.232,38.066C32.232,39.676 30.901,41.007 29.291,41.007C28.398,41.007 27.591,40.597 27.05,39.956C27.916,38.466 28.763,36.862 29.604,35.143C31.07,35.301 32.232,36.562 32.232,38.066ZM58.608,29.291C58.608,30.901 57.277,32.232 55.667,32.232C54.058,32.232 52.727,30.901 52.727,29.291C52.727,27.682 54.058,26.351 55.667,26.351C57.277,26.351 58.608,27.682 58.608,29.291ZM5.881,29.291C5.881,30.901 4.55,32.232 2.941,32.232C1.331,32.232 0,30.901 0,29.291C0,27.682 1.331,26.351 2.941,26.351C4.55,26.351 5.881,27.682 5.881,29.291ZM14.656,29.291C14.656,30.901 13.351,32.232 11.716,32.232C10.106,32.232 8.775,30.901 8.775,29.291C8.775,27.682 10.106,26.351 11.716,26.351C13.351,26.351 14.656,27.682 14.656,29.291ZM23.457,29.291C23.457,30.901 22.126,32.232 20.516,32.232C18.907,32.232 17.576,30.901 17.576,29.291C17.576,27.682 18.907,26.351 20.516,26.351C22.126,26.351 23.457,27.682 23.457,29.291ZM41.032,29.291C41.032,30.901 39.701,32.232 38.092,32.232C36.483,32.232 35.151,30.901 35.151,29.291C35.151,27.682 36.483,26.351 38.092,26.351C39.701,26.351 41.032,27.682 41.032,29.291ZM49.807,29.291C49.807,30.901 48.476,32.232 46.867,32.232C45.258,32.232 43.926,30.901 43.926,29.291C43.926,27.682 45.258,26.351 46.867,26.351C48.476,26.351 49.807,27.682 49.807,29.291ZM31.442,31.281C31.58,30.996 31.718,30.691 31.857,30.384C31.977,30.118 32.096,29.855 32.214,29.607C32.145,30.248 31.864,30.83 31.442,31.281ZM26.771,28.065L26.377,28.924C26.451,28.32 26.715,27.77 27.108,27.338L26.771,28.065ZM31.523,18.59C30.658,20.084 29.813,21.691 28.972,23.413C27.51,23.255 26.351,22.016 26.351,20.491C26.351,18.881 27.682,17.55 29.291,17.55C30.179,17.55 30.983,17.955 31.523,18.59ZM32.232,11.716C32.232,13.325 30.901,14.656 29.291,14.656C27.682,14.656 26.351,13.325 26.351,11.716C26.351,10.106 27.682,8.775 29.291,8.775C30.901,8.775 32.232,10.106 32.232,11.716ZM32.232,2.941C32.232,4.55 30.901,5.881 29.291,5.881C27.682,5.881 26.351,4.55 26.351,2.941C26.351,1.331 27.682,0 29.291,0C30.901,0 32.232,1.331 32.232,2.941Z" style="fill-rule:nonzero;"/>
<path d="M2.803,52.396C1.307,52.643 0.237,54.108 0.504,55.597C0.751,57.093 2.216,58.169 3.711,57.928C17.696,55.598 24.556,46.57 31.857,30.384C38.113,16.508 43.608,8.067 55.805,6.052C57.295,5.806 58.371,4.341 58.129,2.851C57.851,1.356 56.392,0.28 54.897,0.521C40.932,2.825 34.078,11.879 26.771,28.065C20.515,41.941 15,50.382 2.803,52.396Z" style="fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.824327,0,0,0.976141,2.488276,-2.712014)">
<path d="M56.78,22.995C64.017,23.632 69.667,28.805 69.667,35.084L69.667,42.696C69.667,49.405 63.217,54.851 55.273,54.851L52.514,54.851L39.525,64.685C37.406,66.289 34.196,66.289 32.077,64.685L19.088,54.851L16.329,54.851C8.385,54.851 1.935,49.405 1.935,42.696L1.935,35.084C1.935,28.805 7.585,23.632 14.822,22.995L14.822,8.007C14.822,6.476 16.294,5.233 18.107,5.233C19.921,5.233 21.393,6.476 21.393,8.007L21.393,22.929L50.209,22.929L50.209,8.007C50.209,6.476 51.681,5.233 53.495,5.233C55.308,5.233 56.78,6.476 56.78,8.007L56.78,22.995ZM28.932,54.851L35.801,60.052L42.67,54.851L28.932,54.851ZM55.273,49.302C59.591,49.302 63.096,46.342 63.096,42.696L63.096,35.084C63.096,31.438 59.591,28.478 55.273,28.478L16.329,28.478C12.011,28.478 8.506,31.438 8.506,35.084L8.506,42.696C8.506,46.342 12.011,49.302 16.329,49.302L55.273,49.302Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.881796,0,0,0.881796,2.413866,6)">
<path d="M8.144,48.624L11.105,53.718L33.55,42.441L55.994,53.718L58.987,48.624L36.537,37.341L36.537,10.769L30.594,10.769L30.594,37.341L8.144,48.624ZM0.384,53.413C-0.592,55.654 0.33,57.211 2.725,57.489L15.69,58.924C18.959,59.318 20.849,57.171 19.138,54.231L11.408,40.828C9.765,37.956 6.931,38.488 5.654,41.467L0.384,53.413ZM66.721,53.413L61.477,41.467C60.174,38.488 57.366,37.956 55.717,40.828L47.962,54.231C46.256,57.171 48.172,59.318 51.415,58.924L64.38,57.489C66.77,57.211 67.697,55.654 66.721,53.413ZM31.172,1.489L23.477,11.964C21.527,14.591 22.46,17.332 25.814,17.332L41.248,17.332C44.665,17.332 45.558,14.639 43.592,11.97L35.87,1.484C34.395,-0.486 32.642,-0.506 31.172,1.489Z" style="fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.783639,0,0,0.783639,3,9.136381)">
<path d="M10.966,55.715L61.631,55.715C67.901,55.715 71.026,52.48 70.761,46.429L52.249,29.059C50.874,27.784 49.224,27.139 47.553,27.139C45.84,27.139 44.303,27.727 42.877,29.003L28.763,41.616L22.999,36.414C21.686,35.233 20.243,34.639 18.78,34.639C17.334,34.639 16.041,35.201 14.754,36.383L2.961,46.953C3.114,52.711 5.792,55.715 10.966,55.715ZM10.251,58.341L63.763,58.341C70.533,58.341 74.014,54.886 74.014,48.218L74.014,10.16C74.014,3.486 70.533,0.011 63.763,0.011L10.251,0.011C3.506,0.011 0,3.486 0,10.16L0,48.218C0,54.886 3.506,58.341 10.251,58.341ZM10.606,52.219C7.701,52.219 6.122,50.714 6.122,47.678L6.122,10.694C6.122,7.658 7.701,6.134 10.606,6.134L63.407,6.134C66.287,6.134 67.891,7.658 67.891,10.694L67.891,47.678C67.891,50.714 66.287,52.219 63.407,52.219L10.606,52.219Z" style="fill-rule:nonzero;"/>
<path d="M24.209,29.743C28.302,29.743 31.677,26.369 31.677,22.239C31.677,18.146 28.302,14.74 24.209,14.74C20.079,14.74 16.705,18.146 16.705,22.239C16.705,26.369 20.079,29.743 24.209,29.743Z" style="fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 72 70" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path d="M38.645,64.222L17.549,64.222C11.671,64.198 8.506,61.129 8.506,55.228L8.506,13.858C8.506,7.958 11.939,4.864 17.619,4.864L54.008,4.864C59.907,4.864 63.096,7.958 63.096,13.858L63.096,35.121C61.386,34.433 59.559,33.974 57.653,33.783L57.653,22.31L54.347,22.31L54.347,23.05C54.347,27.911 52.199,30.851 48.168,31.749L45.342,34.575C44.524,35.393 43.197,35.393 42.379,34.575L39.549,31.745C35.516,30.843 33.374,27.904 33.374,23.05L33.374,22.31L13.973,22.31L13.973,55.44C13.973,57.721 15.098,58.965 17.297,59.072C17.269,58.754 17.255,58.42 17.255,58.07L17.255,54.215C17.255,49.957 19.434,48.069 23.402,48.069L36.442,48.069C35.975,49.668 35.702,51.349 35.651,53.085L24.624,53.085C23.237,53.085 22.516,53.749 22.516,55.165L22.516,57.102C22.516,58.518 23.237,59.21 24.624,59.21L36.417,59.21C36.93,60.995 37.685,62.679 38.645,64.222ZM57.653,17.418L57.653,13.652C57.653,11.264 56.396,10.001 54.013,10.001L17.613,10.001C15.206,10.001 13.973,11.264 13.973,13.652L13.973,17.418L33.807,17.418C34.894,13.675 37.985,11.731 42.487,11.731L45.258,11.731C49.934,11.731 52.908,13.675 53.94,17.418L57.653,17.418ZM42.481,16.868C40.074,16.868 38.841,18.13 38.841,20.518L38.841,23.262C38.841,25.65 40.074,26.902 42.481,26.902L45.264,26.902C47.647,26.902 48.904,25.65 48.904,23.262L48.904,20.518C48.904,18.149 47.666,16.888 45.32,16.868L42.481,16.868Z"/>
<g transform="matrix(1,0,0,1,35.1075,-13.675)">
<path d="M19.178,83.675L21.86,83.675C22.896,83.675 23.714,83.056 23.949,82.006L24.677,79.011C25.075,78.891 25.513,78.706 25.906,78.51L28.52,80.101C29.389,80.672 30.396,80.644 31.191,79.849L33.035,77.979C33.748,77.216 33.821,76.234 33.251,75.277L31.691,72.637C31.913,72.276 32.021,71.92 32.166,71.528L35.186,70.826C36.217,70.564 36.892,69.747 36.892,68.705L36.892,66.06C36.892,65.038 36.191,64.272 35.186,64.011L32.197,63.289C32.038,62.825 31.867,62.484 31.722,62.148L33.37,59.446C33.904,58.571 33.804,57.481 33.086,56.8L31.18,54.956C30.427,54.209 29.411,54.031 28.562,54.596L25.906,56.269C25.436,56.028 25.075,55.914 24.683,55.769L23.949,52.722C23.714,51.712 22.896,51.042 21.86,51.042L19.178,51.042C18.131,51.042 17.304,51.737 17.063,52.728L16.381,55.737C15.886,55.903 15.519,56.028 15.101,56.269L12.444,54.596C11.633,54.068 10.585,54.204 9.852,54.956L7.997,56.8C7.279,57.501 7.077,58.571 7.642,59.446L9.316,62.148C9.166,62.484 8.981,62.876 8.81,63.289L5.852,64.011C4.841,64.272 4.177,65.064 4.177,66.06L4.177,68.705C4.177,69.747 4.847,70.564 5.852,70.826L8.847,71.528C9.037,71.92 9.182,72.276 9.342,72.637L7.782,75.302C7.211,76.234 7.311,77.267 8.023,77.979L9.847,79.849C10.585,80.638 11.613,80.646 12.487,80.101L15.158,78.51C15.596,78.757 15.989,78.891 16.381,79.011L17.063,82.006C17.299,83.005 18.131,83.675 19.178,83.675ZM20.491,72.507C17.681,72.507 15.371,70.197 15.371,67.387C15.371,64.551 17.681,62.236 20.491,62.236C23.326,62.236 25.642,64.551 25.642,67.387C25.642,70.197 23.326,72.507 20.491,72.507Z" style="fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.781552,0,0,0.781552,1,17.941979)">
<path d="M79.329,9.044C79.329,3.244 76.045,0.021 70.183,0.021L9.093,0.021C3.221,0.021 0,3.244 0,9.044L0,26.911C0,32.701 3.263,35.953 9.125,35.953L70.225,35.953C76.077,35.953 79.329,32.701 79.329,26.911L79.329,9.044ZM72.826,10.089L72.826,25.876C72.826,28.201 71.564,29.461 69.323,29.461L9.964,29.461C7.775,29.461 6.482,28.201 6.482,25.876L6.482,10.089C6.482,7.763 7.785,6.503 9.995,6.503L69.354,6.503C71.564,6.503 72.826,7.763 72.826,10.089ZM13.04,4.664L10.112,4.664L10.112,20.338C10.112,21.156 10.774,21.776 11.602,21.776C12.461,21.776 13.04,21.134 13.04,20.297L13.04,4.664ZM18.661,4.664L15.732,4.664L15.732,15.295C15.732,16.144 16.404,16.744 17.211,16.744C18.092,16.744 18.661,16.123 18.661,15.264L18.661,4.664ZM24.27,4.664L21.32,4.664L21.32,15.295C21.32,16.144 22.014,16.744 22.81,16.744C23.67,16.744 24.27,16.123 24.27,15.264L24.27,4.664ZM29.849,4.664L26.92,4.664L26.92,15.295C26.92,16.144 27.592,16.744 28.42,16.744C29.279,16.744 29.849,16.123 29.849,15.264L29.849,4.664ZM35.479,4.664L32.55,4.664L32.55,15.295C32.55,16.144 33.222,16.744 34.019,16.744C34.9,16.744 35.479,16.123 35.479,15.264L35.479,4.664ZM41.11,4.664L38.181,4.664L38.181,20.338C38.181,21.156 38.843,21.776 39.65,21.776C40.53,21.776 41.11,21.134 41.11,20.297L41.11,4.664ZM46.709,4.664L43.781,4.664L43.781,15.295C43.781,16.144 44.452,16.744 45.259,16.744C46.118,16.744 46.709,16.123 46.709,15.264L46.709,4.664ZM52.319,4.664L49.39,4.664L49.39,15.295C49.39,16.144 50.062,16.744 50.88,16.744C51.739,16.744 52.319,16.123 52.319,15.264L52.319,4.664ZM57.918,4.664L54.999,4.664L54.999,15.295C54.999,16.144 55.661,16.744 56.468,16.744C57.348,16.744 57.918,16.123 57.918,15.264L57.918,4.664ZM63.548,4.664L60.62,4.664L60.62,15.295C60.62,16.144 61.292,16.744 62.088,16.744C62.948,16.744 63.548,16.123 63.548,15.264L63.548,4.664ZM69.158,4.664L66.229,4.664L66.229,20.338C66.229,21.156 66.891,21.776 67.719,21.776C68.578,21.776 69.158,21.134 69.158,20.297L69.158,4.664Z" style="fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 64 64" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(0.800063,0,0,0.800063,1,5.597937)">
<path d="M75.036,26.688L59.489,26.688C57.02,26.688 56.427,28.797 57.739,30.578L65.442,40.938C66.427,42.266 68.099,42.281 69.083,40.938L76.802,30.594C78.145,28.797 77.52,26.688 75.036,26.688ZM38.755,8.219C52.458,8.219 63.536,19.297 63.536,33.031C63.536,35.281 65.38,37.125 67.661,37.125C69.911,37.125 71.739,35.297 71.755,33.047C71.739,14.75 56.974,0 38.755,0C30.599,0 23.161,3.078 17.583,8.094C15.364,9.812 15.552,12.531 16.974,14.109C18.239,15.547 20.395,16.141 22.802,14.391C26.974,10.547 32.583,8.219 38.755,8.219ZM2.458,39.312L18.02,39.312C20.474,39.312 21.067,37.188 19.77,35.422L12.052,25.047C11.067,23.734 9.411,23.719 8.427,25.047L0.692,35.406C-0.651,37.188 -0.026,39.312 2.458,39.312ZM38.755,57.781C25.052,57.781 13.958,46.703 13.958,32.969C13.958,30.703 12.114,28.859 9.833,28.859C7.583,28.859 5.755,30.688 5.739,32.938C5.755,51.234 20.52,66 38.755,66C46.911,66 54.349,62.922 59.911,57.906C62.13,56.156 61.942,53.469 60.52,51.875C59.255,50.453 57.099,49.844 54.692,51.594C50.52,55.422 44.911,57.781 38.755,57.781Z" style="fill-rule:nonzero;"/>
<path d="M37.411,48.156L39.974,48.156C40.927,48.156 41.661,47.578 41.864,46.641L42.552,43.812C42.942,43.656 43.317,43.516 43.661,43.344L46.145,44.875C46.942,45.375 47.911,45.297 48.552,44.625L50.317,42.844C50.989,42.172 51.083,41.188 50.567,40.391L49.067,37.938C49.224,37.594 49.38,37.234 49.489,36.875L52.349,36.203C53.27,35.984 53.864,35.25 53.864,34.266L53.864,31.781C53.864,30.828 53.27,30.094 52.349,29.891L49.52,29.219C49.395,28.812 49.224,28.438 49.083,28.109L50.599,25.625C51.114,24.812 51.036,23.859 50.349,23.188L48.536,21.406C47.88,20.797 46.989,20.641 46.192,21.109L43.661,22.672C43.317,22.516 42.974,22.359 42.567,22.219L41.864,19.344C41.645,18.406 40.927,17.828 39.974,17.828L37.411,17.828C36.458,17.828 35.739,18.406 35.52,19.359L34.833,22.188C34.442,22.328 34.052,22.484 33.692,22.656L31.192,21.109C30.38,20.641 29.505,20.766 28.833,21.406L27.02,23.188C26.349,23.859 26.27,24.812 26.77,25.625L28.286,28.109C28.145,28.438 28.005,28.812 27.849,29.219L25.02,29.891C24.099,30.094 23.52,30.828 23.52,31.781L23.52,34.266C23.52,35.25 24.099,35.984 25.02,36.203L27.88,36.875C28.02,37.234 28.145,37.594 28.302,37.938L26.833,40.391C26.302,41.188 26.395,42.172 27.067,42.844L28.817,44.625C29.489,45.297 30.442,45.375 31.239,44.875L33.708,43.344C34.067,43.516 34.442,43.656 34.833,43.812L35.52,46.641C35.739,47.578 36.458,48.156 37.411,48.156ZM38.692,37.797C36.02,37.797 33.849,35.641 33.849,32.969C33.849,30.312 36.02,28.125 38.692,28.125C41.349,28.125 43.52,30.312 43.52,32.969C43.52,35.641 41.349,37.797 38.692,37.797Z" style="fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -39,9 +39,6 @@
.ant-splitter, .ant-splitter,
.ant-steps-item-title, .ant-steps-item-title,
.ant-steps-icon, .ant-steps-icon,
.ant-color-picker-presets-label,
.ant-select-selection-item,
.ant-color-picker-trigger-text,
[class*=' ant-radio'] { [class*=' ant-radio'] {
font-family: 'DM Sans'; font-family: 'DM Sans';
} }
@ -83,23 +80,6 @@
font-size: 95%; font-size: 95%;
} }
.ant-select-selection-item .country-display {
margin-left: 1px !important;
}
.object-display-tag,
.object-type-display-tag,
.country-display {
opacity: 1;
transition: opacity 0.15s ease-in-out;
}
.object-select.ant-select-focused .object-display-tag,
.ant-select-focused .object-type-display-tag,
.ant-select-focused .country-display {
opacity: 0.5;
}
.flag { .flag {
line-height: 0.7; line-height: 0.7;
} }
@ -139,8 +119,6 @@
:root { :root {
--unit-100vh: 100vh; --unit-100vh: 100vh;
--scrollbox-vertical-right-padding: 16px;
--scrollbox-horizontal-bottom-padding: 16px;
} }
@supports (height: 100dvh) { @supports (height: 100dvh) {
:root { :root {
@ -218,7 +196,6 @@ code {
/* --- Start of src/index.css --- */ /* --- Start of src/index.css --- */
body { body {
margin: 0; margin: 0;
overflow: hidden;
} }
.ant-modal-mask { .ant-modal-mask {
@ -281,11 +258,6 @@ body {
margin: 8px; margin: 8px;
} }
.farmcontrol-splitter.large > .ant-splitter-bar {
margin: 11px;
opacity: 0.6;
}
.dark-mode { .dark-mode {
--sb-track-color: #1d1d1d; --sb-track-color: #1d1d1d;
--sb-thumb-color: #848484; --sb-thumb-color: #848484;
@ -359,36 +331,15 @@ body {
margin-left: 1px !important; margin-left: 1px !important;
} }
.tags-input.ant-select-multiple .ant-select-selection-item,
.tags-input.ant-tree-select.ant-select-multiple .ant-select-selection-item {
background: transparent !important;
border: none !important;
padding: 0 !important;
margin-inline-end: 0 !important;
height: auto !important;
line-height: normal !important;
}
.tags-input.ant-select-multiple .ant-select-selection-item-remove,
.tags-input.ant-tree-select.ant-select-multiple
.ant-select-selection-item-remove {
display: none;
}
.ant-badge.ant-badge-status { .ant-badge.ant-badge-status {
line-height: 18.5px; line-height: 18.5px;
} }
.simplebar-track.simplebar-vertical { .simplebar-track.simplebar-vertical {
right: calc(-1 * var(--scrollbox-vertical-right-padding)); right: -16px;
width: 8px !important; width: 8px !important;
} }
.simplebar-track.simplebar-horizontal {
bottom: calc(-1 * var(--scrollbox-horizontal-bottom-padding));
height: 8px !important;
}
.simplebar-scrollbar:before { .simplebar-scrollbar:before {
background: #78787854 !important; background: #78787854 !important;
} }
@ -418,7 +369,7 @@ body {
margin-right: 1px !important; margin-right: 1px !important;
} }
.object-select .ant-select-selection-item .object-display-tag { .ant-select-selection-item .object-display-tag {
top: 1.5px; top: 1.5px;
} }
@ -580,7 +531,7 @@ body {
.markdown p { .markdown p {
font-size: 14px; font-size: 14px;
margin: 10px 0; margin: 10px 0;
line-height: 1.6; line-height: 1;
} }
.markdown h1 { .markdown h1 {
@ -603,10 +554,6 @@ body {
width: 100%; width: 100%;
} }
.property-changes .markdown {
width: unset;
}
.markdown ul, .markdown ul,
.markdown ol { .markdown ol {
padding-left: 20px; padding-left: 20px;
@ -640,7 +587,6 @@ body {
.h-100 { .h-100 {
height: 100%; height: 100%;
min-height: 0;
} }
.ant-table.ant-table-middle .ant-table-filter-trigger { .ant-table.ant-table-middle .ant-table-filter-trigger {
@ -656,189 +602,3 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton {
min-width: 0; min-width: 0;
height: 20px; height: 20px;
} }
.sidebar-scroll .simplebar-track.simplebar-vertical {
right: -1px;
width: 0px !important;
transition:
width 0.15s ease-in-out,
right 0.15s ease-in-out;
}
.sidebar-scroll .simplebar-track.simplebar-vertical {
border-radius: 0 0 6.5px 0;
}
.sidebar-scroll.dark .simplebar-track.simplebar-vertical {
background-color: #141414;
border-inline-end: 1px solid rgba(253, 253, 253, 0.12);
border-bottom: 1px solid rgba(253, 253, 253, 0.12);
}
.sidebar-scroll.light .simplebar-track.simplebar-vertical {
background-color: #ffffff;
border-inline-end: 1px solid rgba(5, 5, 5, 0.06);
border-bottom: 1px solid rgba(5, 5, 5, 0.06);
}
.sidebar-scroll.simplebar-scrolling .simplebar-track.simplebar-vertical {
width: 12px !important;
right: -13px;
}
.sidebar-scroll
.simplebar-track.simplebar-vertical
.simplebar-scrollbar:before {
top: 4px;
bottom: 4px;
left: 4px;
right: 4px;
}
.ant-color-picker
.ant-color-picker-inner
.ant-color-picker-panel
.ant-color-picker-select
.ant-color-picker-palette {
border-radius: 8px;
}
.ant-color-picker
.ant-collapse
.ant-collapse-item:last-child
.ant-collapse-content-box {
padding-bottom: 0 !important;
}
.ant-color-picker .ant-collapse .ant-collapse-expand-icon {
height: 12px !important;
padding-inline-end: 8px !important;
}
.ant-color-picker .ant-color-picker-inner .ant-color-picker-presets-label {
line-height: 1 !important;
}
.ant-color-picker
.ant-collapse
.ant-collapse-item:first-child
.ant-collapse-header {
margin: 0 0 5.5px 0;
}
.ant-color-picker .ant-collapse .ant-collapse-item .ant-collapse-header {
margin: 5.5px 0;
}
.subSteps.ant-timeline .ant-timeline-item-last > .ant-timeline-item-content {
min-height: unset;
}
.subSteps.ant-timeline .ant-timeline-item-last {
padding-bottom: 6px;
}
.subSteps.ant-timeline {
margin-top: 16px;
}
.ant-steps.ant-steps-vertical
> .ant-steps-item
> .ant-steps-item-container
> .ant-steps-item-tail::after {
width: 1.5px;
}
.subSteps.ant-timeline .ant-timeline-item-head {
background-color: unset;
}
.subSteps.ant-timeline .subSteps-dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: var(--color-primary);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.subSteps.ant-timeline .subSteps-dot svg path {
stroke: var(--layout-modal-bg);
stroke-width: 10px;
}
.subSteps.ant-timeline .subSteps-dot span {
width: 5px;
height: 5px;
margin-top: 0px;
margin-right: 0px;
}
.subSteps.ant-timeline .subSteps-dot.subSteps-dot-disabled {
background-color: var(--color-primary-disabled);
}
.subSteps.ant-timeline .subSteps-dot.subSteps-dot-disabled svg path {
stroke: var(--color-primary);
}
.ant-steps .ant-steps-item-finish .ant-steps-item-icon svg path {
stroke: var(--color-primary);
stroke-width: 3px;
}
.ant-descriptions .ant-descriptions-item-label::after {
top: 0;
}
.ant-descriptions-small .ant-descriptions-row > td {
padding-bottom: 6px;
}
.minimal-code-block-editor .ant-typography pre {
margin: 0;
}
.ant-splitter-panel:not(:first-child) .info-collapse .info-collapse-label {
margin-left: 4px;
}
.farmcontrol-splitter .ant-splitter-panel {
overflow: visible;
}
.farmcontrol-splitter.ant-splitter-horizontal .ant-splitter-panel {
width: 100%;
min-width: 0;
}
.farmcontrol-splitter
.ant-splitter-panel:has(~ .ant-splitter-panel)
.info-collapse.ant-collapse.ant-collapse-icon-position-end
> .ant-collapse-item
> .ant-collapse-header
.ant-collapse-expand-icon {
padding-inline-end: 2px;
}
.objectTableCards {
overflow: hidden;
}
.objectTableCardsContainer {
width: 100%;
height: 100%;
min-width: 0;
}
.objectTableCardsContainer .ant-spin-nested-loading {
width: 100%;
height: 100%;
}
.objectTableCardsContainer .ant-spin-container {
width: 100%;
height: 100%;
}

View File

@ -25,11 +25,7 @@
"@codemirror/lang-sql": "^6.9.1", "@codemirror/lang-sql": "^6.9.1",
"@codemirror/lang-xml": "^6.1.0", "@codemirror/lang-xml": "^6.1.0",
"@codemirror/lang-yaml": "^6.1.2", "@codemirror/lang-yaml": "^6.1.2",
"@codemirror/commands": "6.10.4",
"@codemirror/language": "6.12.1",
"@codemirror/state": "6.7.1",
"@codemirror/theme-one-dark": "^6.1.3", "@codemirror/theme-one-dark": "^6.1.3",
"@codemirror/view": "6.39.12",
"@simplewebauthn/browser": "^13.1.2", "@simplewebauthn/browser": "^13.1.2",
"@tanstack/react-query": "^5.90.10", "@tanstack/react-query": "^5.90.10",
"@tiptap/extension-link": "^3.20.1", "@tiptap/extension-link": "^3.20.1",
@ -46,8 +42,6 @@
"antd": "^5.27.1", "antd": "^5.27.1",
"antd-style": "^3.7.1", "antd-style": "^3.7.1",
"axios": "^1.11.0", "axios": "^1.11.0",
"blurhash": "^2.0.5",
"codemirror": "^6.0.2",
"country-list": "^2.4.1", "country-list": "^2.4.1",
"cross-env": "^10.0.0", "cross-env": "^10.0.0",
"dayjs": "^1.11.18", "dayjs": "^1.11.18",
@ -86,7 +80,7 @@
"electron": "cross-env ELECTRON_START_URL=http://0.0.0.0:5780 && cross-env NODE_ENV=development && electron .", "electron": "cross-env ELECTRON_START_URL=http://0.0.0.0:5780 && cross-env NODE_ENV=development && electron .",
"start": "serve -s build", "start": "serve -s build",
"build": "vite build", "build": "vite build",
"dev:electron": "concurrently \"cross-env NODE_ENV=development vite --port 5780 --no-open\" \"cross-env ELECTRON_START_URL=http://localhost:5780 NODE_ENV=development electron public/electron.js\"", "dev:electron": "concurrently \"cross-env NODE_ENV=development vite --port 5780 --no-open\" \"cross-env ELECTRON_START_URL=http://localhost:5780 cross-env NODE_ENV=development electron public/electron.js\"",
"build:electron": "vite build && electron-builder", "build:electron": "vite build && electron-builder",
"build:cloudflare": "cross-env VITE_DEPLOY_TARGET=cloudflare vite build", "build:cloudflare": "cross-env VITE_DEPLOY_TARGET=cloudflare vite build",
"deploy": "npm run build:cloudflare && wrangler pages deploy --branch main" "deploy": "npm run build:cloudflare && wrangler pages deploy --branch main"
@ -219,7 +213,7 @@
"win": { "win": {
"target": [ "target": [
"nsis", "nsis",
"msiWrapped" "msi"
], ],
"protocols": [ "protocols": [
{ {
@ -238,12 +232,6 @@
"allowToChangeInstallationDirectory": true, "allowToChangeInstallationDirectory": true,
"include": "scripts/installer.nsh", "include": "scripts/installer.nsh",
"perMachine": true "perMachine": true
},
"msiWrapped": {
"upgradeCode": "{735812DB-E33B-57A0-8FBC-5FC3155925AA}",
"perMachine": true,
"impersonate": false,
"wrappedInstallerArgs": "/S"
} }
} }
} }

204
pnpm-lock.yaml generated
View File

@ -4,14 +4,6 @@ settings:
autoInstallPeers: true autoInstallPeers: true
excludeLinksFromLockfile: false excludeLinksFromLockfile: false
overrides:
baseline-browser-mapping: 2.11.4
'@codemirror/state': 6.7.1
'@codemirror/view': 6.39.12
'@codemirror/language': 6.12.1
'@codemirror/commands': 6.10.4
'@codemirror/autocomplete': 6.20.0
importers: importers:
.: .:
@ -22,9 +14,6 @@ importers:
'@babel/plugin-transform-private-property-in-object': '@babel/plugin-transform-private-property-in-object':
specifier: ^7.27.1 specifier: ^7.27.1
version: 7.28.6(@babel/core@7.29.0) version: 7.28.6(@babel/core@7.29.0)
'@codemirror/commands':
specifier: 6.10.4
version: 6.10.4
'@codemirror/lang-cpp': '@codemirror/lang-cpp':
specifier: ^6.0.3 specifier: ^6.0.3
version: 6.0.3 version: 6.0.3
@ -67,18 +56,9 @@ importers:
'@codemirror/lang-yaml': '@codemirror/lang-yaml':
specifier: ^6.1.2 specifier: ^6.1.2
version: 6.1.2 version: 6.1.2
'@codemirror/language':
specifier: 6.12.1
version: 6.12.1
'@codemirror/state':
specifier: 6.7.1
version: 6.7.1
'@codemirror/theme-one-dark': '@codemirror/theme-one-dark':
specifier: ^6.1.3 specifier: ^6.1.3
version: 6.1.3 version: 6.1.3
'@codemirror/view':
specifier: 6.39.12
version: 6.39.12
'@simplewebauthn/browser': '@simplewebauthn/browser':
specifier: ^13.1.2 specifier: ^13.1.2
version: 13.2.2 version: 13.2.2
@ -114,7 +94,7 @@ importers:
version: 3.9.1 version: 3.9.1
'@uiw/react-codemirror': '@uiw/react-codemirror':
specifier: ^4.25.1 specifier: ^4.25.1
version: 4.25.4(@babel/runtime@7.28.6)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.3)(@codemirror/search@6.6.0)(@codemirror/state@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.12)(codemirror@6.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) version: 4.25.4(@babel/runtime@7.28.6)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.3)(@codemirror/search@6.6.0)(@codemirror/state@6.5.4)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.12)(codemirror@6.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
'@vscode/sudo-prompt': '@vscode/sudo-prompt':
specifier: ^9.3.2 specifier: ^9.3.2
version: 9.3.2 version: 9.3.2
@ -127,12 +107,6 @@ importers:
axios: axios:
specifier: ^1.11.0 specifier: ^1.11.0
version: 1.13.4 version: 1.13.4
blurhash:
specifier: ^2.0.5
version: 2.0.5
codemirror:
specifier: ^6.0.2
version: 6.0.2
country-list: country-list:
specifier: ^2.4.1 specifier: ^2.4.1
version: 2.4.1 version: 2.4.1
@ -530,8 +504,8 @@ packages:
'@codemirror/autocomplete@6.20.0': '@codemirror/autocomplete@6.20.0':
resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==} resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==}
'@codemirror/commands@6.10.4': '@codemirror/commands@6.10.1':
resolution: {integrity: sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg==} resolution: {integrity: sha512-uWDWFypNdQmz2y1LaNJzK7fL7TYKLeUAU0npEC685OKTF3KcQ2Vu3klIM78D7I6wGhktme0lh3CuQLv0ZCrD9Q==}
'@codemirror/lang-cpp@6.0.3': '@codemirror/lang-cpp@6.0.3':
resolution: {integrity: sha512-URM26M3vunFFn9/sm6rzqrBzDgfWuDixp85uTY49wKudToc2jTHUrKIGGKs+QWND+YLofNNZpxcNGRynFJfvgA==} resolution: {integrity: sha512-URM26M3vunFFn9/sm6rzqrBzDgfWuDixp85uTY49wKudToc2jTHUrKIGGKs+QWND+YLofNNZpxcNGRynFJfvgA==}
@ -584,8 +558,8 @@ packages:
'@codemirror/search@6.6.0': '@codemirror/search@6.6.0':
resolution: {integrity: sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==} resolution: {integrity: sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==}
'@codemirror/state@6.7.1': '@codemirror/state@6.5.4':
resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} resolution: {integrity: sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw==}
'@codemirror/theme-one-dark@6.1.3': '@codemirror/theme-one-dark@6.1.3':
resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==} resolution: {integrity: sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==}
@ -1240,9 +1214,6 @@ packages:
'@lezer/common@1.5.0': '@lezer/common@1.5.0':
resolution: {integrity: sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==} resolution: {integrity: sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==}
'@lezer/common@1.5.2':
resolution: {integrity: sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==}
'@lezer/cpp@1.1.5': '@lezer/cpp@1.1.5':
resolution: {integrity: sha512-DIhSXmYtJKLehrjzDFN+2cPt547ySQ41nA8yqcDf/GxMc+YM736xqltFkvADL2M0VebU5I+3+4ks2Vv+Kyq3Aw==} resolution: {integrity: sha512-DIhSXmYtJKLehrjzDFN+2cPt547ySQ41nA8yqcDf/GxMc+YM736xqltFkvADL2M0VebU5I+3+4ks2Vv+Kyq3Aw==}
@ -1300,8 +1271,8 @@ packages:
resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
'@marijn/find-cluster-break@1.0.3': '@marijn/find-cluster-break@1.0.2':
resolution: {integrity: sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==} resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
'@nodelib/fs.scandir@2.1.5': '@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
@ -2021,9 +1992,6 @@ packages:
'@types/estree@1.0.8': '@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/estree@1.0.9':
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
'@types/fs-extra@9.0.13': '@types/fs-extra@9.0.13':
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
@ -2132,21 +2100,21 @@ packages:
'@uiw/codemirror-extensions-basic-setup@4.25.4': '@uiw/codemirror-extensions-basic-setup@4.25.4':
resolution: {integrity: sha512-YzNwkm0AbPv1EXhCHYR5v0nqfemG2jEB0Z3Att4rBYqKrlG7AA9Rhjc3IyBaOzsBu18wtrp9/+uhTyu7TXSRng==} resolution: {integrity: sha512-YzNwkm0AbPv1EXhCHYR5v0nqfemG2jEB0Z3Att4rBYqKrlG7AA9Rhjc3IyBaOzsBu18wtrp9/+uhTyu7TXSRng==}
peerDependencies: peerDependencies:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': '>=6.0.0'
'@codemirror/commands': 6.10.4 '@codemirror/commands': '>=6.0.0'
'@codemirror/language': 6.12.1 '@codemirror/language': '>=6.0.0'
'@codemirror/lint': '>=6.0.0' '@codemirror/lint': '>=6.0.0'
'@codemirror/search': '>=6.0.0' '@codemirror/search': '>=6.0.0'
'@codemirror/state': 6.7.1 '@codemirror/state': '>=6.0.0'
'@codemirror/view': 6.39.12 '@codemirror/view': '>=6.0.0'
'@uiw/react-codemirror@4.25.4': '@uiw/react-codemirror@4.25.4':
resolution: {integrity: sha512-ipO067oyfUw+DVaXhQCxkB0ZD9b7RnY+ByrprSYSKCHaULvJ3sqWYC/Zen6zVQ8/XC4o5EPBfatGiX20kC7XGA==} resolution: {integrity: sha512-ipO067oyfUw+DVaXhQCxkB0ZD9b7RnY+ByrprSYSKCHaULvJ3sqWYC/Zen6zVQ8/XC4o5EPBfatGiX20kC7XGA==}
peerDependencies: peerDependencies:
'@babel/runtime': '>=7.11.0' '@babel/runtime': '>=7.11.0'
'@codemirror/state': 6.7.1 '@codemirror/state': '>=6.0.0'
'@codemirror/theme-one-dark': '>=6.0.0' '@codemirror/theme-one-dark': '>=6.0.0'
'@codemirror/view': 6.39.12 '@codemirror/view': '>=6.0.0'
codemirror: '>=6.0.0' codemirror: '>=6.0.0'
react: '>=17.0.0' react: '>=17.0.0'
react-dom: '>=17.0.0' react-dom: '>=17.0.0'
@ -2197,11 +2165,6 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
hasBin: true hasBin: true
acorn@8.17.0:
resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==}
engines: {node: '>=0.4.0'}
hasBin: true
agent-base@7.1.4: agent-base@7.1.4:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'} engines: {node: '>= 14'}
@ -2382,9 +2345,8 @@ packages:
base64-js@1.5.1: base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
baseline-browser-mapping@2.11.4: baseline-browser-mapping@2.9.19:
resolution: {integrity: sha512-s4+sLr9mZ/CyqeRritFeYV/Zx73OAtmaHn6kkBS1XRoJn1hrg3xIDUcpicAEX68tkcIN0iBCgti31C8zxtkhsQ==} resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
engines: {node: '>=6.0.0'}
hasBin: true hasBin: true
bl@4.1.0: bl@4.1.0:
@ -2396,9 +2358,6 @@ packages:
bluebird@3.7.2: bluebird@3.7.2:
resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
blurhash@2.0.5:
resolution: {integrity: sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==}
body-parser@2.2.2: body-parser@2.2.2:
resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -2499,8 +2458,8 @@ packages:
camelize@1.0.1: camelize@1.0.1:
resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==}
caniuse-lite@1.0.30001806: caniuse-lite@1.0.30001766:
resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==} resolution: {integrity: sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==}
ccount@2.0.1: ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@ -2721,9 +2680,6 @@ packages:
crelt@1.0.6: crelt@1.0.6:
resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==}
crelt@1.0.7:
resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==}
cross-dirname@0.1.0: cross-dirname@0.1.0:
resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==} resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==}
@ -3505,10 +3461,6 @@ packages:
resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==}
engines: {node: '>=14.14'} engines: {node: '>=14.14'}
fs-extra@11.4.0:
resolution: {integrity: sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==}
engines: {node: '>=14.14'}
fs-extra@7.0.1: fs-extra@7.0.1:
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
engines: {node: '>=6 <7 || >=8'} engines: {node: '>=6 <7 || >=8'}
@ -4042,9 +3994,6 @@ packages:
jsonfile@6.2.0: jsonfile@6.2.0:
resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
jsonfile@6.2.1:
resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==}
jsx-ast-utils@3.3.5: jsx-ast-utils@3.3.5:
resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==}
engines: {node: '>=4.0'} engines: {node: '>=4.0'}
@ -4111,9 +4060,6 @@ packages:
lodash@4.17.23: lodash@4.17.23:
resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==}
lodash@4.18.1:
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
log-symbols@4.1.0: log-symbols@4.1.0:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -6538,16 +6484,16 @@ snapshots:
'@codemirror/autocomplete@6.20.0': '@codemirror/autocomplete@6.20.0':
dependencies: dependencies:
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@codemirror/commands@6.10.4': '@codemirror/commands@6.10.1':
dependencies: dependencies:
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@lezer/common': 1.5.2 '@lezer/common': 1.5.0
'@codemirror/lang-cpp@6.0.3': '@codemirror/lang-cpp@6.0.3':
dependencies: dependencies:
@ -6558,7 +6504,7 @@ snapshots:
dependencies: dependencies:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/css': 1.3.0 '@lezer/css': 1.3.0
@ -6566,7 +6512,7 @@ snapshots:
dependencies: dependencies:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/go': 1.0.1 '@lezer/go': 1.0.1
@ -6576,7 +6522,7 @@ snapshots:
'@codemirror/lang-css': 6.3.1 '@codemirror/lang-css': 6.3.1
'@codemirror/lang-javascript': 6.2.4 '@codemirror/lang-javascript': 6.2.4
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/css': 1.3.0 '@lezer/css': 1.3.0
@ -6592,7 +6538,7 @@ snapshots:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/lint': 6.9.3 '@codemirror/lint': 6.9.3
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/javascript': 1.5.4 '@lezer/javascript': 1.5.4
@ -6607,7 +6553,7 @@ snapshots:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/lang-html': 6.4.11 '@codemirror/lang-html': 6.4.11
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/markdown': 1.6.3 '@lezer/markdown': 1.6.3
@ -6616,7 +6562,7 @@ snapshots:
dependencies: dependencies:
'@codemirror/lang-html': 6.4.11 '@codemirror/lang-html': 6.4.11
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/php': 1.0.5 '@lezer/php': 1.0.5
@ -6624,7 +6570,7 @@ snapshots:
dependencies: dependencies:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/python': 1.1.18 '@lezer/python': 1.1.18
@ -6637,7 +6583,7 @@ snapshots:
dependencies: dependencies:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/highlight': 1.2.3 '@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.8 '@lezer/lr': 1.4.8
@ -6646,7 +6592,7 @@ snapshots:
dependencies: dependencies:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/xml': 1.0.6 '@lezer/xml': 1.0.6
@ -6655,7 +6601,7 @@ snapshots:
dependencies: dependencies:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
'@lezer/highlight': 1.2.3 '@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.8 '@lezer/lr': 1.4.8
@ -6663,40 +6609,40 @@ snapshots:
'@codemirror/language@6.12.1': '@codemirror/language@6.12.1':
dependencies: dependencies:
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@lezer/common': 1.5.2 '@lezer/common': 1.5.0
'@lezer/highlight': 1.2.3 '@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.8 '@lezer/lr': 1.4.8
style-mod: 4.1.3 style-mod: 4.1.3
'@codemirror/lint@6.9.3': '@codemirror/lint@6.9.3':
dependencies: dependencies:
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
crelt: 1.0.6 crelt: 1.0.6
'@codemirror/search@6.6.0': '@codemirror/search@6.6.0':
dependencies: dependencies:
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
crelt: 1.0.7 crelt: 1.0.6
'@codemirror/state@6.7.1': '@codemirror/state@6.5.4':
dependencies: dependencies:
'@marijn/find-cluster-break': 1.0.3 '@marijn/find-cluster-break': 1.0.2
'@codemirror/theme-one-dark@6.1.3': '@codemirror/theme-one-dark@6.1.3':
dependencies: dependencies:
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@lezer/highlight': 1.2.3 '@lezer/highlight': 1.2.3
'@codemirror/view@6.39.12': '@codemirror/view@6.39.12':
dependencies: dependencies:
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
crelt: 1.0.7 crelt: 1.0.6
style-mod: 4.1.3 style-mod: 4.1.3
w3c-keyname: 2.2.8 w3c-keyname: 2.2.8
@ -6821,7 +6767,7 @@ snapshots:
dependencies: dependencies:
cross-dirname: 0.1.0 cross-dirname: 0.1.0
debug: 4.4.3 debug: 4.4.3
fs-extra: 11.4.0 fs-extra: 11.3.3
minimist: 1.2.8 minimist: 1.2.8
postject: 1.0.0-alpha.6 postject: 1.0.0-alpha.6
transitivePeerDependencies: transitivePeerDependencies:
@ -7305,8 +7251,6 @@ snapshots:
'@lezer/common@1.5.0': {} '@lezer/common@1.5.0': {}
'@lezer/common@1.5.2': {}
'@lezer/cpp@1.1.5': '@lezer/cpp@1.1.5':
dependencies: dependencies:
'@lezer/common': 1.5.0 '@lezer/common': 1.5.0
@ -7388,7 +7332,7 @@ snapshots:
'@lezer/yaml@1.0.4': '@lezer/yaml@1.0.4':
dependencies: dependencies:
'@lezer/common': 1.5.2 '@lezer/common': 1.5.0
'@lezer/highlight': 1.2.3 '@lezer/highlight': 1.2.3
'@lezer/lr': 1.4.8 '@lezer/lr': 1.4.8
@ -7409,7 +7353,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@marijn/find-cluster-break@1.0.3': {} '@marijn/find-cluster-break@1.0.2': {}
'@nodelib/fs.scandir@2.1.5': '@nodelib/fs.scandir@2.1.5':
dependencies: dependencies:
@ -8200,7 +8144,7 @@ snapshots:
'@types/eslint@9.6.1': '@types/eslint@9.6.1':
dependencies: dependencies:
'@types/estree': 1.0.9 '@types/estree': 1.0.8
'@types/json-schema': 7.0.15 '@types/json-schema': 7.0.15
optional: true optional: true
@ -8210,9 +8154,6 @@ snapshots:
'@types/estree@1.0.8': {} '@types/estree@1.0.8': {}
'@types/estree@1.0.9':
optional: true
'@types/fs-extra@9.0.13': '@types/fs-extra@9.0.13':
dependencies: dependencies:
'@types/node': 25.2.0 '@types/node': 25.2.0
@ -8330,24 +8271,24 @@ snapshots:
'@typescript-eslint/types': 6.21.0 '@typescript-eslint/types': 6.21.0
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
'@uiw/codemirror-extensions-basic-setup@4.25.4(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.4)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.3)(@codemirror/search@6.6.0)(@codemirror/state@6.7.1)(@codemirror/view@6.39.12)': '@uiw/codemirror-extensions-basic-setup@4.25.4(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.1)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.3)(@codemirror/search@6.6.0)(@codemirror/state@6.5.4)(@codemirror/view@6.39.12)':
dependencies: dependencies:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/commands': 6.10.4 '@codemirror/commands': 6.10.1
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/lint': 6.9.3 '@codemirror/lint': 6.9.3
'@codemirror/search': 6.6.0 '@codemirror/search': 6.6.0
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@uiw/react-codemirror@4.25.4(@babel/runtime@7.28.6)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.3)(@codemirror/search@6.6.0)(@codemirror/state@6.7.1)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.12)(codemirror@6.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': '@uiw/react-codemirror@4.25.4(@babel/runtime@7.28.6)(@codemirror/autocomplete@6.20.0)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.3)(@codemirror/search@6.6.0)(@codemirror/state@6.5.4)(@codemirror/theme-one-dark@6.1.3)(@codemirror/view@6.39.12)(codemirror@6.0.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
dependencies: dependencies:
'@babel/runtime': 7.28.6 '@babel/runtime': 7.28.6
'@codemirror/commands': 6.10.4 '@codemirror/commands': 6.10.1
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/theme-one-dark': 6.1.3 '@codemirror/theme-one-dark': 6.1.3
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
'@uiw/codemirror-extensions-basic-setup': 4.25.4(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.4)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.3)(@codemirror/search@6.6.0)(@codemirror/state@6.7.1)(@codemirror/view@6.39.12) '@uiw/codemirror-extensions-basic-setup': 4.25.4(@codemirror/autocomplete@6.20.0)(@codemirror/commands@6.10.1)(@codemirror/language@6.12.1)(@codemirror/lint@6.9.3)(@codemirror/search@6.6.0)(@codemirror/state@6.5.4)(@codemirror/view@6.39.12)
codemirror: 6.0.2 codemirror: 6.0.2
react: 19.2.4 react: 19.2.4
react-dom: 19.2.4(react@19.2.4) react-dom: 19.2.4(react@19.2.4)
@ -8394,9 +8335,6 @@ snapshots:
acorn@8.15.0: {} acorn@8.15.0: {}
acorn@8.17.0:
optional: true
agent-base@7.1.4: {} agent-base@7.1.4: {}
ajv-formats@3.0.1(ajv@8.17.1): ajv-formats@3.0.1(ajv@8.17.1):
@ -8694,7 +8632,7 @@ snapshots:
base64-js@1.5.1: {} base64-js@1.5.1: {}
baseline-browser-mapping@2.11.4: {} baseline-browser-mapping@2.9.19: {}
bl@4.1.0: bl@4.1.0:
dependencies: dependencies:
@ -8706,8 +8644,6 @@ snapshots:
bluebird@3.7.2: {} bluebird@3.7.2: {}
blurhash@2.0.5: {}
body-parser@2.2.2: body-parser@2.2.2:
dependencies: dependencies:
bytes: 3.1.2 bytes: 3.1.2
@ -8753,8 +8689,8 @@ snapshots:
browserslist@4.28.1: browserslist@4.28.1:
dependencies: dependencies:
baseline-browser-mapping: 2.11.4 baseline-browser-mapping: 2.9.19
caniuse-lite: 1.0.30001806 caniuse-lite: 1.0.30001766
electron-to-chromium: 1.5.283 electron-to-chromium: 1.5.283
node-releases: 2.0.27 node-releases: 2.0.27
update-browserslist-db: 1.2.3(browserslist@4.28.1) update-browserslist-db: 1.2.3(browserslist@4.28.1)
@ -8858,7 +8794,7 @@ snapshots:
camelize@1.0.1: {} camelize@1.0.1: {}
caniuse-lite@1.0.30001806: {} caniuse-lite@1.0.30001766: {}
ccount@2.0.1: {} ccount@2.0.1: {}
@ -8936,11 +8872,11 @@ snapshots:
codemirror@6.0.2: codemirror@6.0.2:
dependencies: dependencies:
'@codemirror/autocomplete': 6.20.0 '@codemirror/autocomplete': 6.20.0
'@codemirror/commands': 6.10.4 '@codemirror/commands': 6.10.1
'@codemirror/language': 6.12.1 '@codemirror/language': 6.12.1
'@codemirror/lint': 6.9.3 '@codemirror/lint': 6.9.3
'@codemirror/search': 6.6.0 '@codemirror/search': 6.6.0
'@codemirror/state': 6.7.1 '@codemirror/state': 6.5.4
'@codemirror/view': 6.39.12 '@codemirror/view': 6.39.12
color-convert@2.0.1: color-convert@2.0.1:
@ -9075,8 +9011,6 @@ snapshots:
crelt@1.0.6: {} crelt@1.0.6: {}
crelt@1.0.7: {}
cross-dirname@0.1.0: cross-dirname@0.1.0:
optional: true optional: true
@ -9437,7 +9371,7 @@ snapshots:
'@electron/asar': 3.4.1 '@electron/asar': 3.4.1
debug: 4.4.3 debug: 4.4.3
fs-extra: 7.0.1 fs-extra: 7.0.1
lodash: 4.18.1 lodash: 4.17.23
temp: 0.9.4 temp: 0.9.4
optionalDependencies: optionalDependencies:
'@electron/windows-sign': 1.2.2 '@electron/windows-sign': 1.2.2
@ -10157,13 +10091,6 @@ snapshots:
jsonfile: 6.2.0 jsonfile: 6.2.0
universalify: 2.0.1 universalify: 2.0.1
fs-extra@11.4.0:
dependencies:
graceful-fs: 4.2.11
jsonfile: 6.2.1
universalify: 2.0.1
optional: true
fs-extra@7.0.1: fs-extra@7.0.1:
dependencies: dependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@ -10725,13 +10652,6 @@ snapshots:
optionalDependencies: optionalDependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
jsonfile@6.2.1:
dependencies:
universalify: 2.0.1
optionalDependencies:
graceful-fs: 4.2.11
optional: true
jsx-ast-utils@3.3.5: jsx-ast-utils@3.3.5:
dependencies: dependencies:
array-includes: 3.1.9 array-includes: 3.1.9
@ -10801,8 +10721,6 @@ snapshots:
lodash@4.17.23: {} lodash@4.17.23: {}
lodash@4.18.1: {}
log-symbols@4.1.0: log-symbols@4.1.0:
dependencies: dependencies:
chalk: 4.1.2 chalk: 4.1.2
@ -13053,7 +12971,7 @@ snapshots:
terser@5.46.0: terser@5.46.0:
dependencies: dependencies:
'@jridgewell/source-map': 0.3.11 '@jridgewell/source-map': 0.3.11
acorn: 8.17.0 acorn: 8.15.0
commander: 2.20.3 commander: 2.20.3
source-map-support: 0.5.21 source-map-support: 0.5.21
optional: true optional: true

View File

@ -5,12 +5,4 @@ allowBuilds:
workerd: true workerd: true
core-js: true core-js: true
electron-winstaller: true electron-winstaller: true
'@tsparticles/engine': true '@tsparticles/engine': true
overrides:
baseline-browser-mapping: 2.11.4
'@codemirror/state': 6.7.1
'@codemirror/view': 6.39.12
'@codemirror/language': 6.12.1
'@codemirror/commands': 6.10.4
'@codemirror/autocomplete': 6.20.0

View File

@ -25,12 +25,6 @@ let runningUpdate = null
const getArtifactName = (artifact) => const getArtifactName = (artifact) =>
String(artifact?.fileName || artifact?.relativePath || artifact?.url || '') String(artifact?.fileName || artifact?.relativePath || artifact?.url || '')
const isCefInstallerArtifact = (artifact) => {
const name = getArtifactName(artifact).toLowerCase()
// CEF builds are named like farmcontrol-0.1.1-x64-cef.msi / -cef.pkg / -cef.exe
return /-cef\.[a-z0-9]+$/.test(name)
}
const normalizeArch = (arch) => { const normalizeArch = (arch) => {
if (arch === 'x64' || arch === 'amd64') return 'x64' if (arch === 'x64' || arch === 'amd64') return 'x64'
if (arch === 'arm64' || arch === 'aarch64') return 'arm64' if (arch === 'arm64' || arch === 'aarch64') return 'arm64'
@ -75,9 +69,7 @@ const selectUpdateArtifact = (
throw new Error(`App updates are not supported on ${platform}.`) throw new Error(`App updates are not supported on ${platform}.`)
} }
const artifacts = (Array.isArray(update?.artifacts) ? update.artifacts : []).filter( const artifacts = Array.isArray(update?.artifacts) ? update.artifacts : []
(artifact) => !isCefInstallerArtifact(artifact)
)
const matchingArtifact = artifacts.find((artifact) => const matchingArtifact = artifacts.find((artifact) =>
artifactMatchesPlatform(artifact, target, platform, arch) artifactMatchesPlatform(artifact, target, platform, arch)
) )
@ -192,6 +184,7 @@ const downloadArtifact = async (artifact, destinationPath, webContents) => {
} }
const restartApp = (app) => { const restartApp = (app) => {
console.log('[app-update] restarting app')
app.relaunch() app.relaunch()
app.exit(0) app.exit(0)
} }

View File

@ -111,6 +111,13 @@ export const launchMacInstaller = (
const installScript = buildMacInstallScript(installerPath, logPath) const installScript = buildMacInstallScript(installerPath, logPath)
const promptName = 'farmcontrol' const promptName = 'farmcontrol'
console.log('[app-update] launching macOS installer:', {
installerPath,
installScript,
logPath,
promptName
})
sendProgress(webContents, { sendProgress(webContents, {
phase: 'installing', phase: 'installing',
percent: 0, percent: 0,
@ -133,6 +140,7 @@ export const launchMacInstaller = (
await fs.unlink(logPath).catch(() => {}) await fs.unlink(logPath).catch(() => {})
if (stdout) console.log('[app-update] installer stdout:', stdout)
if (stderr) console.error('[app-update] installer stderr:', stderr) if (stderr) console.error('[app-update] installer stderr:', stderr)
if (error) { if (error) {
@ -166,6 +174,7 @@ export const launchMacInstaller = (
message: message || 'Installation complete. Restarting Farm Control...' message: message || 'Installation complete. Restarting Farm Control...'
}) })
console.log('[app-update] installer completed successfully')
resolve() resolve()
}) })
}) })

View File

@ -149,33 +149,6 @@ function attachKeyboardShortcuts(browserWindow) {
// Keyboard shortcuts for the main window can be added here if needed // Keyboard shortcuts for the main window can be added here if needed
} }
function sendNavigationGesture(browserWindow, direction) {
if (!browserWindow || browserWindow.isDestroyed()) return
browserWindow.webContents.send('navigation-gesture', direction)
}
function setupNavigationGestures(browserWindow) {
if (!browserWindow) return
if (process.platform === 'darwin') {
browserWindow.on('swipe', (_event, direction) => {
if (direction === 'left') {
sendNavigationGesture(browserWindow, 'back')
} else if (direction === 'right') {
sendNavigationGesture(browserWindow, 'forward')
}
})
}
browserWindow.on('app-command', (_event, command) => {
if (command === 'browser-backward') {
sendNavigationGesture(browserWindow, 'back')
} else if (command === 'browser-forward') {
sendNavigationGesture(browserWindow, 'forward')
}
})
}
function setupWindowEvents() { function setupWindowEvents() {
if (!win) return if (!win) return
win.on('maximize', () => { win.on('maximize', () => {
@ -184,6 +157,7 @@ function setupWindowEvents() {
}) })
}) })
win.on('enter-full-screen', () => { win.on('enter-full-screen', () => {
console.log('Entered fullscreen')
win.webContents.send('window-state', { win.webContents.send('window-state', {
isFullScreen: true isFullScreen: true
}) })
@ -226,7 +200,6 @@ export function createWindow() {
setupWindowEvents() setupWindowEvents()
attachKeyboardShortcuts(win) attachKeyboardShortcuts(win)
setupNavigationGestures(win)
} }
export function getWindow() { export function getWindow() {
@ -320,6 +293,7 @@ export function setupMainWindowAppEvents(app) {
export function setupDevAuthServer() { export function setupDevAuthServer() {
const env = (process.env.NODE_ENV || 'development').trim() const env = (process.env.NODE_ENV || 'development').trim()
if (env == 'development') { if (env == 'development') {
console.log('Starting development auth web server...')
import('express').then(({ default: express }) => { import('express').then(({ default: express }) => {
const app = express() const app = express()
const port = 3500 const port = 3500
@ -336,7 +310,11 @@ export function setupDevAuthServer() {
} }
}) })
app.listen(port, () => {}) app.listen(port, () => {
console.log(`Dev auth server running on http://localhost:${port}`)
})
}) })
} else {
console.log('Will use url scheme instead of auth server.')
} }
} }

View File

@ -1,401 +1,82 @@
import { spawn } from 'child_process' import { spawn } from 'child_process'
import { promises as fs } from 'fs'
import os from 'os'
import path from 'path'
import process from 'process' import process from 'process'
const MSI_OLE_HEADER = Buffer.from([0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1]) const buildWindowsInstallCommand = (installerPath) => ({
const DEBUG_PREFIX = '[app-update][win-progress]' command: 'cmd.exe',
args: [
'/d',
'/s',
'/c',
`timeout /t 2 /nobreak >NUL && msiexec.exe /i "${installerPath}" /qn /norestart`
]
})
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) export const launchWindowsInstaller = (
const debugLog = () => {}
const decodeMsiLogBuffer = (buffer) => {
if (!buffer?.length) return ''
if (buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xfe) {
debugLog('decoded MSI log as UTF-16 LE (BOM)')
return buffer.subarray(2).toString('utf16le')
}
const sample = buffer.subarray(0, Math.min(buffer.length, 64))
const looksUtf16 =
sample.length >= 4 &&
sample.filter((byte) => byte === 0).length > sample.length / 4
if (looksUtf16) {
debugLog('decoded MSI log as UTF-16 LE (heuristic)')
return buffer.toString('utf16le')
}
debugLog('decoded MSI log as UTF-8')
return buffer.toString('utf8')
}
const formatMsiActionName = (actionName) => {
const humanized = String(actionName)
.replace(/([a-z])([A-Z])/g, '$1 $2')
.replace(/_/g, ' ')
.toLowerCase()
.trim()
if (!humanized) return 'Installing update...'
return `${humanized.charAt(0).toUpperCase()}${humanized.slice(1)}...`
}
const parseWindowsInstallerProgress = (output) => {
const lines = String(output || '').split(/\r?\n/)
let percent = null
let message = 'Installing update...'
let totalTicks = 0
let currentTicks = 0
let actionStarts = 0
let actionEnds = 0
const matchedLines = []
for (const line of lines) {
const actionStart = line.match(/^Action start \d{2}:\d{2}:\d{2}: (.+?)\./)
if (actionStart) {
actionStarts += 1
message = formatMsiActionName(actionStart[1])
matchedLines.push(`action-start:${actionStart[1]}`)
}
const doingAction = line.match(/Doing action:\s*(.+)$/)
if (doingAction && !actionStart) {
message = formatMsiActionName(doingAction[1])
matchedLines.push(`doing-action:${doingAction[1]}`)
}
if (/^Action ended \d{2}:\d{2}:\d{2}: .+?\. Return value \d+\./.test(line)) {
actionEnds += 1
matchedLines.push('action-ended')
}
const progressReset = line.match(/^\s*0\s+(\d+)\s+0(?:\s+\d+)?\s*$/)
if (progressReset) {
totalTicks = Number.parseInt(progressReset[1], 10) || 0
currentTicks = 0
matchedLines.push(`progress-reset:${totalTicks}`)
}
const progressIncrement = line.match(/^\s*2\s+(\d+)\s*$/)
if (progressIncrement) {
currentTicks += Number.parseInt(progressIncrement[1], 10) || 0
matchedLines.push(`progress-increment:${progressIncrement[1]}`)
}
const progressAddition = line.match(/^\s*3\s+(\d+)\s*$/)
if (progressAddition) {
totalTicks += Number.parseInt(progressAddition[1], 10) || 0
matchedLines.push(`progress-addition:${progressAddition[1]}`)
}
if (/Installation success or error status:\s*0\b/.test(line)) {
percent = 100
message = 'Installation complete. Restarting Farm Control...'
matchedLines.push('install-success')
}
}
if (percent !== 100) {
if (totalTicks > 0) {
percent = Math.min(99, Math.round((currentTicks / totalTicks) * 100))
} else if (actionStarts > 0) {
percent = Math.min(
95,
Math.max(5, Math.round((actionEnds / actionStarts) * 90))
)
}
}
return {
percent,
message,
stats: {
lineCount: lines.length,
actionStarts,
actionEnds,
totalTicks,
currentTicks,
matchedLines: matchedLines.slice(-8)
}
}
}
const isWindowsInstallSuccessful = (output) =>
/Installation success or error status:\s*0\b/.test(output) ||
/MainEngineThread is returning 0\b/.test(output)
const isWindowsInstallFailed = (output) =>
/Installation success or error status:\s*[1-9]\d*\b/.test(output) ||
/MainEngineThread is returning [1-9]\d*\b/.test(output)
const isValidMsiPackage = async (filePath) => {
const handle = await fs.open(filePath, 'r')
try {
const header = Buffer.alloc(MSI_OLE_HEADER.length)
await handle.read(header, 0, header.length, 0)
return header.equals(MSI_OLE_HEADER)
} finally {
await handle.close()
}
}
const prepareInstallerPath = async (installerPath) => {
const fileName = path.basename(installerPath)
const updateDir = path.join(
process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'),
'FarmControl',
'Updates'
)
await fs.mkdir(updateDir, { recursive: true })
const stablePath = path.join(updateDir, fileName)
await fs.copyFile(installerPath, stablePath)
// Resolve to a canonical long path. Short 8.3 paths (e.g. ADMINI~1) break msiexec.
const resolvedPath = await fs.realpath(stablePath)
const stats = await fs.stat(resolvedPath)
if (!stats.isFile() || stats.size === 0) {
throw new Error('Update installer file is missing or empty.')
}
if (!(await isValidMsiPackage(resolvedPath))) {
throw new Error(
'Downloaded update is not a valid Windows Installer package. The file may be corrupted or incomplete.'
)
}
return resolvedPath
}
const startWindowsInstallerProgressWatch = (
logPath,
webContents,
sendProgress
) => {
let installerOutput = ''
let lastLogSize = 0
let lastPercent = null
let lastMessage = null
let pollCount = 0
const poll = async () => {
pollCount += 1
try {
const stat = await fs.stat(logPath)
if (stat.size === 0) {
debugLog(`poll #${pollCount}: log exists but is empty`, { logPath })
return
}
if (stat.size === lastLogSize) {
debugLog(`poll #${pollCount}: no new log data`, {
logPath,
size: stat.size
})
return
}
const buffer = Buffer.alloc(stat.size)
const handle = await fs.open(logPath, 'r')
try {
await handle.read(buffer, 0, stat.size, 0)
} finally {
await handle.close()
}
lastLogSize = stat.size
installerOutput = decodeMsiLogBuffer(buffer)
const { percent, message, stats } =
parseWindowsInstallerProgress(installerOutput)
const resolvedPercent = percent ?? lastPercent ?? 0
const resolvedMessage = message || 'Installing update...'
debugLog(`poll #${pollCount}: parsed installer log`, {
logPath,
size: stat.size,
textLength: installerOutput.length,
preview: installerOutput.slice(0, 240).replace(/\s+/g, ' '),
parsed: stats,
resolvedPercent,
resolvedMessage
})
if (
resolvedPercent !== lastPercent ||
resolvedMessage !== lastMessage
) {
debugLog(`poll #${pollCount}: sending progress update`, {
percent: resolvedPercent,
message: resolvedMessage
})
lastPercent = resolvedPercent
lastMessage = resolvedMessage
sendProgress(webContents, {
phase: 'installing',
percent: resolvedPercent,
message: resolvedMessage
})
} else {
debugLog(`poll #${pollCount}: progress unchanged, skipping UI update`, {
percent: resolvedPercent,
message: resolvedMessage
})
}
} catch (error) {
if (error?.code === 'ENOENT') {
debugLog(`poll #${pollCount}: log file not created yet`, { logPath })
return
}
console.error(`${DEBUG_PREFIX} installer log poll error:`, error)
}
}
const intervalId = setInterval(() => {
poll().catch((error) => {
console.error(`${DEBUG_PREFIX} installer log poll error:`, error)
})
}, 300)
return async () => {
clearInterval(intervalId)
await poll()
debugLog('stopped progress watch', {
logPath,
finalSize: lastLogSize,
textLength: installerOutput.length,
pollCount
})
return installerOutput
}
}
export const launchWindowsInstaller = async (
app, app,
installerPath, installerPath,
webContents, webContents,
{ sendProgress, getInstallErrorMessage } { sendProgress, getInstallErrorMessage }
) => { ) => {
const resolvedPath = await prepareInstallerPath(installerPath) const { command, args } = buildWindowsInstallCommand(installerPath)
const logPath = path.join(path.dirname(resolvedPath), 'install.log')
debugLog('prepared installer', { console.log('[app-update] launching installer:', {
installerPath, installerPath,
resolvedPath, command,
logPath args,
shellCommand: args.join(' '),
platform: process.platform
}) })
sendProgress(webContents, { sendProgress(webContents, {
phase: 'installing', phase: 'installing',
percent: 0, percent: 100,
message: 'Installing update...' message: 'Installing update. Farm Control will restart automatically.'
}) })
await fs.unlink(logPath).catch(() => {})
// Allow file handles from the download/copy to settle before msiexec opens the MSI.
await sleep(2000)
const stopProgressWatch = startWindowsInstallerProgressWatch(
logPath,
webContents,
sendProgress
)
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let processOutput = '' let installerOutput = ''
const startedAt = Date.now()
const installerArgs = [ const installerProcess = spawn(command, args, {
'/i', detached: true,
resolvedPath,
'/qn',
'/norestart',
'/L*v!',
logPath
]
debugLog('spawning msiexec', {
args: installerArgs,
elapsedMs: Date.now() - startedAt
})
const installerProcess = spawn('msiexec.exe', installerArgs, {
stdio: ['ignore', 'pipe', 'pipe'], stdio: ['ignore', 'pipe', 'pipe'],
windowsHide: true windowsHide: true
}) })
installerProcess.stdout?.on('data', (data) => { installerProcess.stdout?.on('data', (data) => {
const text = data.toString('utf16le') const text = data.toString()
processOutput += text installerOutput += text
debugLog('msiexec stdout chunk', { console.log('[app-update] installer stdout:', text)
length: text.length,
preview: text.slice(0, 200)
})
}) })
installerProcess.stderr?.on('data', (data) => { installerProcess.stderr?.on('data', (data) => {
const text = data.toString('utf16le') const text = data.toString()
processOutput += text installerOutput += text
debugLog('msiexec stderr chunk', { console.error('[app-update] installer stderr:', text)
length: text.length,
preview: text.slice(0, 200)
})
}) })
installerProcess.on('spawn', () => { installerProcess.on('spawn', () => {
debugLog('msiexec spawned', { console.log('[app-update] installer spawned, pid:', installerProcess.pid)
pid: installerProcess.pid,
elapsedMs: Date.now() - startedAt
})
}) })
installerProcess.on('error', async (error) => { installerProcess.on('error', (error) => {
console.error(`${DEBUG_PREFIX} installer spawn error:`, error) console.error('[app-update] installer spawn error:', error)
const watchedOutput = await stopProgressWatch()
debugLog('installer spawn failed', {
watchedOutputLength: watchedOutput.length,
processOutputLength: processOutput.length
})
const message = error?.message || 'Failed to start update installer.'
sendProgress(webContents, { sendProgress(webContents, {
phase: 'error', phase: 'error',
percent: null, percent: null,
message message: error?.message || 'Failed to start update installer.'
}) })
reject(error) reject(error)
}) })
installerProcess.on('exit', async (code, signal) => { installerProcess.on('exit', (code, signal) => {
const watchedOutput = await stopProgressWatch() console.log('[app-update] installer exited:', {
const output = watchedOutput || processOutput
const finalParse = parseWindowsInstallerProgress(output)
debugLog('msiexec exited', {
code, code,
signal, signal,
elapsedMs: Date.now() - startedAt, output: installerOutput
watchedOutputLength: watchedOutput.length,
processOutputLength: processOutput.length,
parsed: finalParse.stats,
outputPreview: output.slice(0, 500).replace(/\s+/g, ' ')
}) })
debugLog('keeping install log', { logPath })
if (code !== 0) { if (code !== 0) {
const message = getInstallErrorMessage(null, output) const message = getInstallErrorMessage(null, installerOutput)
sendProgress(webContents, { sendProgress(webContents, {
phase: 'error', phase: 'error',
percent: null, percent: null,
@ -405,38 +86,14 @@ export const launchWindowsInstaller = async (
return return
} }
const succeeded =
isWindowsInstallSuccessful(output) ||
(code === 0 && !isWindowsInstallFailed(output))
debugLog('install success evaluation', {
succeeded,
isSuccessful: isWindowsInstallSuccessful(output),
isFailed: isWindowsInstallFailed(output),
exitCode: code
})
if (!succeeded) {
const message = getInstallErrorMessage(null, output)
sendProgress(webContents, {
phase: 'error',
percent: null,
message
})
reject(new Error(message))
return
}
const { percent, message } = finalParse
sendProgress(webContents, { sendProgress(webContents, {
phase: 'installing', phase: 'installing',
percent: percent ?? 100, percent: 100,
message: message || 'Installation complete. Restarting Farm Control...' message: 'Installation complete. Restarting Farm Control...'
}) })
debugLog('installer completed successfully')
resolve() resolve()
}) })
installerProcess.unref()
}) })
} }

View File

@ -6,7 +6,6 @@ import {
Navigate Navigate
} from 'react-router-dom' } from 'react-router-dom'
import { App, ConfigProvider } from 'antd' import { App, ConfigProvider } from 'antd'
import { lazy } from 'react'
import Dashboard from './components/Dashboard/Dashboard.jsx' import Dashboard from './components/Dashboard/Dashboard.jsx'
import PrivateRoute from './components/PrivateRoute' import PrivateRoute from './components/PrivateRoute'
@ -18,7 +17,6 @@ import {
ElectronSpotlightContentPage ElectronSpotlightContentPage
} from './components/Dashboard/context/SpotlightContext.jsx' } from './components/Dashboard/context/SpotlightContext.jsx'
import { ActionsModalProvider } from './components/Dashboard/context/ActionsModalContext.jsx' import { ActionsModalProvider } from './components/Dashboard/context/ActionsModalContext.jsx'
import { ActionsProvider } from './components/Dashboard/context/ActionsContext.jsx'
import MissingPlaceholder from './components/Dashboard/common/MissingPlaceholder.jsx' import MissingPlaceholder from './components/Dashboard/common/MissingPlaceholder.jsx'
import { import {
@ -35,11 +33,6 @@ import AuthCallback from './components/App/AuthCallback.jsx'
import EmailNotificationTemplate from './components/Email/EmailNotificationTemplate.jsx' import EmailNotificationTemplate from './components/Email/EmailNotificationTemplate.jsx'
import MarketplaceAuthCallback from './components/Dashboard/Sales/Marketplaces/MarketplaceAuthCallback.jsx' import MarketplaceAuthCallback from './components/Dashboard/Sales/Marketplaces/MarketplaceAuthCallback.jsx'
import AuthLaunch from './components/App/AppLaunch.jsx' import AuthLaunch from './components/App/AppLaunch.jsx'
import { TableStateProvider } from './components/Dashboard/context/TableStateContext.jsx'
const SlicerIntegration = lazy(
() =>
import('./components/Dashboard/Production/Printers/SlicerIntegration.jsx')
)
import { import {
ProductionRoutes, ProductionRoutes,
@ -47,8 +40,7 @@ import {
FinanceRoutes, FinanceRoutes,
SalesRoutes, SalesRoutes,
ManagementRoutes, ManagementRoutes,
DeveloperRoutes, DeveloperRoutes
ModelRoutes
} from './routes' } from './routes'
const getRouter = () => { const getRouter = () => {
@ -85,89 +77,80 @@ const AppContent = () => {
<PrintServerProvider> <PrintServerProvider>
<ApiServerProvider> <ApiServerProvider>
<MessageProvider> <MessageProvider>
<TableStateProvider> <AppUpdateProvider>
<AppUpdateProvider> <NotificationProvider>
<NotificationProvider> <SpotlightProvider>
<SpotlightProvider> <ActionsModalProvider>
<ActionsModalProvider> <Routes>
<ActionsProvider> <Route
<Routes> path='/applaunch'
<Route element={<AuthLaunch />}
path='/applaunch' />
element={<AuthLaunch />} <Route
path='/dashboard/electron/spotlightcontent'
element={
<PrivateRoute
component={() => (
<ElectronSpotlightContentPage />
)}
/> />
<Route }
path='/dashboard/electron/spotlightcontent' />
element={ <Route
<PrivateRoute path='/'
component={() => ( element={
<ElectronSpotlightContentPage /> <PrivateRoute
)} component={() => (
<Navigate
to='/dashboard/production/overview'
replace
/> />
} )}
/>
<Route
path='/'
element={
<PrivateRoute
component={() => (
<Navigate
to='/dashboard/production/overview'
replace
/>
)}
/>
}
/>
<Route
path='/auth/callback'
element={<AuthCallback />}
/>
<Route
path='/auth/marketplace/callback'
element={<MarketplaceAuthCallback />}
/>
<Route
path='/email/notification'
element={<EmailNotificationTemplate />}
/>
<Route
path='/slicer'
element={<SlicerIntegration />}
/> />
}
/>
<Route
path='/auth/callback'
element={<AuthCallback />}
/>
<Route
path='/auth/marketplace/callback'
element={<MarketplaceAuthCallback />}
/>
<Route
path='/email/notification'
element={<EmailNotificationTemplate />}
/>
<Route <Route
path='/dashboard' path='/dashboard'
element={ element={
<PrivateRoute <PrivateRoute
component={() => <Dashboard />} component={() => <Dashboard />}
/>
}
>
{ProductionRoutes}
{InventoryRoutes}
{FinanceRoutes}
{SalesRoutes}
{ManagementRoutes}
{ModelRoutes}
{DeveloperRoutes}
</Route>
<Route
path='*'
element={
<AppError
message='Error 404. Page not found.'
showRefresh={false}
/>
}
/> />
</Routes> }
</ActionsProvider> >
</ActionsModalProvider> {ProductionRoutes}
</SpotlightProvider> {InventoryRoutes}
</NotificationProvider> {FinanceRoutes}
</AppUpdateProvider> {SalesRoutes}
</TableStateProvider> {ManagementRoutes}
{DeveloperRoutes}
</Route>
<Route
path='*'
element={
<AppError
message='Error 404. Page not found.'
showRefresh={false}
/>
}
/>
</Routes>
</ActionsModalProvider>
</SpotlightProvider>
</NotificationProvider>
</AppUpdateProvider>
</MessageProvider> </MessageProvider>
</ApiServerProvider> </ApiServerProvider>
</PrintServerProvider> </PrintServerProvider>

View File

@ -31,16 +31,16 @@ const ApiContextDebug = () => {
connecting, connecting,
connected, connected,
fetchLoading, fetchLoading,
setObjectActivity, lockObject,
clearObjectActivity, unlockObject,
fetchObjectActivities, fetchObjectLock,
updateObject, updateObject,
createObject, createObject,
deleteObject, deleteObject,
subscribeToObjectUpdates, subscribeToObjectUpdates,
subscribeToObjectEvent, subscribeToObjectEvent,
subscribeToObjectTypeUpdates, subscribeToObjectTypeUpdates,
subscribeToObjectActivity, subscribeToObjectLock,
fetchObject, fetchObject,
fetchObjects, fetchObjects,
fetchObjectsByProperty, fetchObjectsByProperty,
@ -169,40 +169,40 @@ const ApiContextDebug = () => {
} }
} }
const testSetObjectActivity = () => { const testLockObject = () => {
try { try {
setObjectActivity(testInputs.objectId, testInputs.objectType, 'viewing') lockObject(testInputs.objectId, testInputs.objectType)
msgApi.success('setActivity command sent') msgApi.success('Lock command sent')
} catch (err) { } catch (err) {
msgApi.error('setActivity command failed') msgApi.error('Lock command failed')
logger.error('setActivity error:', err) logger.error('Lock error:', err)
} }
} }
const testClearObjectActivity = () => { const testUnlockObject = () => {
try { try {
clearObjectActivity(testInputs.objectId, testInputs.objectType) unlockObject(testInputs.objectId, testInputs.objectType)
msgApi.success('clearActivity command sent') msgApi.success('Unlock command sent')
} catch (err) { } catch (err) {
msgApi.error('clearActivity command failed') msgApi.error('Unlock command failed')
logger.error('clearActivity error:', err) logger.error('Unlock error:', err)
} }
} }
const testFetchObjectActivities = async () => { const testFetchObjectLock = async () => {
try { try {
msgApi.loading('Testing fetchObjectActivities...', 0) msgApi.loading('Testing fetchObjectLock...', 0)
const result = await fetchObjectActivities( const result = await fetchObjectLock(
testInputs.objectId, testInputs.objectId,
testInputs.objectType testInputs.objectType
) )
msgApi.destroy() msgApi.destroy()
msgApi.success('fetchObjectActivities test completed') msgApi.success('fetchObjectLock test completed')
logger.debug('fetchObjectActivities test completed', result) logger.debug('fetchObjectLock test completed', result)
} catch (err) { } catch (err) {
msgApi.destroy() msgApi.destroy()
msgApi.error('fetchObjectActivities test failed') msgApi.error('fetchObjectLock test failed')
logger.error('fetchObjectActivities error:', err) logger.error('fetchObjectLock error:', err)
} }
} }
@ -477,27 +477,28 @@ const ApiContextDebug = () => {
} }
} }
const testSubscribeToObjectActivity = () => { const testSubscribeToObjectLock = () => {
try { try {
const callback = (activity) => { const callback = (lockData) => {
logger.debug('Object activity update received:', activity) logger.debug('Object lock update received:', lockData)
} }
const unsubscribe = subscribeToObjectActivity( const unsubscribe = subscribeToObjectLock(
testInputs.objectId, testInputs.objectId,
testInputs.objectType, testInputs.objectType,
callback callback
) )
msgApi.success('Subscribed to object activity updates') msgApi.success('Subscribed to object lock updates')
logger.debug('Subscribed to object activity updates for test-id') logger.debug('Subscribed to object lock updates for test-id')
// Store unsubscribe function for cleanup
setTimeout(() => { setTimeout(() => {
if (unsubscribe) { if (unsubscribe) {
unsubscribe() unsubscribe()
logger.debug('Unsubscribed from object activity updates') logger.debug('Unsubscribed from object lock updates')
} }
}, 10000) }, 10000) // Auto-unsubscribe after 10 seconds
} catch (err) { } catch (err) {
msgApi.error('Subscribe to object activity updates failed') msgApi.error('Subscribe to object lock updates failed')
logger.error('Subscribe error:', err) logger.error('Subscribe error:', err)
} }
} }
@ -718,8 +719,8 @@ const ApiContextDebug = () => {
<Button onClick={testFetchObjects} block> <Button onClick={testFetchObjects} block>
Test fetchObjects Test fetchObjects
</Button> </Button>
<Button onClick={testFetchObjectActivities} block> <Button onClick={testFetchObjectLock} block>
Test fetchObjectActivities Test fetchObjectLock
</Button> </Button>
<Button onClick={testFetchObjectsByProperty} block> <Button onClick={testFetchObjectsByProperty} block>
Test fetchObjectsByProperty Test fetchObjectsByProperty
@ -745,11 +746,11 @@ const ApiContextDebug = () => {
collapseKey='crudTests' collapseKey='crudTests'
> >
<Space direction='vertical' style={{ width: '100%' }}> <Space direction='vertical' style={{ width: '100%' }}>
<Button onClick={testSetObjectActivity} block> <Button onClick={testLockObject} block>
Test Set Activity Test Lock Object
</Button> </Button>
<Button onClick={testClearObjectActivity} block> <Button onClick={testUnlockObject} block>
Test Clear Activity Test Unlock Object
</Button> </Button>
<Button onClick={testUpdateObject} block> <Button onClick={testUpdateObject} block>
Test updateObject Test updateObject
@ -802,8 +803,8 @@ const ApiContextDebug = () => {
<Button onClick={testSubscribeToObjectTypeUpdates} block> <Button onClick={testSubscribeToObjectTypeUpdates} block>
Test Subscribe Object Type Updates Test Subscribe Object Type Updates
</Button> </Button>
<Button onClick={testSubscribeToObjectActivity} block> <Button onClick={testSubscribeToObjectLock} block>
Test Subscribe Object Activity Test Subscribe Object Lock
</Button> </Button>
</Space> </Space>
</InfoCollapse> </InfoCollapse>

View File

@ -50,7 +50,7 @@ const Invoices = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const Invoices = () => {
type='invoice' type='invoice'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -16,10 +16,8 @@ import PaymentIcon from '../../../Icons/PaymentIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
@ -32,6 +30,9 @@ import {
} from '../../../../database/ObjectModels.js' } from '../../../../database/ObjectModels.js'
import OrderItemIcon from '../../../Icons/OrderItemIcon.jsx' import OrderItemIcon from '../../../Icons/OrderItemIcon.jsx'
import ShipmentIcon from '../../../Icons/ShipmentIcon.jsx' import ShipmentIcon from '../../../Icons/ShipmentIcon.jsx'
import PostInvoice from './PostInvoice.jsx'
import AcknowledgeInvoice from './AcknowledgeInvoice.jsx'
import NewPayment from '../Payments/NewPayment.jsx'
const log = loglevel.getLogger('InvoiceInfo') const log = loglevel.getLogger('InvoiceInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -40,15 +41,6 @@ const InvoiceInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const { setOnModalOk } = useActions()
useEffect(() => {
setOnModalOk(() => () => {
objectFormRef.current?.handleFetchObject?.()
})
return () => setOnModalOk(null)
}, [setOnModalOk])
const invoiceId = new URLSearchParams(location.search).get('invoiceId') const invoiceId = new URLSearchParams(location.search).get('invoiceId')
const [collapseState, updateCollapseState] = useCollapseState('InvoiceInfo', { const [collapseState, updateCollapseState] = useCollapseState('InvoiceInfo', {
info: true, info: true,
@ -56,7 +48,7 @@ const InvoiceInfo = () => {
invoiceShipments: true, invoiceShipments: true,
payments: true, payments: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
}) })
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -67,6 +59,9 @@ const InvoiceInfo = () => {
loading: false, loading: false,
objectData: {} objectData: {}
}) })
const [postInvoiceOpen, setPostInvoiceOpen] = useState(false)
const [acknowledgeInvoiceOpen, setAcknowledgeInvoiceOpen] = useState(false)
const [newPaymentOpen, setNewPaymentOpen] = useState(false)
const actions = { const actions = {
edit: () => { edit: () => {
@ -85,6 +80,18 @@ const InvoiceInfo = () => {
objectFormRef?.current?.handleDelete?.() objectFormRef?.current?.handleDelete?.()
return true return true
}, },
post: () => {
setPostInvoiceOpen(true)
return true
},
acknowledge: () => {
setAcknowledgeInvoiceOpen(true)
return true
},
newPayment: () => {
setNewPaymentOpen(true)
return true
}
} }
const editDisabled = const editDisabled =
@ -93,6 +100,7 @@ const InvoiceInfo = () => {
?.disabled(objectFormState.objectData) ?? false ?.disabled(objectFormState.objectData) ?? false
return ( return (
<>
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
@ -102,7 +110,7 @@ const InvoiceInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='invoice' type='invoice'
@ -134,10 +142,7 @@ const InvoiceInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -154,18 +159,12 @@ const InvoiceInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={invoiceId}
objectType='invoice'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -181,7 +180,6 @@ const InvoiceInfo = () => {
type='invoice' type='invoice'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -298,6 +296,65 @@ const InvoiceInfo = () => {
</Flex> </Flex>
</ScrollBox> </ScrollBox>
</Flex> </Flex>
<Modal
open={postInvoiceOpen}
onCancel={() => {
setPostInvoiceOpen(false)
}}
width={500}
footer={null}
destroyOnHidden={true}
centered={true}
>
<PostInvoice
onOk={() => {
setPostInvoiceOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={acknowledgeInvoiceOpen}
onCancel={() => {
setAcknowledgeInvoiceOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<AcknowledgeInvoice
onOk={() => {
setAcknowledgeInvoiceOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={newPaymentOpen}
styles={{ content: { paddingBottom: '24px' } }}
footer={null}
width={800}
onCancel={() => {
setNewPaymentOpen(false)
}}
destroyOnHidden={true}
>
<NewPayment
onOk={() => {
setNewPaymentOpen(false)
objectFormRef?.current.handleFetchObject()
}}
reset={newPaymentOpen}
defaultValues={{
invoice: { ...objectFormState.objectData },
amount: objectFormState.objectData?.grandTotalAmount
}}
/>
</Modal>
</>
) )
} }

View File

@ -50,7 +50,7 @@ const Payments = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const Payments = () => {
type='payment' type='payment'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal
@ -114,3 +105,4 @@ const Payments = () => {
} }
export default Payments export default Payments

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,10 +14,8 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
@ -25,6 +23,10 @@ import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import { getModelByName } from '../../../../database/ObjectModels.js' import { getModelByName } from '../../../../database/ObjectModels.js'
import PostPayment from './PostPayment.jsx'
import AuthorisePayment from './AuthorisePayment.jsx'
import DeclinePayment from './DeclinePayment.jsx'
import CancelPayment from './CancelPayment.jsx'
const log = loglevel.getLogger('PaymentInfo') const log = loglevel.getLogger('PaymentInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -33,20 +35,11 @@ const PaymentInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const { setOnModalOk } = useActions()
useEffect(() => {
setOnModalOk(() => () => {
objectFormRef.current?.handleFetchObject?.()
})
return () => setOnModalOk(null)
}, [setOnModalOk])
const paymentId = new URLSearchParams(location.search).get('paymentId') const paymentId = new URLSearchParams(location.search).get('paymentId')
const [collapseState, updateCollapseState] = useCollapseState('PaymentInfo', { const [collapseState, updateCollapseState] = useCollapseState('PaymentInfo', {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
}) })
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -57,6 +50,10 @@ const PaymentInfo = () => {
loading: false, loading: false,
objectData: {} objectData: {}
}) })
const [postPaymentOpen, setPostPaymentOpen] = useState(false)
const [authorisePaymentOpen, setAuthorisePaymentOpen] = useState(false)
const [declinePaymentOpen, setDeclinePaymentOpen] = useState(false)
const [cancelPaymentOpen, setCancelPaymentOpen] = useState(false)
const actions = { const actions = {
edit: () => { edit: () => {
@ -75,6 +72,22 @@ const PaymentInfo = () => {
objectFormRef?.current?.handleDelete?.() objectFormRef?.current?.handleDelete?.()
return true return true
}, },
post: () => {
setPostPaymentOpen(true)
return true
},
authorise: () => {
setAuthorisePaymentOpen(true)
return true
},
decline: () => {
setDeclinePaymentOpen(true)
return true
},
cancel: () => {
setCancelPaymentOpen(true)
return true
}
} }
const editDisabled = const editDisabled =
@ -83,6 +96,7 @@ const PaymentInfo = () => {
?.disabled(objectFormState.objectData) ?? false ?.disabled(objectFormState.objectData) ?? false
return ( return (
<>
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
@ -92,7 +106,7 @@ const PaymentInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='payment' type='payment'
@ -121,10 +135,7 @@ const PaymentInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -141,18 +152,12 @@ const PaymentInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={paymentId}
objectType='payment'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -168,7 +173,6 @@ const PaymentInfo = () => {
type='payment' type='payment'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -230,6 +234,79 @@ const PaymentInfo = () => {
</Flex> </Flex>
</ScrollBox> </ScrollBox>
</Flex> </Flex>
<Modal
open={postPaymentOpen}
onCancel={() => {
setPostPaymentOpen(false)
}}
width={500}
footer={null}
destroyOnHidden={true}
centered={true}
>
<PostPayment
onOk={() => {
setPostPaymentOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={authorisePaymentOpen}
onCancel={() => {
setAuthorisePaymentOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<AuthorisePayment
onOk={() => {
setAuthorisePaymentOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={declinePaymentOpen}
onCancel={() => {
setDeclinePaymentOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<DeclinePayment
onOk={() => {
setDeclinePaymentOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={cancelPaymentOpen}
onCancel={() => {
setCancelPaymentOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<CancelPayment
onOk={() => {
setCancelPaymentOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
</>
) )
} }

View File

@ -50,7 +50,7 @@ const TaxRecords = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const TaxRecords = () => {
type='taxRecord' type='taxRecord'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,8 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -36,7 +35,7 @@ const TaxRecordInfo = () => {
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -75,7 +74,7 @@ const TaxRecordInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='taxRecord' type='taxRecord'
@ -104,10 +103,7 @@ const TaxRecordInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -123,17 +119,9 @@ const TaxRecordInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={taxRecordId}
objectType='taxRecord'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -155,7 +143,6 @@ const TaxRecordInfo = () => {
type='taxRecord' type='taxRecord'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -55,7 +55,7 @@ const FilamentStocks = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -86,15 +86,6 @@ const FilamentStocks = () => {
type='filamentStock' type='filamentStock'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import ObjectInfo from '../../common/ObjectInfo' import ObjectInfo from '../../common/ObjectInfo'
@ -8,21 +8,18 @@ import ObjectTable from '../../common/ObjectTable'
import ObjectActions from '../../common/ObjectActions' import ObjectActions from '../../common/ObjectActions'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx'
import ActionHandler from '../../common/ActionHandler' import ActionHandler from '../../common/ActionHandler'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import ActivityIndicator from '../../common/ActivityIndicator' import LockIndicator from '../../common/LockIndicator'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon' import InfoCircleIcon from '../../../Icons/InfoCircleIcon'
import FilamentStockIcon from '../../../Icons/FilamentStockIcon' import FilamentStockIcon from '../../../Icons/FilamentStockIcon'
import NoteIcon from '../../../Icons/NoteIcon' import NoteIcon from '../../../Icons/NoteIcon'
import AuditLogIcon from '../../../Icons/AuditLogIcon' import AuditLogIcon from '../../../Icons/AuditLogIcon'
import GraphIcon from '../../../Icons/GraphIcon'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder'
import DocumentPrintButton from '../../common/DocumentPrintButton' import DocumentPrintButton from '../../common/DocumentPrintButton'
import UserNotifierToggle from '../../common/UserNotifierToggle' import UserNotifierToggle from '../../common/UserNotifierToggle'
import ScrollBox from '../../common/ScrollBox' import ScrollBox from '../../common/ScrollBox'
import HistoryDisplay from '../../common/HistoryDisplay'
const FilamentStockInfo = () => { const FilamentStockInfo = () => {
const location = useLocation() const location = useLocation()
@ -36,9 +33,8 @@ const FilamentStockInfo = () => {
{ {
info: true, info: true,
events: true, events: true,
history: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -73,7 +69,7 @@ const FilamentStockInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='filamentStock' type='filamentStock'
@ -86,7 +82,6 @@ const FilamentStockInfo = () => {
items={[ items={[
{ key: 'info', label: 'Filament Stock Information' }, { key: 'info', label: 'Filament Stock Information' },
{ key: 'events', label: 'Filament Stock Events' }, { key: 'events', label: 'Filament Stock Events' },
{ key: 'history', label: 'Filament Stock History' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
{ key: 'auditLogs', label: 'Audit Logs' } { key: 'auditLogs', label: 'Audit Logs' }
]} ]}
@ -104,10 +99,7 @@ const FilamentStockInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -126,12 +118,6 @@ const FilamentStockInfo = () => {
disabled={true} disabled={true}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={filamentStockId}
objectType='filamentStock'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -153,7 +139,6 @@ const FilamentStockInfo = () => {
type='filamentStock' type='filamentStock'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -182,25 +167,7 @@ const FilamentStockInfo = () => {
<ObjectTable <ObjectTable
type='stockEvent' type='stockEvent'
masterFilter={{ 'parent._id': filamentStockId }} masterFilter={{ 'parent._id': filamentStockId }}
visibleColumns={{ parent: false }} visibleColumns={{ 'parent._id': false }}
/>
)}
</InfoCollapse>
<InfoCollapse
title='Filament Stock History'
icon={<GraphIcon />}
active={collapseState.history}
onToggle={(expanded) => updateCollapseState('history', expanded)}
collapseKey='history'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<HistoryDisplay
history={objectFormState.objectData?.history || []}
objectType='filamentStock'
chartType='line'
loading={objectFormState.loading}
/> />
)} )}
</InfoCollapse> </InfoCollapse>

View File

@ -215,7 +215,6 @@ const LoadFilamentStock = ({
showBed={false} showBed={false}
showMoreInfo={false} showMoreInfo={false}
id={loadFilamentStockFormValues.printer._id} id={loadFilamentStockFormValues.printer._id}
offline={!connected}
/> />
) : null} ) : null}
</Flex> </Flex>

View File

@ -175,7 +175,6 @@ const UnloadFilamentStock = ({ onOk, reset, printer = null }) => {
showBed={false} showBed={false}
showMoreInfo={false} showMoreInfo={false}
id={unloadFilamentStockFormValues.printer._id} id={unloadFilamentStockFormValues.printer._id}
offline={!connected}
/> />
) : null} ) : null}
</Flex> </Flex>

View File

@ -50,7 +50,7 @@ const OrderItems = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const OrderItems = () => {
type='orderItem' type='orderItem'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,8 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -36,7 +35,7 @@ const OrderItemInfo = () => {
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -79,7 +78,7 @@ const OrderItemInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='orderItem' type='orderItem'
@ -103,10 +102,7 @@ const OrderItemInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -122,17 +118,9 @@ const OrderItemInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={orderItemId}
objectType='orderItem'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -148,7 +136,6 @@ const OrderItemInfo = () => {
type='orderItem' type='orderItem'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -55,7 +55,7 @@ const PartStocks = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -86,15 +86,6 @@ const PartStocks = () => {
type='partStock' type='partStock'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -12,11 +12,9 @@ import ViewButton from '../../common/ViewButton.jsx'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx' import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import GraphIcon from '../../../Icons/GraphIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -24,8 +22,6 @@ import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx' import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import HistoryDisplay from '../../common/HistoryDisplay.jsx'
import PartStockIcon from '../../../Icons/PartStockIcon.jsx'
const log = loglevel.getLogger('PartStockInfo') const log = loglevel.getLogger('PartStockInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -39,10 +35,9 @@ const PartStockInfo = () => {
'PartStockInfo', 'PartStockInfo',
{ {
info: true, info: true,
events: true, stocks: true,
history: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -50,7 +45,7 @@ const PartStockInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -81,7 +76,7 @@ const PartStockInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='partStock' type='partStock'
@ -93,8 +88,6 @@ const PartStockInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
items={[ items={[
{ key: 'info', label: 'Part Stock Information' }, { key: 'info', label: 'Part Stock Information' },
{ key: 'events', label: 'Part Stock Events' },
{ key: 'history', label: 'Part Stock History' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
{ key: 'auditLogs', label: 'Audit Logs' } { key: 'auditLogs', label: 'Audit Logs' }
]} ]}
@ -112,10 +105,7 @@ const PartStockInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -131,17 +121,9 @@ const PartStockInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={partStockId}
objectType='partStock'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -164,7 +146,6 @@ const PartStockInfo = () => {
type='partStock' type='partStock'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -189,43 +170,6 @@ const PartStockInfo = () => {
</InfoCollapse> </InfoCollapse>
</ActionHandler> </ActionHandler>
<InfoCollapse
title='Part Stock Events'
icon={<PartStockIcon />}
active={collapseState.events}
onToggle={(expanded) => updateCollapseState('events', expanded)}
collapseKey='events'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
type='stockEvent'
masterFilter={{ 'parent._id': partStockId }}
visibleColumns={{ parent: false }}
/>
)}
</InfoCollapse>
<InfoCollapse
title='Part Stock History'
icon={<GraphIcon />}
active={collapseState.history}
onToggle={(expanded) => updateCollapseState('history', expanded)}
collapseKey='history'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<HistoryDisplay
history={objectFormState.objectData?.history || []}
objectType='partStock'
chartType='line'
loading={objectFormState.loading}
/>
)}
</InfoCollapse>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}

View File

@ -56,7 +56,7 @@ const ProductStocks = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -87,15 +87,6 @@ const ProductStocks = () => {
type='productStock' type='productStock'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -10,29 +10,22 @@ import InfoCollapse from '../../common/InfoCollapse.jsx'
import ObjectInfo from '../../common/ObjectInfo.jsx' import ObjectInfo from '../../common/ObjectInfo.jsx'
import ObjectProperty from '../../common/ObjectProperty.jsx' import ObjectProperty from '../../common/ObjectProperty.jsx'
import ViewButton from '../../common/ViewButton.jsx' import ViewButton from '../../common/ViewButton.jsx'
import { import { getModelProperty, getModelByName } from '../../../../database/ObjectModels.js'
getModelProperty, import PostProductStock from './PostProductStock.jsx'
getModelByName
} from '../../../../database/ObjectModels.js'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx' import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import PartStockIcon from '../../../Icons/PartStockIcon.jsx' import PartStockIcon from '../../../Icons/PartStockIcon.jsx'
import ProductStockIcon from '../../../Icons/ProductStockIcon.jsx'
import GraphIcon from '../../../Icons/GraphIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx' import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import HistoryDisplay from '../../common/HistoryDisplay.jsx'
const log = loglevel.getLogger('ProductStockInfo') const log = loglevel.getLogger('ProductStockInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -41,27 +34,17 @@ const ProductStockInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const { setOnModalOk } = useActions()
useEffect(() => {
setOnModalOk(() => () => {
objectFormRef.current?.handleFetchObject?.()
})
return () => setOnModalOk(null)
}, [setOnModalOk])
const productStockId = new URLSearchParams(location.search).get( const productStockId = new URLSearchParams(location.search).get(
'productStockId' 'productStockId'
) )
const [postProductStockOpen, setPostProductStockOpen] = useState(false)
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState(
'ProductStockInfo', 'ProductStockInfo',
{ {
info: true, info: true,
partStocks: true, partStocks: true,
events: true,
history: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -69,7 +52,7 @@ const ProductStockInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -91,6 +74,10 @@ const ProductStockInfo = () => {
objectFormRef?.current.handleDelete?.() objectFormRef?.current.handleDelete?.()
return true return true
}, },
post: () => {
setPostProductStockOpen(true)
return true
}
} }
const editDisabled = const editDisabled =
@ -99,6 +86,7 @@ const ProductStockInfo = () => {
?.disabled(objectFormState.objectData) ?? false ?.disabled(objectFormState.objectData) ?? false
return ( return (
<>
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
@ -108,7 +96,7 @@ const ProductStockInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='productStock' type='productStock'
@ -121,8 +109,6 @@ const ProductStockInfo = () => {
items={[ items={[
{ key: 'info', label: 'Product Stock Information' }, { key: 'info', label: 'Product Stock Information' },
{ key: 'partStocks', label: 'Part Stocks' }, { key: 'partStocks', label: 'Part Stocks' },
{ key: 'events', label: 'Product Stock Events' },
{ key: 'history', label: 'Product Stock History' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
{ key: 'auditLogs', label: 'Audit Logs' } { key: 'auditLogs', label: 'Audit Logs' }
]} ]}
@ -140,10 +126,7 @@ const ProductStockInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -160,18 +143,12 @@ const ProductStockInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={productStockId}
objectType='productStock'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -187,7 +164,6 @@ const ProductStockInfo = () => {
type='productStock' type='productStock'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -235,43 +211,6 @@ const ProductStockInfo = () => {
</ObjectForm> </ObjectForm>
</ActionHandler> </ActionHandler>
<InfoCollapse
title='Product Stock Events'
icon={<ProductStockIcon />}
active={collapseState.events}
onToggle={(expanded) => updateCollapseState('events', expanded)}
collapseKey='events'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
type='stockEvent'
masterFilter={{ 'parent._id': productStockId }}
visibleColumns={{ parent: false }}
/>
)}
</InfoCollapse>
<InfoCollapse
title='Product Stock History'
icon={<GraphIcon />}
active={collapseState.history}
onToggle={(expanded) => updateCollapseState('history', expanded)}
collapseKey='history'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<HistoryDisplay
history={objectFormState.objectData?.history || []}
objectType='productStock'
chartType='line'
loading={objectFormState.loading}
/>
)}
</InfoCollapse>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
@ -306,6 +245,25 @@ const ProductStockInfo = () => {
</Flex> </Flex>
</ScrollBox> </ScrollBox>
</Flex> </Flex>
<Modal
open={postProductStockOpen}
onCancel={() => {
setPostProductStockOpen(false)
}}
width={500}
footer={null}
destroyOnHidden={true}
centered={true}
>
<PostProductStock
onOk={() => {
setPostProductStockOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
</>
) )
} }

View File

@ -50,7 +50,7 @@ const PurchaseOrders = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const PurchaseOrders = () => {
type='purchaseOrder' type='purchaseOrder'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,10 +14,8 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
@ -25,10 +23,16 @@ import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import OrderItemsIcon from '../../../Icons/OrderItemIcon.jsx' import OrderItemsIcon from '../../../Icons/OrderItemIcon.jsx'
import NewOrderItem from '../OrderItems/NewOrderItem.jsx'
import NewShipment from '../Shipments/NewShipment.jsx'
import PostPurchaseOrder from './PostPurchaseOrder.jsx'
import AcknowledgePurchaseOrder from './AcknowledgePurchaseOrder.jsx'
import CancelPurchaseOrder from './CancelPurchaseOrder.jsx'
import ShipmentIcon from '../../../Icons/ShipmentIcon.jsx' import ShipmentIcon from '../../../Icons/ShipmentIcon.jsx'
import InvoiceIcon from '../../../Icons/InvoiceIcon.jsx' import InvoiceIcon from '../../../Icons/InvoiceIcon.jsx'
import StockEventIcon from '../../../Icons/StockEventIcon.jsx' import StockEventIcon from '../../../Icons/StockEventIcon.jsx'
import { getModelByName } from '../../../../database/ObjectModels.js' import { getModelByName } from '../../../../database/ObjectModels.js'
import NewInvoice from '../../Finance/Invoices/NewInvoice.jsx'
const log = loglevel.getLogger('PurchaseOrderInfo') const log = loglevel.getLogger('PurchaseOrderInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -39,15 +43,13 @@ const PurchaseOrderInfo = () => {
const orderItemsTableRef = useRef(null) const orderItemsTableRef = useRef(null)
const shipmentsTableRef = useRef(null) const shipmentsTableRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const [newOrderItemOpen, setNewOrderItemOpen] = useState(false)
const [newShipmentOpen, setNewShipmentOpen] = useState(false)
const { setOnModalOk } = useActions() const [postPurchaseOrderOpen, setPostPurchaseOrderOpen] = useState(false)
useEffect(() => { const [acknowledgePurchaseOrderOpen, setAcknowledgePurchaseOrderOpen] =
setOnModalOk(() => () => { useState(false)
objectFormRef.current?.handleFetchObject?.() const [cancelPurchaseOrderOpen, setCancelPurchaseOrderOpen] = useState(false)
}) const [newInvoiceOpen, setNewInvoiceOpen] = useState(false)
return () => setOnModalOk(null)
}, [setOnModalOk])
const purchaseOrderId = new URLSearchParams(location.search).get( const purchaseOrderId = new URLSearchParams(location.search).get(
'purchaseOrderId' 'purchaseOrderId'
) )
@ -56,9 +58,7 @@ const PurchaseOrderInfo = () => {
{ {
info: true, info: true,
notes: true, notes: true,
orderItems: true, auditLogs: true,
shipments: true,
auditLogs: false,
invoices: true, invoices: true,
stockEvents: true stockEvents: true
} }
@ -93,6 +93,30 @@ const PurchaseOrderInfo = () => {
objectFormRef?.current?.handleDelete?.() objectFormRef?.current?.handleDelete?.()
return true return true
}, },
newOrderItem: () => {
setNewOrderItemOpen(true)
return true
},
newShipment: () => {
setNewShipmentOpen(true)
return true
},
newInvoice: () => {
setNewInvoiceOpen(true)
return true
},
post: () => {
setPostPurchaseOrderOpen(true)
return true
},
acknowledge: () => {
setAcknowledgePurchaseOrderOpen(true)
return true
},
cancel: () => {
setCancelPurchaseOrderOpen(true)
return true
}
} }
const editDisabled = getModelByName('purchaseOrder') const editDisabled = getModelByName('purchaseOrder')
@ -100,6 +124,7 @@ const PurchaseOrderInfo = () => {
.disabled(objectFormState.objectData) .disabled(objectFormState.objectData)
return ( return (
<>
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
@ -109,7 +134,7 @@ const PurchaseOrderInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='purchaseOrder' type='purchaseOrder'
@ -142,10 +167,7 @@ const PurchaseOrderInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -162,18 +184,12 @@ const PurchaseOrderInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={purchaseOrderId}
objectType='purchaseOrder'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -189,7 +205,6 @@ const PurchaseOrderInfo = () => {
type='purchaseOrder' type='purchaseOrder'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -334,6 +349,122 @@ const PurchaseOrderInfo = () => {
</Flex> </Flex>
</ScrollBox> </ScrollBox>
</Flex> </Flex>
<Modal
open={newOrderItemOpen}
onCancel={() => {
setNewOrderItemOpen(false)
}}
width={800}
footer={null}
destroyOnHidden={true}
>
<NewOrderItem
onOk={() => {
setNewOrderItemOpen(false)
}}
reset={newOrderItemOpen}
defaultValues={{
order: { _id: purchaseOrderId },
orderType: 'purchaseOrder',
syncAmount: 'itemCost'
}}
/>
</Modal>
<Modal
open={newShipmentOpen}
onCancel={() => {
setNewShipmentOpen(false)
}}
width={800}
footer={null}
destroyOnHidden={true}
>
<NewShipment
onOk={() => {
setNewShipmentOpen(false)
}}
reset={newShipmentOpen}
defaultValues={{
orderType: 'purchaseOrder',
order: { _id: purchaseOrderId }
}}
/>
</Modal>
<Modal
open={newInvoiceOpen}
onCancel={() => {
setNewInvoiceOpen(false)
}}
width={800}
footer={null}
destroyOnHidden={true}
>
<NewInvoice
onOk={() => {
setNewInvoiceOpen(false)
}}
reset={newInvoiceOpen}
defaultValues={{
orderType: 'purchaseOrder',
order: { ...objectFormState.objectData }
}}
/>
</Modal>
<Modal
open={postPurchaseOrderOpen}
onCancel={() => {
setPostPurchaseOrderOpen(false)
}}
width={500}
footer={null}
destroyOnHidden={true}
centered={true}
>
<PostPurchaseOrder
onOk={() => {
setPostPurchaseOrderOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={acknowledgePurchaseOrderOpen}
onCancel={() => {
setAcknowledgePurchaseOrderOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<AcknowledgePurchaseOrder
onOk={() => {
setAcknowledgePurchaseOrderOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={cancelPurchaseOrderOpen}
onCancel={() => {
setCancelPurchaseOrderOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<CancelPurchaseOrder
onOk={() => {
setCancelPurchaseOrderOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
</>
) )
} }

View File

@ -50,7 +50,7 @@ const Shipments = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const Shipments = () => {
type='shipment' type='shipment'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Modal, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,8 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -51,7 +50,7 @@ const PurchaseOrderInfo = () => {
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -113,7 +112,7 @@ const PurchaseOrderInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='purchaseOrder' type='purchaseOrder'
@ -139,10 +138,7 @@ const PurchaseOrderInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -158,17 +154,9 @@ const PurchaseOrderInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={purchaseOrderId}
objectType='purchaseOrder'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -184,7 +172,6 @@ const PurchaseOrderInfo = () => {
type='purchaseOrder' type='purchaseOrder'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,10 +14,8 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
@ -25,6 +23,9 @@ import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import OrderItemIcon from '../../../Icons/OrderItemIcon.jsx' import OrderItemIcon from '../../../Icons/OrderItemIcon.jsx'
import ShipShipment from './ShipShipment.jsx'
import ReceiveShipment from './ReceiveShipment.jsx'
import CancelShipment from './CancelShipment.jsx'
const log = loglevel.getLogger('ShipmentInfo') const log = loglevel.getLogger('ShipmentInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -33,22 +34,13 @@ const ShipmentInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const { setOnModalOk } = useActions()
useEffect(() => {
setOnModalOk(() => () => {
objectFormRef.current?.handleFetchObject?.()
})
return () => setOnModalOk(null)
}, [setOnModalOk])
const shipmentId = new URLSearchParams(location.search).get('shipmentId') const shipmentId = new URLSearchParams(location.search).get('shipmentId')
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState(
'ShipmentInfo', 'ShipmentInfo',
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -60,6 +52,10 @@ const ShipmentInfo = () => {
loading: false, loading: false,
objectData: {} objectData: {}
}) })
const [shipShipmentOpen, setShipShipmentOpen] = useState(false)
const [receiveShipmentOpen, setReceiveShipmentOpen] = useState(false)
const [cancelShipmentOpen, setCancelShipmentOpen] = useState(false)
const actions = { const actions = {
edit: () => { edit: () => {
objectFormRef?.current?.startEditing?.() objectFormRef?.current?.startEditing?.()
@ -77,9 +73,22 @@ const ShipmentInfo = () => {
objectFormRef?.current?.handleDelete?.() objectFormRef?.current?.handleDelete?.()
return true return true
}, },
ship: () => {
setShipShipmentOpen(true)
return true
},
receive: () => {
setReceiveShipmentOpen(true)
return true
},
cancel: () => {
setCancelShipmentOpen(true)
return true
}
} }
return ( return (
<>
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
@ -89,7 +98,7 @@ const ShipmentInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='shipment' type='shipment'
@ -118,10 +127,7 @@ const ShipmentInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -137,17 +143,9 @@ const ShipmentInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={shipmentId}
objectType='shipment'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -163,7 +161,6 @@ const ShipmentInfo = () => {
type='shipment' type='shipment'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -247,6 +244,61 @@ const ShipmentInfo = () => {
</Flex> </Flex>
</ScrollBox> </ScrollBox>
</Flex> </Flex>
<Modal
open={shipShipmentOpen}
onCancel={() => {
setShipShipmentOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<ShipShipment
onOk={() => {
setShipShipmentOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={receiveShipmentOpen}
onCancel={() => {
setReceiveShipmentOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<ReceiveShipment
onOk={() => {
setReceiveShipmentOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
<Modal
open={cancelShipmentOpen}
onCancel={() => {
setCancelShipmentOpen(false)
}}
width={515}
footer={null}
destroyOnHidden={true}
centered={true}
>
<CancelShipment
onOk={() => {
setCancelShipmentOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
</>
) )
} }

View File

@ -55,7 +55,7 @@ const StockAudits = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -86,15 +86,6 @@ const StockAudits = () => {
type='stockAudit' type='stockAudit'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,8 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -38,7 +37,7 @@ const StockAuditInfo = () => {
info: true, info: true,
stocks: true, stocks: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -46,7 +45,7 @@ const StockAuditInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -77,7 +76,7 @@ const StockAuditInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockAudit' type='stockAudit'
@ -106,10 +105,7 @@ const StockAuditInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -125,17 +121,9 @@ const StockAuditInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={stockAuditId}
objectType='stockAudit'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -158,7 +146,6 @@ const StockAuditInfo = () => {
type='stockAudit' type='stockAudit'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -38,7 +38,7 @@ const StockEvents = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -69,15 +69,6 @@ const StockEvents = () => {
type='stockEvent' type='stockEvent'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
</> </>

View File

@ -53,7 +53,7 @@ const StockLocations = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -84,15 +84,6 @@ const StockLocations = () => {
type='stockLocation' type='stockLocation'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,8 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -39,7 +38,7 @@ const StockLocationInfo = () => {
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -47,7 +46,7 @@ const StockLocationInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -78,7 +77,7 @@ const StockLocationInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockLocation' type='stockLocation'
@ -107,10 +106,7 @@ const StockLocationInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -126,17 +122,9 @@ const StockLocationInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={stockLocationId}
objectType='stockLocation'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -159,7 +147,6 @@ const StockLocationInfo = () => {
type='stockLocation' type='stockLocation'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -53,7 +53,7 @@ const StockTransfers = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -84,15 +84,6 @@ const StockTransfers = () => {
type='stockTransfer' type='stockTransfer'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import useCollapseState from '../../hooks/useCollapseState.jsx' import useCollapseState from '../../hooks/useCollapseState.jsx'
import NotesPanel from '../../common/NotesPanel.jsx' import NotesPanel from '../../common/NotesPanel.jsx'
@ -8,20 +8,16 @@ import InfoCollapse from '../../common/InfoCollapse.jsx'
import ObjectInfo from '../../common/ObjectInfo.jsx' import ObjectInfo from '../../common/ObjectInfo.jsx'
import ObjectProperty from '../../common/ObjectProperty.jsx' import ObjectProperty from '../../common/ObjectProperty.jsx'
import ViewButton from '../../common/ViewButton.jsx' import ViewButton from '../../common/ViewButton.jsx'
import { import { getModelProperty, getModelByName } from '../../../../database/ObjectModels.js'
getModelProperty, import PostStockTransfer from './PostStockTransfer.jsx'
getModelByName
} from '../../../../database/ObjectModels.js'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx' import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import StockTransferIcon from '../../../Icons/StockTransferIcon.jsx' import StockTransferIcon from '../../../Icons/StockTransferIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
@ -33,25 +29,17 @@ const StockTransferInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const { setOnModalOk } = useActions()
useEffect(() => {
setOnModalOk(() => () => {
objectFormRef.current?.handleFetchObject?.()
})
return () => setOnModalOk(null)
}, [setOnModalOk])
const stockTransferId = new URLSearchParams(location.search).get( const stockTransferId = new URLSearchParams(location.search).get(
'stockTransferId' 'stockTransferId'
) )
const [postOpen, setPostOpen] = useState(false)
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState(
'StockTransferInfo', 'StockTransferInfo',
{ {
info: true, info: true,
lines: true, lines: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -59,7 +47,7 @@ const StockTransferInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -81,6 +69,10 @@ const StockTransferInfo = () => {
objectFormRef?.current.handleDelete?.() objectFormRef?.current.handleDelete?.()
return true return true
}, },
post: () => {
setPostOpen(true)
return true
}
} }
const editDisabled = const editDisabled =
@ -89,6 +81,7 @@ const StockTransferInfo = () => {
?.disabled(objectFormState.objectData) ?? false ?.disabled(objectFormState.objectData) ?? false
return ( return (
<>
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
@ -98,7 +91,7 @@ const StockTransferInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='stockTransfer' type='stockTransfer'
@ -128,10 +121,7 @@ const StockTransferInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -148,18 +138,12 @@ const StockTransferInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={stockTransferId}
objectType='stockTransfer'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -175,7 +159,6 @@ const StockTransferInfo = () => {
type='stockTransfer' type='stockTransfer'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -257,6 +240,25 @@ const StockTransferInfo = () => {
</Flex> </Flex>
</ScrollBox> </ScrollBox>
</Flex> </Flex>
<Modal
open={postOpen}
onCancel={() => {
setPostOpen(false)
}}
width={520}
footer={null}
destroyOnHidden={true}
centered={true}
>
<PostStockTransfer
onOk={() => {
setPostOpen(false)
objectFormRef?.current.handleFetchObject()
}}
objectData={objectFormState.objectData}
/>
</Modal>
</>
) )
} }

View File

@ -12,6 +12,7 @@ import useCollapseState from '../hooks/useCollapseState'
import InfoCollapse from '../common/InfoCollapse' import InfoCollapse from '../common/InfoCollapse'
import InfoCircleIcon from '../../Icons/InfoCircleIcon' import InfoCircleIcon from '../../Icons/InfoCircleIcon'
import ReloadIcon from '../../Icons/ReloadIcon' import ReloadIcon from '../../Icons/ReloadIcon'
import DownloadIcon from '../../Icons/DownloadIcon'
import DeveloperIcon from '../../Icons/DeveloperIcon' import DeveloperIcon from '../../Icons/DeveloperIcon'
import { version as appVersion } from '../../../../package.json' import { version as appVersion } from '../../../../package.json'
import { ApiServerContext } from '../context/ApiServerContext' import { ApiServerContext } from '../context/ApiServerContext'
@ -20,7 +21,6 @@ import { ElectronContext } from '../context/ElectronContext'
import { AppUpdateContext } from '../context/AppUpdateContext' import { AppUpdateContext } from '../context/AppUpdateContext'
import { useMediaQuery } from 'react-responsive' import { useMediaQuery } from 'react-responsive'
import FarmControlAppIcon from '../../Logos/FarmControlAppIcon' import FarmControlAppIcon from '../../Logos/FarmControlAppIcon'
import SoftwareUpdateIcon from '../../Icons/SoftwareUpdateIcon'
const { Title, Text, Link } = Typography const { Title, Text, Link } = Typography
const About = () => { const About = () => {
@ -53,7 +53,7 @@ const About = () => {
actions.unshift( actions.unshift(
{ {
label: 'Check for Updates', label: 'Check for Updates',
icon: <SoftwareUpdateIcon />, icon: <DownloadIcon />,
onClick: checkForUpdates onClick: checkForUpdates
}, },
{ type: 'divider' } { type: 'divider' }
@ -126,7 +126,9 @@ const About = () => {
collapseKey='purchaseOrderStats' collapseKey='purchaseOrderStats'
> >
<Flex gap='large'> <Flex gap='large'>
<FarmControlAppIcon style={{ width: '200px', height: '200px' }} /> <FarmControlAppIcon
style={{ width: '200px', height: '200px' }}
/>
<Flex vertical gap='small' justify='center'> <Flex vertical gap='small' justify='center'>
<Flex gap='middle' align='center'> <Flex gap='middle' align='center'>
<Title level={2} style={{ margin: 0 }}> <Title level={2} style={{ margin: 0 }}>

View File

@ -49,7 +49,7 @@ const AppPasswords = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space> <Space>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const AppPasswords = () => {
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect, useContext } from 'react' import { useRef, useState, useContext } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Flex, Space } from 'antd' import { Space, Flex, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -10,16 +10,15 @@ import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx' import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import RegenerateAppPasswordSecret from './RegenerateAppPasswordSecret.jsx'
import { getModelByName } from '../../../../database/ObjectModels.js' import { getModelByName } from '../../../../database/ObjectModels.js'
import { AuthContext } from '../../context/AuthContext.jsx' import { AuthContext } from '../../context/AuthContext.jsx'
@ -27,24 +26,16 @@ const AppPasswordInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const { setOnModalOk } = useActions()
useEffect(() => {
setOnModalOk(() => () => {
objectFormRef.current?.handleFetchObject?.()
})
return () => setOnModalOk(null)
}, [setOnModalOk])
const { userProfile } = useContext(AuthContext) const { userProfile } = useContext(AuthContext)
const appPasswordId = new URLSearchParams(location.search).get( const appPasswordId = new URLSearchParams(location.search).get(
'appPasswordId' 'appPasswordId'
) )
const [regenerateSecretOpen, setRegenerateSecretOpen] = useState(false)
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState(
'AppPasswordInfo', 'AppPasswordInfo',
{ {
info: true, info: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -57,6 +48,10 @@ const AppPasswordInfo = () => {
}) })
const actions = { const actions = {
regenerateSecret: () => {
setRegenerateSecretOpen(true)
return false
},
edit: () => { edit: () => {
objectFormRef?.current?.startEditing?.() objectFormRef?.current?.startEditing?.()
return false return false
@ -76,13 +71,14 @@ const AppPasswordInfo = () => {
.disabled({ ...objectFormState.objectData, _user: userProfile }) .disabled({ ...objectFormState.objectData, _user: userProfile })
return ( return (
<>
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='appPassword' type='appPassword'
@ -110,10 +106,7 @@ const AppPasswordInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -130,18 +123,12 @@ const AppPasswordInfo = () => {
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={
objectFormState.beingEditedByOther || objectFormState.lock?.locked ||
objectFormState.loading || objectFormState.loading ||
editDisabled editDisabled
} }
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={appPasswordId}
objectType='appPassword'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -163,7 +150,6 @@ const AppPasswordInfo = () => {
type='appPassword' type='appPassword'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -202,6 +188,20 @@ const AppPasswordInfo = () => {
</Flex> </Flex>
</ScrollBox> </ScrollBox>
</Flex> </Flex>
<Modal
open={regenerateSecretOpen}
destroyOnClose
width={650}
onCancel={() => {
actionHandlerRef.current?.clearAction?.()
setRegenerateSecretOpen(false)
}}
footer={null}
>
<RegenerateAppPasswordSecret id={appPasswordId} />
</Modal>
</>
) )
} }

View File

@ -24,12 +24,25 @@ const NewAppPassword = ({ onOk, reset, defaultValues = {} }) => {
column={1} column={1}
bordered={false} bordered={false}
isEditing={true} isEditing={true}
labelWidth={75}
required={true} required={true}
objectData={objectData} objectData={objectData}
/> />
) )
}, },
{
title: 'Optional',
key: 'optional',
content: (
<ObjectInfo
type='appPassword'
column={1}
bordered={false}
isEditing={true}
required={false}
objectData={objectData}
/>
)
},
{ {
title: 'Summary', title: 'Summary',
key: 'summary', key: 'summary',
@ -46,7 +59,6 @@ const NewAppPassword = ({ onOk, reset, defaultValues = {} }) => {
secret: false secret: false
}} }}
isEditing={false} isEditing={false}
labelWidth={70}
objectData={objectData} objectData={objectData}
/> />
) )

View File

@ -1,6 +1,6 @@
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { useState } from 'react' import { useState } from 'react'
import { Button, Flex, Modal, Progress, Typography, theme, Divider } from 'antd' import { Button, Flex, Modal, Progress, Typography, theme } from 'antd'
import CloudIcon from '../../../Icons/CloudIcon' import CloudIcon from '../../../Icons/CloudIcon'
import HostIcon from '../../../Icons/HostIcon' import HostIcon from '../../../Icons/HostIcon'
@ -72,17 +72,11 @@ const getDownloadStageStatus = (phase, isError) => {
return 'pending' return 'pending'
} }
const isInstallComplete = (phase, message) => { const isInstallComplete = (phase, message) =>
if (phase !== 'installing') return false phase === 'installing' &&
String(message || '')
const normalized = String(message || '').toLowerCase() .toLowerCase()
.includes('complete')
return (
normalized.includes('complete') ||
normalized.includes('successful') ||
normalized.includes('restarting')
)
}
const getInstallStageStatus = (phase, isError, message) => { const getInstallStageStatus = (phase, isError, message) => {
if (isError && ['downloaded', 'installing'].includes(phase)) return 'error' if (isError && ['downloaded', 'installing'].includes(phase)) return 'error'
@ -112,7 +106,7 @@ const UpdateStage = ({ stage, status, percent, detail }) => {
const resolvedStatus = const resolvedStatus =
status !== 'error' && resolvedPercent === 100 ? 'complete' : status status !== 'error' && resolvedPercent === 100 ? 'complete' : status
const color = getStageColor(resolvedStatus, token) const color = getStageColor(resolvedStatus, token)
const showProgress = resolvedStatus === 'active' && stage !== 'restart' const showProgress = resolvedStatus === 'active'
const StatusIcon = const StatusIcon =
resolvedStatus === 'complete' resolvedStatus === 'complete'
@ -179,6 +173,8 @@ const AppUpdateProgress = ({ progress, update, onClose }) => {
const installDetail = installStatus === 'active' ? message : null const installDetail = installStatus === 'active' ? message : null
const restartDetail = restartStatus === 'active' ? message : null
return ( return (
<Flex vertical gap='middle'> <Flex vertical gap='middle'>
<Text> <Text>
@ -188,7 +184,6 @@ const AppUpdateProgress = ({ progress, update, onClose }) => {
{update?.branch ? `${update.branch}` : 'unknown'}... {update?.branch ? `${update.branch}` : 'unknown'}...
</Text> </Text>
<Divider style={{ margin: '4px 0' }} />
<Flex vertical gap='middle'> <Flex vertical gap='middle'>
<UpdateStage <UpdateStage
stage='download' stage='download'
@ -202,7 +197,11 @@ const AppUpdateProgress = ({ progress, update, onClose }) => {
percent={installPercent} percent={installPercent}
detail={installDetail} detail={installDetail}
/> />
<UpdateStage stage='restart' status={restartStatus} /> <UpdateStage
stage='restart'
status={restartStatus}
detail={restartDetail}
/>
</Flex> </Flex>
<Modal <Modal

View File

@ -36,7 +36,7 @@ const AuditLogs = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -62,15 +62,6 @@ const AuditLogs = () => {
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
type='auditLog' type='auditLog'
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
</> </>

View File

@ -50,7 +50,7 @@ const CourierServices = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const CourierServices = () => {
type='courierService' type='courierService'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,8 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -38,7 +37,7 @@ const CourierServiceInfo = () => {
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -77,7 +76,7 @@ const CourierServiceInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='courierService' type='courierService'
@ -106,10 +105,7 @@ const CourierServiceInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -125,17 +121,9 @@ const CourierServiceInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={courierServiceId}
objectType='courierService'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -157,7 +145,6 @@ const CourierServiceInfo = () => {
type='courierService' type='courierService'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -10,9 +10,6 @@ const NewCourierService = ({ onOk, defaultValues }) => {
defaultValues={{ defaultValues={{
active: true, active: true,
tracked: false, tracked: false,
cost: 0,
shippingCurrency: 'GBP',
international: false,
...defaultValues ...defaultValues
}} }}
> >
@ -29,7 +26,6 @@ const NewCourierService = ({ onOk, defaultValues }) => {
isEditing={true} isEditing={true}
required={true} required={true}
objectData={objectData} objectData={objectData}
labelWidth={80}
/> />
) )
}, },
@ -43,7 +39,6 @@ const NewCourierService = ({ onOk, defaultValues }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={false} required={false}
labelWidth={120}
objectData={objectData} objectData={objectData}
/> />
) )
@ -64,7 +59,6 @@ const NewCourierService = ({ onOk, defaultValues }) => {
}} }}
isEditing={false} isEditing={false}
objectData={objectData} objectData={objectData}
labelWidth={120}
/> />
) )
} }

View File

@ -49,7 +49,7 @@ const Couriers = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -79,15 +79,6 @@ const Couriers = () => {
type='courier' type='courier'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,8 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -35,7 +34,7 @@ const CourierInfo = () => {
const [collapseState, updateCollapseState] = useCollapseState('CourierInfo', { const [collapseState, updateCollapseState] = useCollapseState('CourierInfo', {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
}) })
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
isEditing: false, isEditing: false,
@ -73,7 +72,7 @@ const CourierInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='courier' type='courier'
@ -102,10 +101,7 @@ const CourierInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -121,17 +117,9 @@ const CourierInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={courierId}
objectType='courier'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -153,7 +141,6 @@ const CourierInfo = () => {
type='courier' type='courier'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -19,7 +19,6 @@ const NewCourier = ({ onOk, defaultValues }) => {
isEditing={true} isEditing={true}
required={true} required={true}
objectData={objectData} objectData={objectData}
labelWidth={75}
/> />
) )
}, },
@ -34,7 +33,6 @@ const NewCourier = ({ onOk, defaultValues }) => {
isEditing={true} isEditing={true}
required={false} required={false}
objectData={objectData} objectData={objectData}
labelWidth={85}
/> />
) )
}, },
@ -54,7 +52,6 @@ const NewCourier = ({ onOk, defaultValues }) => {
}} }}
isEditing={false} isEditing={false}
objectData={objectData} objectData={objectData}
labelWidth={85}
/> />
) )
} }

View File

@ -50,7 +50,7 @@ const DocumentJobs = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const DocumentJobs = () => {
type='documentJob' type='documentJob'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,8 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -39,7 +38,7 @@ const DocumentJobInfo = () => {
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -74,7 +73,7 @@ const DocumentJobInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentJob' type='documentJob'
@ -103,10 +102,7 @@ const DocumentJobInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -122,17 +118,9 @@ const DocumentJobInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={documentJobId}
objectType='documentJob'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -154,7 +142,6 @@ const DocumentJobInfo = () => {
type='documentJob' type='documentJob'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -35,7 +35,6 @@ const NewDocumentJob = ({ onOk, defaultValues = {} }) => {
column={1} column={1}
visibleProperties={{ name: false }} visibleProperties={{ name: false }}
bordered={false} bordered={false}
labelWidth={115}
isEditing={true} isEditing={true}
required={true} required={true}
objectData={objectData} objectData={objectData}
@ -57,7 +56,7 @@ const NewDocumentJob = ({ onOk, defaultValues = {} }) => {
disabled={downloading} disabled={downloading}
sideBarGrow={true} sideBarGrow={true}
sideBar={ sideBar={
<div style={{ minHeight: '760px', flexGrow: 1 }}> <div style={{ minHeight: '500px', flexGrow: 1 }}>
<TemplatePreview <TemplatePreview
objectData={objectData?.object} objectData={objectData?.object}
documentTemplate={objectData?.documentTemplate} documentTemplate={objectData?.documentTemplate}

View File

@ -49,7 +49,7 @@ const DocumentPrinters = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -79,15 +79,6 @@ const DocumentPrinters = () => {
type='documentPrinter' type='documentPrinter'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,8 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -40,7 +39,7 @@ const DocumentPrinterInfo = () => {
info: true, info: true,
stocks: true, stocks: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -48,7 +47,7 @@ const DocumentPrinterInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -79,7 +78,7 @@ const DocumentPrinterInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentPrinter' type='documentPrinter'
@ -111,10 +110,7 @@ const DocumentPrinterInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -130,17 +126,9 @@ const DocumentPrinterInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={documentPrinterId}
objectType='documentPrinter'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -163,7 +151,6 @@ const DocumentPrinterInfo = () => {
type='documentPrinter' type='documentPrinter'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -174,7 +161,6 @@ const DocumentPrinterInfo = () => {
loading={loading} loading={loading}
indicator={<LoadingOutlined />} indicator={<LoadingOutlined />}
isEditing={isEditing} isEditing={isEditing}
labelWidth={165}
type='documentPrinter' type='documentPrinter'
objectData={objectData} objectData={objectData}
/> />

View File

@ -21,7 +21,6 @@ const NewDocumentPrinter = ({ onOk, defaultValues }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={true} required={true}
labelWidth={100}
objectData={objectData} objectData={objectData}
/> />
) )
@ -36,7 +35,6 @@ const NewDocumentPrinter = ({ onOk, defaultValues }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={false} required={false}
labelWidth={125}
visibleProperties={{ content: false, testObject: false }} visibleProperties={{ content: false, testObject: false }}
objectData={objectData} objectData={objectData}
/> />
@ -54,12 +52,8 @@ const NewDocumentPrinter = ({ onOk, defaultValues }) => {
_id: false, _id: false,
_reference: false, _reference: false,
createdAt: false, createdAt: false,
connectedAt: false,
state: false,
online: false,
updatedAt: false updatedAt: false
}} }}
labelWidth={130}
isEditing={false} isEditing={false}
objectData={objectData} objectData={objectData}
/> />

View File

@ -48,7 +48,7 @@ const DocumentSizes = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -78,15 +78,6 @@ const DocumentSizes = () => {
type='documentSize' type='documentSize'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,8 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -39,7 +38,7 @@ const DocumentSizeInfo = () => {
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -74,7 +73,7 @@ const DocumentSizeInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentSize' type='documentSize'
@ -103,10 +102,7 @@ const DocumentSizeInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -122,17 +118,9 @@ const DocumentSizeInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={documentSizeId}
objectType='documentSize'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -154,7 +142,6 @@ const DocumentSizeInfo = () => {
type='documentSize' type='documentSize'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -164,7 +151,6 @@ const DocumentSizeInfo = () => {
loading={loading} loading={loading}
indicator={<LoadingOutlined />} indicator={<LoadingOutlined />}
isEditing={isEditing} isEditing={isEditing}
labelWidth={160}
type='documentSize' type='documentSize'
objectData={objectData} objectData={objectData}
/> />

View File

@ -22,7 +22,6 @@ const NewDocumentSize = ({ onOk, defaultValues }) => {
isEditing={true} isEditing={true}
required={true} required={true}
objectData={objectData} objectData={objectData}
labelWidth={120}
/> />
) )
}, },
@ -40,7 +39,6 @@ const NewDocumentSize = ({ onOk, defaultValues }) => {
createdAt: false, createdAt: false,
updatedAt: false updatedAt: false
}} }}
labelWidth={120}
isEditing={false} isEditing={false}
objectData={objectData} objectData={objectData}
/> />

View File

@ -50,7 +50,7 @@ const DocumentTemplates = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const DocumentTemplates = () => {
type='documentTemplate' type='documentTemplate'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -10,7 +10,7 @@ import ViewButton from '../../common/ViewButton.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
@ -33,7 +33,7 @@ const DocumentTemplateDesign = () => {
preview: true, preview: true,
editor: true, editor: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -41,7 +41,7 @@ const DocumentTemplateDesign = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -97,7 +97,7 @@ const DocumentTemplateDesign = () => {
updateVisibleState={updateCollapseState} updateVisibleState={updateCollapseState}
/> />
</Space> </Space>
<ActivityIndicator activities={objectFormState.activities} /> <LockIndicator lock={objectFormState.lock} />
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -113,7 +113,7 @@ const DocumentTemplateDesign = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={objectFormState.beingEditedByOther || objectFormState.loading} disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
</Space> </Space>

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,8 +14,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -40,7 +39,7 @@ const DocumentTemplateInfo = () => {
info: true, info: true,
stocks: true, stocks: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -48,7 +47,7 @@ const DocumentTemplateInfo = () => {
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
@ -79,7 +78,7 @@ const DocumentTemplateInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='documentTemplate' type='documentTemplate'
@ -108,10 +107,7 @@ const DocumentTemplateInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -127,17 +123,9 @@ const DocumentTemplateInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={documentTemplateId}
objectType='documentTemplate'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -160,7 +148,6 @@ const DocumentTemplateInfo = () => {
type='documentTemplate' type='documentTemplate'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -177,7 +164,7 @@ const DocumentTemplateInfo = () => {
content: false, content: false,
testObject: false testObject: false
}} }}
labelWidth='190px' labelWidth='175px'
/> />
) )
}} }}

View File

@ -21,7 +21,6 @@ const NewDocumentTemplate = ({ onOk, defaultValues }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={true} required={true}
labelWidth={130}
objectData={objectData} objectData={objectData}
/> />
) )

View File

@ -53,7 +53,7 @@ const FilamentSkus = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -84,15 +84,6 @@ const FilamentSkus = () => {
type='filamentSku' type='filamentSku'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -8,8 +8,7 @@ import ObjectInfo from '../../common/ObjectInfo'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx' import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
@ -25,15 +24,13 @@ const FilamentSkuInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const filamentSkuId = new URLSearchParams(location.search).get( const filamentSkuId = new URLSearchParams(location.search).get('filamentSkuId')
'filamentSkuId'
)
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState(
'FilamentSkuInfo', 'FilamentSkuInfo',
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -72,7 +69,7 @@ const FilamentSkuInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='filamentSku' type='filamentSku'
@ -101,10 +98,7 @@ const FilamentSkuInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -120,17 +114,9 @@ const FilamentSkuInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={filamentSkuId}
objectType='filamentSku'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -152,7 +138,6 @@ const FilamentSkuInfo = () => {
type='filamentSku' type='filamentSku'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -8,14 +8,9 @@ const NewFilamentSku = ({ onOk, reset, defaultValues }) => {
<NewObjectForm <NewObjectForm
type='filamentSku' type='filamentSku'
reset={reset} reset={reset}
defaultValues={{ defaultValues={defaultValues}
overrideCost: false,
color: '#ff0000',
...defaultValues
}}
> >
{({ handleSubmit, submitLoading, objectData, formValid }) => { {({ handleSubmit, submitLoading, objectData, formValid }) => {
console.log('objectData', objectData)
const steps = [ const steps = [
{ {
title: 'Required', title: 'Required',
@ -24,7 +19,7 @@ const NewFilamentSku = ({ onOk, reset, defaultValues }) => {
<ObjectInfo <ObjectInfo
type='filamentSku' type='filamentSku'
column={1} column={1}
labelWidth={80} labelWidth={70}
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={true} required={true}
@ -34,26 +29,27 @@ const NewFilamentSku = ({ onOk, reset, defaultValues }) => {
cost: false, cost: false,
costWithTax: false, costWithTax: false,
costTaxRate: false, costTaxRate: false,
overrideCost: false,
vendor: false vendor: false
}} }}
/> />
) )
}, },
{ {
title: 'Cost', title: 'Color & Cost',
key: 'cost', key: 'colorCost',
content: ( content: (
<ObjectInfo <ObjectInfo
type='filamentSku' type='filamentSku'
column={1} column={1}
labelWidth={120} labelWidth={100}
required={true}
visibleProperties={{ visibleProperties={{
overrideCost: true, _id: false,
cost: true, createdAt: false,
costTaxRate: true, updatedAt: false,
costWithTax: true barcode: false,
filament: false,
name: false,
description: false
}} }}
bordered={false} bordered={false}
isEditing={true} isEditing={true}
@ -68,7 +64,7 @@ const NewFilamentSku = ({ onOk, reset, defaultValues }) => {
<ObjectInfo <ObjectInfo
type='filamentSku' type='filamentSku'
column={1} column={1}
labelWidth={110} labelWidth={100}
visibleProperties={{ visibleProperties={{
barcode: true, barcode: true,
description: true description: true
@ -92,9 +88,9 @@ const NewFilamentSku = ({ onOk, reset, defaultValues }) => {
_id: false, _id: false,
_reference: false _reference: false
}} }}
labelWidth={100}
bordered={false} bordered={false}
isEditing={false} isEditing={false}
labelWidth={120}
objectData={objectData} objectData={objectData}
/> />
) )

View File

@ -55,7 +55,7 @@ const Filaments = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space> <Space>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -86,15 +86,6 @@ const Filaments = () => {
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
@ -14,10 +14,8 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler' import ActionHandler from '../../common/ActionHandler'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
@ -26,6 +24,7 @@ import FilamentSkuIcon from '../../../Icons/FilamentSkuIcon.jsx'
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx' import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import NewFilamentSku from '../FilamentSkus/NewFilamentSku'
const log = loglevel.getLogger('FilamentInfo') const log = loglevel.getLogger('FilamentInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -35,15 +34,8 @@ const FilamentInfo = () => {
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const filamentId = new URLSearchParams(location.search).get('filamentId') const filamentId = new URLSearchParams(location.search).get('filamentId')
const [newFilamentSkuOpen, setNewFilamentSkuOpen] = useState(false)
const filamentSkusTableRef = useRef() const filamentSkusTableRef = useRef()
const { setOnModalOk } = useActions()
useEffect(() => {
setOnModalOk(() => () => {
filamentSkusTableRef.current?.reload?.()
})
return () => setOnModalOk(null)
}, [setOnModalOk])
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState(
'FilamentInfo', 'FilamentInfo',
{ {
@ -51,7 +43,7 @@ const FilamentInfo = () => {
filamentSkus: true, filamentSkus: true,
stocks: true, stocks: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
@ -65,6 +57,10 @@ const FilamentInfo = () => {
}) })
const actions = { const actions = {
newFilamentSku: () => {
setNewFilamentSkuOpen(true)
return true
},
edit: () => { edit: () => {
objectFormRef?.current?.startEditing?.() objectFormRef?.current?.startEditing?.()
return false return false
@ -84,192 +80,204 @@ const FilamentInfo = () => {
} }
return ( return (
<Flex <>
gap='large' <Flex
vertical='true' gap='large'
style={{ vertical='true'
maxHeight: '100%', style={{
minHeight: 0 maxHeight: '100%',
}} minHeight: 0
> }}
<Flex justify={'space-between'}> >
<Space size='small'> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<ObjectActions <Space size='small'>
type='filament' <ObjectActions
id={filamentId} type='filament'
disabled={objectFormState.loading} id={filamentId}
objectData={objectFormState.objectData} disabled={objectFormState.loading}
/> objectData={objectFormState.objectData}
<ViewButton />
disabled={objectFormState.loading} <ViewButton
items={[ disabled={objectFormState.loading}
{ key: 'info', label: 'Filament Information' }, items={[
{ key: 'filamentSkus', label: 'Filament SKUs' }, { key: 'info', label: 'Filament Information' },
{ key: 'stocks', label: 'Filament Stocks' }, { key: 'filamentSkus', label: 'Filament SKUs' },
{ key: 'notes', label: 'Notes' }, { key: 'stocks', label: 'Filament Stocks' },
{ key: 'auditLogs', label: 'Audit Logs' } { key: 'notes', label: 'Notes' },
]} { key: 'auditLogs', label: 'Audit Logs' }
visibleState={collapseState} ]}
updateVisibleState={updateCollapseState} visibleState={collapseState}
/> updateVisibleState={updateCollapseState}
<UserNotifierToggle />
type='filament' <UserNotifierToggle
objectData={objectFormState.objectData} type='filament'
disabled={objectFormState.loading} objectData={objectFormState.objectData}
/> disabled={objectFormState.loading}
<DocumentPrintButton />
type='filament' <DocumentPrintButton
objectData={objectFormState.objectData} type='filament'
disabled={objectFormState.loading} objectData={objectFormState.objectData}
disabled={objectFormState.loading}
/>
</Space>
<LockIndicator lock={objectFormState.lock} />
</Space>
<Space>
<EditButtons
isEditing={objectFormState.isEditing}
handleUpdate={() => {
actionHandlerRef.current.callAction('finishEdit')
}}
cancelEditing={() => {
actionHandlerRef.current.callAction('cancelEdit')
}}
startEditing={() => {
actionHandlerRef.current.callAction('edit')
}}
editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid}
disabled={objectFormState.lock?.locked || objectFormState.loading}
loading={objectFormState.editLoading}
/> />
</Space> </Space>
<ActivityIndicator
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space>
<Space>
<EditButtons
isEditing={objectFormState.isEditing}
handleUpdate={() => {
actionHandlerRef.current.callAction('finishEdit')
}}
cancelEditing={() => {
actionHandlerRef.current.callAction('cancelEdit')
}}
startEditing={() => {
actionHandlerRef.current.callAction('edit')
}}
editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid}
disabled={
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading}
/>
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={filamentId}
objectType='filament'
showEndingDivider={true}
/>
</Space>
</Flex>
<ScrollBox>
<Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={objectFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse
title='Filament Information'
icon={<InfoCircleIcon />}
active={collapseState.info}
onToggle={(expanded) => updateCollapseState('info', expanded)}
collapseKey='info'
>
<ObjectForm
id={filamentId}
type='filament'
style={{ height: '100%' }}
ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => {
return (
<ObjectInfo
loading={loading}
indicator={<LoadingOutlined />}
isEditing={isEditing}
type='filament'
objectData={objectData}
/>
)
}}
</ObjectForm>
</InfoCollapse>
</ActionHandler>
<InfoCollapse
title='Filament SKUs'
icon={<FilamentSkuIcon />}
active={collapseState.filamentSkus}
onToggle={(expanded) =>
updateCollapseState('filamentSkus', expanded)
}
collapseKey='filamentSkus'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
ref={filamentSkusTableRef}
type='filamentSku'
masterFilter={{ filament: filamentId }}
visibleColumns={{ filament: false }}
/>
)}
</InfoCollapse>
<InfoCollapse
title='Filament Stocks'
icon={<FilamentIcon />}
active={collapseState.stocks}
onToggle={(expanded) => updateCollapseState('stocks', expanded)}
collapseKey='stocks'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
type='filamentStock'
masterFilter={{ filament: filamentId }}
visibleColumns={{
filament: false,
startingWeight: false
}}
/>
)}
</InfoCollapse>
<InfoCollapse
title='Notes'
icon={<NoteIcon />}
active={collapseState.notes}
onToggle={(expanded) => updateCollapseState('notes', expanded)}
collapseKey='notes'
>
<Card>
<NotesPanel _id={filamentId} type='filament' />
</Card>
</InfoCollapse>
<InfoCollapse
title='Audit Logs'
icon={<AuditLogIcon />}
active={collapseState.auditLogs}
onToggle={(expanded) => updateCollapseState('auditLogs', expanded)}
collapseKey='auditLogs'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
type='auditLog'
masterFilter={{ 'parent._id': filamentId }}
visibleColumns={{ _id: false, 'parent._id': false }}
/>
)}
</InfoCollapse>
</Flex> </Flex>
</ScrollBox>
</Flex> <ScrollBox>
<Flex vertical gap={'large'}>
<ActionHandler
actions={actions}
loading={objectFormState.loading}
ref={actionHandlerRef}
>
<InfoCollapse
title='Filament Information'
icon={<InfoCircleIcon />}
active={collapseState.info}
onToggle={(expanded) => updateCollapseState('info', expanded)}
collapseKey='info'
>
<ObjectForm
id={filamentId}
type='filament'
style={{ height: '100%' }}
ref={objectFormRef}
onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state }))
}}
>
{({ loading, isEditing, objectData }) => {
return (
<ObjectInfo
loading={loading}
indicator={<LoadingOutlined />}
isEditing={isEditing}
type='filament'
objectData={objectData}
/>
)
}}
</ObjectForm>
</InfoCollapse>
</ActionHandler>
<InfoCollapse
title='Filament SKUs'
icon={<FilamentSkuIcon />}
active={collapseState.filamentSkus}
onToggle={(expanded) =>
updateCollapseState('filamentSkus', expanded)
}
collapseKey='filamentSkus'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
ref={filamentSkusTableRef}
type='filamentSku'
masterFilter={{ filament: filamentId }}
visibleColumns={{ filament: false }}
/>
)}
</InfoCollapse>
<InfoCollapse
title='Filament Stocks'
icon={<FilamentIcon />}
active={collapseState.stocks}
onToggle={(expanded) => updateCollapseState('stocks', expanded)}
collapseKey='stocks'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
type='filamentStock'
masterFilter={{ filament: filamentId }}
visibleColumns={{
filament: false,
startingWeight: false
}}
/>
)}
</InfoCollapse>
<Modal
open={newFilamentSkuOpen}
styles={{ content: { paddingBottom: '24px' } }}
footer={null}
width={700}
onCancel={() => setNewFilamentSkuOpen(false)}
destroyOnClose
>
<NewFilamentSku
onOk={() => {
setNewFilamentSkuOpen(false)
filamentSkusTableRef.current?.reload?.()
}}
reset={newFilamentSkuOpen}
defaultValues={{
filament: filamentId ? { _id: filamentId } : undefined
}}
/>
</Modal>
<InfoCollapse
title='Notes'
icon={<NoteIcon />}
active={collapseState.notes}
onToggle={(expanded) => updateCollapseState('notes', expanded)}
collapseKey='notes'
>
<Card>
<NotesPanel _id={filamentId} type='filament' />
</Card>
</InfoCollapse>
<InfoCollapse
title='Audit Logs'
icon={<AuditLogIcon />}
active={collapseState.auditLogs}
onToggle={(expanded) =>
updateCollapseState('auditLogs', expanded)
}
collapseKey='auditLogs'
>
{objectFormState.loading ? (
<InfoCollapsePlaceholder />
) : (
<ObjectTable
type='auditLog'
masterFilter={{ 'parent._id': filamentId }}
visibleColumns={{ _id: false, 'parent._id': false }}
/>
)}
</InfoCollapse>
</Flex>
</ScrollBox>
</Flex>
</>
) )
} }

View File

@ -18,33 +18,7 @@ const NewFilament = ({ onOk }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={true} required={true}
labelWidth={120}
objectData={objectData} objectData={objectData}
visibleProperties={{
cost: false,
costTaxRate: false,
costWithTax: false
}}
/>
)
},
{
title: 'Cost',
key: 'cost',
content: (
<ObjectInfo
type='filament'
column={1}
bordered={false}
isEditing={true}
required={true}
labelWidth={120}
objectData={objectData}
visibleProperties={{
cost: true,
costTaxRate: true,
costWithTax: true
}}
/> />
) )
}, },
@ -58,7 +32,6 @@ const NewFilament = ({ onOk }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={false} required={false}
labelWidth={90}
objectData={objectData} objectData={objectData}
/> />
) )
@ -77,7 +50,6 @@ const NewFilament = ({ onOk }) => {
createdAt: false, createdAt: false,
updatedAt: false updatedAt: false
}} }}
labelWidth={120}
isEditing={false} isEditing={false}
objectData={objectData} objectData={objectData}
/> />

View File

@ -38,7 +38,7 @@ const Files = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -68,15 +68,6 @@ const Files = () => {
type='file' type='file'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
</> </>

View File

@ -1,6 +1,6 @@
import { useContext, useRef, useState } from 'react' import { useContext, useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
import useCollapseState from '../../hooks/useCollapseState.jsx' import useCollapseState from '../../hooks/useCollapseState.jsx'
@ -13,8 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -26,9 +25,6 @@ import FilePreview from '../../common/FilePreview.jsx'
import MissingPlaceholder from '../../common/MissingPlaceholder.jsx' import MissingPlaceholder from '../../common/MissingPlaceholder.jsx'
import { ApiServerContext } from '../../context/ApiServerContext.jsx' import { ApiServerContext } from '../../context/ApiServerContext.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import JsonObjectIcon from '../../../Icons/JsonObjectIcon.jsx'
import ObjectProperty from '../../common/ObjectProperty.jsx'
import { getModelProperty } from '../../../../database/ObjectModels.js'
const log = loglevel.getLogger('FileInfo') const log = loglevel.getLogger('FileInfo')
log.setLevel(config.logLevel) log.setLevel(config.logLevel)
@ -41,7 +37,7 @@ const FileInfo = () => {
const [collapseState, updateCollapseState] = useCollapseState('FileInfo', { const [collapseState, updateCollapseState] = useCollapseState('FileInfo', {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
}) })
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
isEditing: false, isEditing: false,
@ -86,7 +82,7 @@ const FileInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='file' type='file'
@ -99,7 +95,6 @@ const FileInfo = () => {
items={[ items={[
{ key: 'info', label: 'File Information' }, { key: 'info', label: 'File Information' },
{ key: 'preview', label: 'Preview' }, { key: 'preview', label: 'Preview' },
{ key: 'metaData', label: 'Meta Data' },
{ key: 'notes', label: 'Notes' }, { key: 'notes', label: 'Notes' },
{ key: 'auditLogs', label: 'Audit Logs' } { key: 'auditLogs', label: 'Audit Logs' }
]} ]}
@ -117,10 +112,7 @@ const FileInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -136,17 +128,9 @@ const FileInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={fileId}
objectType='file'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -168,7 +152,6 @@ const FileInfo = () => {
type='file' type='file'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -178,8 +161,6 @@ const FileInfo = () => {
loading={loading} loading={loading}
isEditing={isEditing} isEditing={isEditing}
type='file' type='file'
labelWidth={170}
visibleProperties={{ metaData: false }}
objectData={objectData} objectData={objectData}
/> />
)} )}
@ -204,24 +185,6 @@ const FileInfo = () => {
<MissingPlaceholder message={'No file.'} /> <MissingPlaceholder message={'No file.'} />
)} )}
</InfoCollapse> </InfoCollapse>
<InfoCollapse
title='Meta Data'
icon={<JsonObjectIcon />}
active={collapseState.metaData}
onToggle={(expanded) => updateCollapseState('metaData', expanded)}
collapseKey='metaData'
>
{objectFormState?.objectData?._id ? (
<Card>
<ObjectProperty
{...getModelProperty('file', 'metaData')}
objectData={objectFormState?.objectData}
/>
</Card>
) : (
<MissingPlaceholder message={'No file meta data.'} />
)}
</InfoCollapse>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}

View File

@ -54,7 +54,7 @@ const Hosts = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space> <Space>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -85,15 +85,6 @@ const Hosts = () => {
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -14,13 +14,12 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
import HostOTP from './HostOtp.jsx'
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx' import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import PrinterIcon from '../../../Icons/PrinterIcon.jsx' import PrinterIcon from '../../../Icons/PrinterIcon.jsx'
@ -34,33 +33,30 @@ const HostInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const { setOnModalOk } = useActions()
useEffect(() => {
setOnModalOk(() => () => {
objectFormRef.current?.handleFetchObject?.()
})
return () => setOnModalOk(null)
}, [setOnModalOk])
const hostId = new URLSearchParams(location.search).get('hostId') const hostId = new URLSearchParams(location.search).get('hostId')
const [collapseState, updateCollapseState] = useCollapseState('HostInfo', { const [collapseState, updateCollapseState] = useCollapseState('HostInfo', {
info: true, info: true,
printers: true, printers: true,
documentPrinters: true, documentPrinters: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
}) })
const [hostOTPOpen, setHostOTPOpen] = useState(false)
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
formValid: false, formValid: false,
activities: [], locked: false,
loading: false, loading: false,
objectData: {} objectData: {}
}) })
const actions = { const actions = {
hostOTP: () => {
setHostOTPOpen(true)
return false
},
edit: () => { edit: () => {
objectFormRef?.current.startEditing() objectFormRef?.current.startEditing()
return false return false
@ -80,6 +76,7 @@ const HostInfo = () => {
} }
return ( return (
<>
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
@ -89,7 +86,7 @@ const HostInfo = () => {
}} }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='host' type='host'
@ -120,10 +117,7 @@ const HostInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -139,17 +133,9 @@ const HostInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={hostId}
objectType='host'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
@ -172,7 +158,6 @@ const HostInfo = () => {
type='host' type='host'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -185,7 +170,6 @@ const HostInfo = () => {
isEditing={isEditing} isEditing={isEditing}
type='host' type='host'
objectData={objectData} objectData={objectData}
labelWidth='175px'
/> />
) )
}} }}
@ -270,6 +254,20 @@ const HostInfo = () => {
</Flex> </Flex>
</ScrollBox> </ScrollBox>
</Flex> </Flex>
<Modal
open={hostOTPOpen}
destroyOnHidden={true}
width={650}
onCancel={() => {
actionHandlerRef.current.clearAction()
setHostOTPOpen(false)
}}
footer={false}
>
<HostOTP id={hostId} />
</Modal>
</>
) )
} }

View File

@ -52,7 +52,7 @@ const Materials = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space> <Space>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -83,15 +83,6 @@ const Materials = () => {
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config' import config from '../../../../config'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
@ -13,8 +13,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -31,14 +30,11 @@ const MaterialInfo = () => {
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const materialId = new URLSearchParams(location.search).get('materialId') const materialId = new URLSearchParams(location.search).get('materialId')
const [collapseState, updateCollapseState] = useCollapseState( const [collapseState, updateCollapseState] = useCollapseState('MaterialInfo', {
'MaterialInfo', info: true,
{ notes: true,
info: true, auditLogs: true
notes: true, })
auditLogs: false
}
)
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
isEditing: false, isEditing: false,
editLoading: false, editLoading: false,
@ -75,7 +71,7 @@ const MaterialInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='material' type='material'
@ -104,10 +100,7 @@ const MaterialInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -123,17 +116,9 @@ const MaterialInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={materialId}
objectType='material'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -155,7 +140,6 @@ const MaterialInfo = () => {
type='material' type='material'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -18,7 +18,6 @@ const NewMaterial = ({ onOk }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={true} required={true}
labelWidth={70}
objectData={objectData} objectData={objectData}
/> />
) )
@ -33,7 +32,6 @@ const NewMaterial = ({ onOk }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={false} required={false}
labelWidth={62}
objectData={objectData} objectData={objectData}
/> />
) )
@ -53,7 +51,6 @@ const NewMaterial = ({ onOk }) => {
updatedAt: false updatedAt: false
}} }}
isEditing={false} isEditing={false}
labelWidth={70}
objectData={objectData} objectData={objectData}
/> />
) )

View File

@ -50,7 +50,7 @@ const NoteTypes = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -80,15 +80,6 @@ const NoteTypes = () => {
type='noteType' type='noteType'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -23,7 +23,6 @@ const NewNoteType = ({ onOk }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={true} required={true}
labelWidth={72}
objectData={objectData} objectData={objectData}
/> />
) )
@ -39,7 +38,6 @@ const NewNoteType = ({ onOk }) => {
isEditing={true} isEditing={true}
required={false} required={false}
objectData={objectData} objectData={objectData}
labelWidth={65}
/> />
) )
}, },
@ -59,7 +57,6 @@ const NewNoteType = ({ onOk }) => {
}} }}
isEditing={false} isEditing={false}
objectData={objectData} objectData={objectData}
labelWidth={70}
/> />
) )
} }

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Flex, Space } from 'antd' import { Space, Flex } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -10,8 +10,7 @@ import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -29,7 +28,7 @@ const NoteTypeInfo = () => {
'NoteTypeInfo', 'NoteTypeInfo',
{ {
info: true, info: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -64,7 +63,7 @@ const NoteTypeInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='noteType' type='noteType'
@ -92,10 +91,7 @@ const NoteTypeInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -111,17 +107,9 @@ const NoteTypeInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={noteTypeId}
objectType='noteType'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -143,7 +131,6 @@ const NoteTypeInfo = () => {
type='noteType' type='noteType'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import { LoadingOutlined } from '@ant-design/icons' import { LoadingOutlined } from '@ant-design/icons'
import loglevel from 'loglevel' import loglevel from 'loglevel'
import config from '../../../../config.js' import config from '../../../../config.js'
@ -16,8 +16,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm.jsx' import ObjectForm from '../../common/ObjectForm.jsx'
import EditButtons from '../../common/EditButtons.jsx' import EditButtons from '../../common/EditButtons.jsx'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -39,7 +38,7 @@ const NoteInfo = () => {
info: true, info: true,
content: true, content: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
}) })
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
isEditing: false, isEditing: false,
@ -77,7 +76,7 @@ const NoteInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='note' type='note'
@ -107,10 +106,7 @@ const NoteInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -126,17 +122,9 @@ const NoteInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={noteId}
objectType='note'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -151,7 +139,6 @@ const NoteInfo = () => {
type='note' type='note'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -52,7 +52,7 @@ const PartSkus = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -83,15 +83,6 @@ const PartSkus = () => {
type='partSku' type='partSku'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -8,8 +8,7 @@ import ObjectInfo from '../../common/ObjectInfo'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx' import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
@ -29,7 +28,7 @@ const PartSkuInfo = () => {
const [collapseState, updateCollapseState] = useCollapseState('PartSkuInfo', { const [collapseState, updateCollapseState] = useCollapseState('PartSkuInfo', {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
}) })
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
isEditing: false, isEditing: false,
@ -67,7 +66,7 @@ const PartSkuInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='partSku' type='partSku'
@ -96,10 +95,7 @@ const PartSkuInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -115,17 +111,9 @@ const PartSkuInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={partSkuId}
objectType='partSku'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -147,7 +135,6 @@ const PartSkuInfo = () => {
type='partSku' type='partSku'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -54,7 +54,7 @@ const Parts = (filter) => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -85,15 +85,6 @@ const Parts = (filter) => {
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
filter={filter} filter={filter}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -26,7 +26,6 @@ const NewPart = ({ onOk, defaultValues }) => {
isEditing={true} isEditing={true}
required={true} required={true}
objectData={objectData} objectData={objectData}
labelWidth={70}
visibleProperties={{ visibleProperties={{
file: false, file: false,
priceMode: false, priceMode: false,
@ -52,7 +51,6 @@ const NewPart = ({ onOk, defaultValues }) => {
isEditing={true} isEditing={true}
required={true} required={true}
objectData={objectData} objectData={objectData}
labelWidth={120}
visibleProperties={{ visibleProperties={{
priceMode: true, priceMode: true,
margin: true, margin: true,
@ -76,7 +74,6 @@ const NewPart = ({ onOk, defaultValues }) => {
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={false} required={false}
labelWidth={50}
objectData={objectData} objectData={objectData}
/> />
) )

View File

@ -1,6 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card, Modal } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -8,13 +8,11 @@ import ObjectInfo from '../../common/ObjectInfo'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx' import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import { useActions } from '../../context/ActionsContext'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx' import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
@ -22,27 +20,20 @@ import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
import UserNotifierToggle from '../../common/UserNotifierToggle.jsx' import UserNotifierToggle from '../../common/UserNotifierToggle.jsx'
import ScrollBox from '../../common/ScrollBox.jsx' import ScrollBox from '../../common/ScrollBox.jsx'
import PartSkuIcon from '../../../Icons/PartSkuIcon.jsx' import PartSkuIcon from '../../../Icons/PartSkuIcon.jsx'
import NewPartSku from '../PartSkus/NewPartSku'
const PartInfo = () => { const PartInfo = () => {
const location = useLocation() const location = useLocation()
const objectFormRef = useRef(null) const objectFormRef = useRef(null)
const actionHandlerRef = useRef(null) const actionHandlerRef = useRef(null)
const partId = new URLSearchParams(location.search).get('partId') const partId = new URLSearchParams(location.search).get('partId')
const [newPartSkuOpen, setNewPartSkuOpen] = useState(false)
const partSkusTableRef = useRef() const partSkusTableRef = useRef()
const { setOnModalOk } = useActions()
useEffect(() => {
setOnModalOk(() => () => {
partSkusTableRef.current?.reload?.()
})
return () => setOnModalOk(null)
}, [setOnModalOk])
const [collapseState, updateCollapseState] = useCollapseState('PartInfo', { const [collapseState, updateCollapseState] = useCollapseState('PartInfo', {
info: true, info: true,
partSkus: true, partSkus: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
}) })
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
isEditing: false, isEditing: false,
@ -54,6 +45,10 @@ const PartInfo = () => {
}) })
const actions = { const actions = {
newPartSku: () => {
setNewPartSkuOpen(true)
return true
},
edit: () => { edit: () => {
objectFormRef?.current?.startEditing?.() objectFormRef?.current?.startEditing?.()
return false return false
@ -69,13 +64,14 @@ const PartInfo = () => {
} }
return ( return (
<>
<Flex <Flex
gap='large' gap='large'
vertical='true' vertical='true'
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='part' type='part'
@ -105,10 +101,7 @@ const PartInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -124,17 +117,9 @@ const PartInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={partId}
objectType='part'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -149,7 +134,6 @@ const PartInfo = () => {
type='part' type='part'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}
@ -194,6 +178,25 @@ const PartInfo = () => {
)} )}
</InfoCollapse> </InfoCollapse>
</ActionHandler> </ActionHandler>
<Modal
open={newPartSkuOpen}
styles={{ content: { paddingBottom: '24px' } }}
footer={null}
width={700}
onCancel={() => setNewPartSkuOpen(false)}
destroyOnClose
>
<NewPartSku
onOk={() => {
setNewPartSkuOpen(false)
partSkusTableRef.current?.reload?.()
}}
reset={newPartSkuOpen}
defaultValues={{
part: objectFormState?.objectData || undefined
}}
/>
</Modal>
<InfoCollapse <InfoCollapse
title='Notes' title='Notes'
icon={<NoteIcon />} icon={<NoteIcon />}
@ -227,6 +230,7 @@ const PartInfo = () => {
</Flex> </Flex>
</ScrollBox> </ScrollBox>
</Flex> </Flex>
</>
) )
} }

View File

@ -52,7 +52,7 @@ const ProductCategories = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space> <Space>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -83,15 +83,6 @@ const ProductCategories = () => {
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
visibleColumns={columnVisibility} visibleColumns={columnVisibility}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
<Modal <Modal

View File

@ -19,7 +19,6 @@ const NewProductCategory = ({ onOk }) => {
isEditing={true} isEditing={true}
required={true} required={true}
objectData={objectData} objectData={objectData}
labelWidth={70}
/> />
) )
}, },
@ -39,7 +38,6 @@ const NewProductCategory = ({ onOk }) => {
}} }}
isEditing={false} isEditing={false}
objectData={objectData} objectData={objectData}
labelWidth={70}
/> />
) )
} }

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -11,8 +11,7 @@ import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import ActionHandler from '../../common/ActionHandler.jsx' import ActionHandler from '../../common/ActionHandler.jsx'
import ObjectActions from '../../common/ObjectActions.jsx' import ObjectActions from '../../common/ObjectActions.jsx'
import ObjectTable from '../../common/ObjectTable.jsx' import ObjectTable from '../../common/ObjectTable.jsx'
@ -33,7 +32,7 @@ const ProductCategoryInfo = () => {
{ {
info: true, info: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -72,7 +71,7 @@ const ProductCategoryInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='productCategory' type='productCategory'
@ -101,10 +100,7 @@ const ProductCategoryInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -120,17 +116,9 @@ const ProductCategoryInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={productCategoryId}
objectType='productCategory'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -152,7 +140,6 @@ const ProductCategoryInfo = () => {
type='productCategory' type='productCategory'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

View File

@ -53,7 +53,7 @@ const ProductSkus = () => {
return ( return (
<> <>
<Flex vertical={'true'} gap='large' className='h-100'> <Flex vertical={'true'} gap='large' className='h-100'>
<Flex justify={'space-between'} style={{ minHeight: 0 }}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='small'>
<Dropdown menu={actionItems}> <Dropdown menu={actionItems}>
<Button>Actions</Button> <Button>Actions</Button>
@ -84,15 +84,6 @@ const ProductSkus = () => {
type='productSku' type='productSku'
cards={viewMode === 'cards'} cards={viewMode === 'cards'}
showFilterSidebar={showFilterSidebar} showFilterSidebar={showFilterSidebar}
expandHeight={true}
saveFilterInSession={true}
saveFilterInUrl={true}
useFilterInSession={true}
useFilterInUrl={true}
saveSortInSession={true}
saveSortInUrl={true}
useSortInSession={true}
useSortInUrl={true}
/> />
</Flex> </Flex>
<Modal <Modal

View File

@ -23,7 +23,7 @@ const NewProductSku = ({ onOk, reset, defaultValues }) => {
<ObjectInfo <ObjectInfo
type='productSku' type='productSku'
column={1} column={1}
labelWidth={80} labelWidth={70}
bordered={false} bordered={false}
isEditing={true} isEditing={true}
required={true} required={true}

View File

@ -1,6 +1,6 @@
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation } from 'react-router-dom'
import { Card, Flex, Space } from 'antd' import { Space, Flex, Card } from 'antd'
import useCollapseState from '../../hooks/useCollapseState' import useCollapseState from '../../hooks/useCollapseState'
import NotesPanel from '../../common/NotesPanel' import NotesPanel from '../../common/NotesPanel'
import InfoCollapse from '../../common/InfoCollapse' import InfoCollapse from '../../common/InfoCollapse'
@ -8,8 +8,7 @@ import ObjectInfo from '../../common/ObjectInfo'
import ViewButton from '../../common/ViewButton' import ViewButton from '../../common/ViewButton'
import ObjectForm from '../../common/ObjectForm' import ObjectForm from '../../common/ObjectForm'
import EditButtons from '../../common/EditButtons' import EditButtons from '../../common/EditButtons'
import ObjectTableNavigationButtons from '../../common/ObjectTableNavigationButtons.jsx' import LockIndicator from '../../common/LockIndicator.jsx'
import ActivityIndicator from '../../common/ActivityIndicator.jsx'
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx' import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
import NoteIcon from '../../../Icons/NoteIcon.jsx' import NoteIcon from '../../../Icons/NoteIcon.jsx'
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx' import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
@ -35,7 +34,7 @@ const ProductSkuInfo = () => {
info: true, info: true,
parts: true, parts: true,
notes: true, notes: true,
auditLogs: false auditLogs: true
} }
) )
const [objectFormState, setEditFormState] = useState({ const [objectFormState, setEditFormState] = useState({
@ -74,7 +73,7 @@ const ProductSkuInfo = () => {
style={{ maxHeight: '100%', minHeight: 0 }} style={{ maxHeight: '100%', minHeight: 0 }}
> >
<Flex justify={'space-between'}> <Flex justify={'space-between'}>
<Space size='small'> <Space size='middle'>
<Space size='small'> <Space size='small'>
<ObjectActions <ObjectActions
type='productSku' type='productSku'
@ -104,10 +103,7 @@ const ProductSkuInfo = () => {
disabled={objectFormState.loading} disabled={objectFormState.loading}
/> />
</Space> </Space>
<ActivityIndicator <LockIndicator lock={objectFormState.lock} />
activities={objectFormState.activities}
showStartingDivider={true}
/>
</Space> </Space>
<Space> <Space>
<EditButtons <EditButtons
@ -123,17 +119,9 @@ const ProductSkuInfo = () => {
}} }}
editLoading={objectFormState.editLoading} editLoading={objectFormState.editLoading}
formValid={objectFormState.formValid} formValid={objectFormState.formValid}
disabled={ disabled={objectFormState.lock?.locked || objectFormState.loading}
objectFormState.beingEditedByOther || objectFormState.loading
}
loading={objectFormState.editLoading} loading={objectFormState.editLoading}
/> />
<ObjectTableNavigationButtons
disabled={objectFormState.loading || objectFormState.isEditing}
_id={productSkuId}
objectType='productSku'
showEndingDivider={true}
/>
</Space> </Space>
</Flex> </Flex>
<ScrollBox> <ScrollBox>
@ -148,7 +136,6 @@ const ProductSkuInfo = () => {
type='productSku' type='productSku'
style={{ height: '100%' }} style={{ height: '100%' }}
ref={objectFormRef} ref={objectFormRef}
setCurrentObject={true}
onStateChange={(state) => { onStateChange={(state) => {
setEditFormState((prev) => ({ ...prev, ...state })) setEditFormState((prev) => ({ ...prev, ...state }))
}} }}

Some files were not shown because too many files have changed in this diff Show More