Compare commits
No commits in common. "12a4d46da88e9bb9f47207883df5da2e528e3550" and "8bbfe20ec494b7e265fb8b41c56dd3785cc00f10" have entirely different histories.
12a4d46da8
...
8bbfe20ec4
@ -1,21 +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(1,0,0,1,12.4182,0)">
|
||||
<g transform="matrix(0.83795,0,0,0.83795,-2.8271,-3.06585)">
|
||||
<path d="M53.485,22.46L53.485,69.739C53.485,76.482 49.963,80.036 43.319,80.036L10.16,80.036C3.517,80.036 0,76.482 0,69.739L0,22.46C0,15.717 3.517,12.164 10.16,12.164L10.52,12.164C10.45,12.571 10.417,12.998 10.417,13.44L10.417,16.721C10.417,17.219 10.46,17.699 10.543,18.157L10.427,18.157C7.509,18.157 5.993,19.749 5.993,22.523L5.993,69.677C5.993,72.476 7.509,74.043 10.427,74.043L43.058,74.043C45.971,74.043 47.492,72.476 47.492,69.677L47.492,22.523C47.492,19.749 45.971,18.157 43.058,18.157L42.937,18.157C43.02,17.699 43.063,17.219 43.063,16.721L43.063,13.44C43.063,12.998 43.029,12.571 42.959,12.164L43.319,12.164C49.963,12.164 53.485,15.717 53.485,22.46Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.83795,0,0,0.83795,-2.8271,-3.06585)">
|
||||
<path d="M17.109,19.927L36.371,19.927C38.251,19.927 39.384,18.726 39.384,16.721L39.384,13.44C39.384,11.429 38.251,10.234 36.371,10.234L33.721,10.234C33.485,6.601 30.469,3.659 26.743,3.659C23.016,3.659 20,6.601 19.764,10.234L17.109,10.234C15.234,10.234 14.101,11.429 14.101,13.44L14.101,16.721C14.101,18.726 15.234,19.927 17.109,19.927ZM26.743,13.248C25.22,13.248 23.984,11.981 23.984,10.495C23.984,8.952 25.22,7.717 26.743,7.717C28.265,7.717 29.495,8.952 29.495,10.495C29.495,11.981 28.265,13.248 26.743,13.248Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.83795,0,0,0.83795,-2.8271,-3.06585)">
|
||||
<path d="M13.473,60.281L27.067,60.281C28.27,60.281 29.263,59.294 29.263,58.085C29.263,56.882 28.301,55.9 27.067,55.9L13.473,55.9C12.244,55.9 11.251,56.882 11.251,58.085C11.251,59.294 12.27,60.281 13.473,60.281Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.83795,0,0,0.83795,-2.8271,-3.06585)">
|
||||
<path d="M13.473,48.622L40.018,48.622C41.252,48.622 42.234,47.64 42.234,46.406C42.234,45.197 41.246,44.241 40.018,44.241L13.473,44.241C12.244,44.241 11.251,45.197 11.251,46.406C11.251,47.64 12.233,48.622 13.473,48.622Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(0.83795,0,0,0.83795,-2.8271,-3.06585)">
|
||||
<path d="M13.473,37.562L40.018,37.562C41.221,37.562 42.234,36.569 42.234,35.366C42.234,34.157 41.221,33.144 40.018,33.144L13.473,33.144C12.27,33.144 11.251,34.157 11.251,35.366C11.251,36.569 12.27,37.562 13.473,37.562Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB |
@ -1,14 +1,13 @@
|
||||
<?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.811652,0,0,0.811652,5.66772,1.86878)">
|
||||
<g transform="matrix(0.75929,0,0,0.75929,7.36648,3.81256)">
|
||||
<g transform="matrix(1.37054,0,0,1.37054,-11.3557,-4.11161)">
|
||||
<path d="M51.032,42.519C50.944,42.707 50.834,42.883 50.707,43.046C49.946,44.027 50.123,45.442 51.104,46.203C52.085,46.965 53.499,46.787 54.261,45.807C54.595,45.377 54.88,44.914 55.111,44.42C55.635,43.294 55.147,41.954 54.021,41.43C52.896,40.905 51.556,41.394 51.032,42.519ZM51.266,35.661L51.266,36.786C51.267,38.028 52.276,39.035 53.517,39.035C54.759,39.034 55.767,38.025 55.766,36.784L55.766,35.659C55.765,34.417 54.756,33.409 53.514,33.41C52.273,33.41 51.265,34.419 51.266,35.661ZM51.261,27.786C51.262,28.131 51.262,28.508 51.262,28.911C51.263,30.153 52.271,31.16 53.513,31.16C54.755,31.159 55.763,30.15 55.762,28.909C55.762,28.506 55.762,28.128 55.761,27.784C55.761,26.542 54.752,25.534 53.51,25.535C52.268,25.535 51.261,26.544 51.261,27.786ZM50.859,20.789C50.948,21.015 51.014,21.246 51.064,21.496C51.311,22.713 52.5,23.5 53.717,23.253C54.934,23.006 55.721,21.817 55.474,20.6C55.37,20.087 55.232,19.614 55.05,19.15C54.598,17.993 53.292,17.422 52.135,17.874C50.979,18.326 50.407,19.632 50.859,20.789ZM46.568,15.31C46.85,15.603 47.114,15.879 47.347,16.122C48.207,17.018 49.633,17.047 50.529,16.187C51.425,15.327 51.454,13.901 50.594,13.005C50.36,12.762 50.096,12.487 49.815,12.194C48.955,11.298 47.529,11.269 46.633,12.129C45.737,12.989 45.708,14.414 46.568,15.31ZM41.132,9.633C41.392,9.901 41.644,10.166 41.886,10.422C42.738,11.325 44.163,11.366 45.066,10.514C45.969,9.662 46.01,8.236 45.158,7.333C44.901,7.062 44.634,6.78 44.358,6.496C43.492,5.605 42.066,5.586 41.176,6.451C40.286,7.317 40.266,8.743 41.132,9.633ZM24.106,8.619C24.162,8.422 24.241,8.231 24.34,8.049C24.938,6.96 24.539,5.591 23.45,4.994C22.361,4.397 20.992,4.796 20.395,5.885C20.131,6.365 19.924,6.873 19.777,7.392C19.438,8.587 20.133,9.832 21.328,10.17C22.523,10.509 23.768,9.813 24.106,8.619ZM36.899,2.219L36.059,2.219C34.817,2.219 33.809,3.227 33.809,4.469C33.809,5.711 34.817,6.719 36.059,6.719L36.899,6.719C36.935,6.719 36.97,6.721 37.006,6.723C38.244,6.822 39.328,5.896 39.426,4.658C39.524,3.42 38.599,2.336 37.361,2.238C37.207,2.225 37.053,2.219 36.899,2.219ZM28.184,6.719L29.309,6.719C30.55,6.719 31.559,5.711 31.559,4.469C31.559,3.227 30.55,2.219 29.309,2.219L28.184,2.219C26.942,2.219 25.934,3.227 25.934,4.469C25.934,5.711 26.942,6.719 28.184,6.719Z"/>
|
||||
<path d="M46.477,44.675L45.352,44.675C44.11,44.675 43.102,45.683 43.102,46.925C43.102,48.167 44.11,49.175 45.352,49.175L46.477,49.175C47.718,49.175 48.727,48.167 48.727,46.925C48.727,45.683 47.718,44.675 46.477,44.675ZM51.032,42.519C50.944,42.707 50.834,42.883 50.707,43.046C49.946,44.027 50.123,45.442 51.104,46.203C52.085,46.965 53.499,46.787 54.261,45.807C54.595,45.377 54.88,44.914 55.111,44.42C55.635,43.294 55.147,41.954 54.021,41.43C52.896,40.905 51.556,41.394 51.032,42.519ZM51.266,35.661C51.266,36.044 51.266,36.421 51.266,36.786C51.267,38.028 52.276,39.035 53.517,39.035C54.759,39.034 55.767,38.025 55.766,36.784C55.766,36.418 55.766,36.042 55.766,35.659C55.765,34.417 54.756,33.409 53.514,33.41C52.273,33.41 51.265,34.419 51.266,35.661ZM51.261,27.786C51.262,28.131 51.262,28.508 51.262,28.911C51.263,30.153 52.271,31.16 53.513,31.16C54.755,31.159 55.763,30.15 55.762,28.909C55.762,28.506 55.762,28.128 55.761,27.784C55.761,26.542 54.752,25.534 53.51,25.535C52.268,25.535 51.261,26.544 51.261,27.786ZM50.859,20.789C50.948,21.015 51.014,21.246 51.064,21.496C51.311,22.713 52.5,23.5 53.717,23.253C54.934,23.006 55.721,21.817 55.474,20.6C55.37,20.087 55.232,19.614 55.05,19.15C54.598,17.993 53.292,17.422 52.135,17.874C50.979,18.326 50.407,19.632 50.859,20.789ZM19.512,15.856L19.512,15.864C19.512,15.914 19.513,15.963 19.517,16.013L19.518,16.042L19.523,16.088L19.523,16.094L19.524,16.101C19.574,16.662 19.796,17.067 20.082,17.36C20.494,17.822 21.094,18.114 21.762,18.114C21.762,18.114 24.012,17.959 24.012,15.85L24.012,14.739C24.012,13.497 23.004,12.489 21.762,12.489C20.52,12.489 19.512,13.497 19.512,14.739L19.512,15.85L19.512,15.856ZM46.568,15.31C46.85,15.603 47.114,15.879 47.347,16.122C48.207,17.018 49.633,17.047 50.529,16.187C51.425,15.327 51.454,13.901 50.594,13.005C50.36,12.762 50.096,12.487 49.815,12.194C48.955,11.298 47.529,11.269 46.633,12.129C45.737,12.989 45.708,14.414 46.568,15.31ZM41.132,9.633C41.392,9.901 41.644,10.166 41.886,10.422C42.738,11.325 44.163,11.366 45.066,10.514C45.969,9.662 46.01,8.236 45.158,7.333C44.901,7.062 44.634,6.78 44.358,6.496C43.492,5.605 42.066,5.586 41.176,6.451C40.286,7.317 40.266,8.743 41.132,9.633ZM24.106,8.619C24.162,8.422 24.241,8.231 24.34,8.049C24.938,6.96 24.539,5.591 23.45,4.994C22.361,4.397 20.992,4.796 20.395,5.885C20.131,6.365 19.924,6.873 19.777,7.392C19.438,8.587 20.133,9.832 21.328,10.17C22.523,10.509 23.768,9.813 24.106,8.619ZM36.899,2.219L36.89,2.219L36.059,2.219C34.817,2.219 33.809,3.227 33.809,4.469C33.809,5.711 34.817,6.719 36.059,6.719L36.899,6.719C36.935,6.719 36.97,6.721 37.006,6.723C38.244,6.822 39.328,5.896 39.426,4.658C39.524,3.42 38.599,2.336 37.361,2.238C37.207,2.225 37.053,2.219 36.899,2.219L36.899,2.219ZM28.184,6.719L29.309,6.719C30.55,6.719 31.559,5.711 31.559,4.469C31.559,3.227 30.55,2.219 29.309,2.219L28.184,2.219C26.942,2.219 25.934,3.227 25.934,4.469C25.934,5.711 26.942,6.719 28.184,6.719Z"/>
|
||||
</g>
|
||||
<g transform="matrix(1.37054,0,0,1.37054,-11.3557,-4.11161)">
|
||||
<path d="M47.785,18.431L46.66,18.431C45.418,18.431 44.41,19.439 44.41,20.681C44.41,21.923 45.418,22.931 46.66,22.931L47.785,22.931C49.027,22.931 50.035,21.923 50.035,20.681C50.035,19.439 49.027,18.431 47.785,18.431ZM41.493,18.243C41.35,18.127 41.218,17.99 41.109,17.844C40.368,16.848 38.958,16.64 37.961,17.381C36.965,18.122 36.757,19.533 37.498,20.529C37.83,20.976 38.233,21.395 38.671,21.747C39.638,22.526 41.055,22.373 41.834,21.406C42.613,20.439 42.46,19.022 41.493,18.243ZM40.961,12.576L40.961,11.451C40.961,10.21 39.953,9.201 38.711,9.201C37.47,9.201 36.461,10.21 36.461,11.451L36.461,12.576C36.461,13.818 37.47,14.826 38.711,14.826C39.953,14.826 40.961,13.818 40.961,12.576Z"/>
|
||||
</g>
|
||||
<g transform="matrix(1.09263,0,0,1.09263,0.0174335,-6.97689)">
|
||||
<g transform="matrix(0.937843,0,0,0.937843,-0.188198,11.8804)">
|
||||
<path d="M10.149,67.641L43.438,67.641C50.137,67.641 53.586,64.135 53.586,57.41L53.586,29.058C53.586,24.717 53.028,22.725 50.308,19.954L33.894,3.284C31.282,0.616 29.111,0 25.212,0L10.149,0C3.481,0 0,3.532 0,10.257L0,57.41C0,64.161 3.455,67.641 10.149,67.641ZM10.637,61.519C7.621,61.519 6.122,59.941 6.122,57.029L6.122,10.637C6.122,7.752 7.621,6.122 10.663,6.122L23.984,6.122L23.984,23.261C23.984,27.733 26.167,29.895 30.619,29.895L47.464,29.895L47.464,57.029C47.464,59.941 45.965,61.519 42.929,61.519L10.637,61.519ZM31.198,24.496C29.903,24.496 29.384,23.945 29.384,22.656L29.384,6.973L46.613,24.496L31.198,24.496Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
@ -27,5 +26,4 @@
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.3 KiB |
@ -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 12 12" 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.156042,0,0,0.156042,1.80453,0.721021)">
|
||||
<rect x="0" y="0" width="53.774" height="67.661" style="fill-opacity:0;"/>
|
||||
<path d="M10.149,67.641L43.438,67.641C50.137,67.641 53.586,64.135 53.586,57.41L53.586,29.058C53.586,24.717 53.028,22.725 50.308,19.954L33.894,3.284C31.282,0.616 29.111,0 25.212,0L10.149,0C3.481,0 0,3.532 0,10.257L0,57.41C0,64.161 3.455,67.641 10.149,67.641ZM10.637,61.519C7.621,61.519 6.122,59.941 6.122,57.029L6.122,10.637C6.122,7.752 7.621,6.122 10.663,6.122L23.984,6.122L23.984,23.261C23.984,27.733 26.167,29.895 30.619,29.895L47.464,29.895L47.464,57.029C47.464,59.941 45.965,61.519 42.929,61.519L10.637,61.519ZM31.198,24.496C29.903,24.496 29.384,23.945 29.384,22.656L29.384,6.973L46.613,24.496L31.198,24.496Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1,16 +1,21 @@
|
||||
<?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(1,0,0,1,12.418,0)">
|
||||
<g transform="matrix(0.83795,0,0,0.83795,-2.8271,-3.0658)">
|
||||
<path d="M53.485,22.46L53.485,69.739C53.485,76.482 49.963,80.036 43.319,80.036L10.16,80.036C3.517,80.036 0,76.482 0,69.739L0,22.46C0,15.717 3.517,12.164 10.16,12.164L10.52,12.164C10.45,12.571 10.417,12.998 10.417,13.44L10.417,16.721C10.417,17.219 10.46,17.699 10.543,18.157L10.427,18.157C7.509,18.157 5.993,19.749 5.993,22.523L5.993,69.677C5.993,72.476 7.509,74.043 10.427,74.043L43.058,74.043C45.971,74.043 47.492,72.476 47.492,69.677L47.492,22.523C47.492,19.749 45.971,18.157 43.058,18.157L42.937,18.157C43.02,17.699 43.063,17.219 43.063,16.721L43.063,13.44C43.063,12.998 43.029,12.571 42.959,12.164L43.319,12.164C49.963,12.164 53.485,15.717 53.485,22.46Z" style="fill-rule:nonzero;"/>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>
|
||||
<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" version="1.1" viewBox="0 0 64 64" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(12.418)">
|
||||
<g transform="matrix(.83795 0 0 .83795 -2.8271 -3.0658)">
|
||||
<path d="m53.485 22.46v47.279c0 6.743-3.522 10.297-10.166 10.297h-33.159c-6.643 0-10.16-3.554-10.16-10.297v-47.279c0-6.743 3.517-10.296 10.16-10.296h0.36c-0.07 0.407-0.103 0.834-0.103 1.276v3.281c0 0.498 0.043 0.978 0.126 1.436h-0.116c-2.918 0-4.434 1.592-4.434 4.366v47.154c0 2.799 1.516 4.366 4.434 4.366h32.631c2.913 0 4.434-1.567 4.434-4.366v-47.154c0-2.774-1.521-4.366-4.434-4.366h-0.121c0.083-0.458 0.126-0.938 0.126-1.436v-3.281c0-0.442-0.034-0.869-0.104-1.276h0.36c6.644 0 10.166 3.553 10.166 10.296z" fill-rule="nonzero"/>
|
||||
</g>
|
||||
<g transform="matrix(0.83795,0,0,0.83795,-2.8271,-3.0658)">
|
||||
<path d="M17.109,19.927L36.371,19.927C38.251,19.927 39.384,18.726 39.384,16.721L39.384,13.44C39.384,11.429 38.251,10.234 36.371,10.234L33.721,10.234C33.485,6.601 30.469,3.659 26.743,3.659C23.016,3.659 20,6.601 19.764,10.234L17.109,10.234C15.234,10.234 14.101,11.429 14.101,13.44L14.101,16.721C14.101,18.726 15.234,19.927 17.109,19.927ZM26.743,13.248C25.22,13.248 23.984,11.981 23.984,10.495C23.984,8.952 25.22,7.717 26.743,7.717C28.265,7.717 29.495,8.952 29.495,10.495C29.495,11.981 28.265,13.248 26.743,13.248Z" style="fill-rule:nonzero;"/>
|
||||
<g transform="matrix(.83795 0 0 .83795 -2.8271 -3.0658)">
|
||||
<path d="m17.109 19.927h19.262c1.88 0 3.013-1.201 3.013-3.206v-3.281c0-2.011-1.133-3.206-3.013-3.206h-2.65c-0.236-3.633-3.252-6.575-6.978-6.575-3.727 0-6.743 2.942-6.979 6.575h-2.655c-1.875 0-3.008 1.195-3.008 3.206v3.281c0 2.005 1.133 3.206 3.008 3.206zm9.634-6.679c-1.523 0-2.759-1.267-2.759-2.753 0-1.543 1.236-2.778 2.759-2.778 1.522 0 2.752 1.235 2.752 2.778 0 1.486-1.23 2.753-2.752 2.753z" fill-rule="nonzero"/>
|
||||
</g>
|
||||
<g transform="matrix(0.411749,0,0,0.411749,6.00393,20.6414)">
|
||||
<rect x="0" y="0" width="65.953" height="73.445" style="fill-opacity:0;"/>
|
||||
<path d="M28.938,13.973L36.828,13.973L36.828,4.613L28.938,4.613L28.938,13.973ZM28.938,24.41L36.828,24.41L36.828,16.895L28.938,16.895L28.938,24.41ZM6.594,57.16L14.453,52.613L10.438,45.77L2.875,50.098L6.594,57.16ZM16.984,51.176L23.5,47.441L19.516,40.566L13.016,44.301L16.984,51.176ZM51.125,52.613L58.984,57.16L62.703,50.098L55.141,45.77L51.125,52.613ZM42.078,47.441L48.609,51.176L52.563,44.301L46.063,40.566L42.078,47.441ZM26.047,45.988L32.797,42.098L39.547,45.988L43.531,39.145L36.828,35.301L36.828,27.316L28.938,27.316L28.938,35.191L22.047,39.145L26.047,45.988ZM4.297,58.176L28.578,72.207C31.297,73.801 34.469,73.801 37.203,72.207L61.469,58.176C64.156,56.645 65.766,53.863 65.766,50.723L65.766,22.691C65.766,19.551 64.156,16.77 61.469,15.223L37.203,1.207C34.469,-0.402 31.297,-0.402 28.578,1.207L4.297,15.223C1.609,16.77 0,19.551 0,22.691L0,50.723C0,53.863 1.609,56.645 4.297,58.176ZM28.938,63.285C28.672,63.145 28.625,63.113 28.359,62.957L9.531,52.066C8.5,51.457 7.875,50.426 7.875,49.238L7.875,27.848L28.938,39.91L28.938,63.285ZM32.797,32.973L11.047,20.52C11.219,20.379 11.281,20.316 11.531,20.176L31.25,8.785C32.281,8.16 33.484,8.16 34.516,8.785L54.25,20.176C54.484,20.316 54.516,20.363 54.625,20.457L32.797,32.973ZM36.828,63.285L36.828,39.801L57.875,27.754L57.875,49.238C57.875,50.426 57.281,51.457 56.25,52.066L37.797,62.738C37.391,62.973 37.219,63.082 36.828,63.285Z" style="fill-rule:nonzero;"/>
|
||||
<g transform="matrix(.83795 0 0 .83795 -2.8271 -3.0658)">
|
||||
<path d="m13.473 60.281h13.594c1.203 0 2.196-0.987 2.196-2.196 0-1.203-0.962-2.185-2.196-2.185h-13.594c-1.229 0-2.222 0.982-2.222 2.185 0 1.209 1.019 2.196 2.222 2.196z" fill-rule="nonzero"/>
|
||||
</g>
|
||||
<g transform="matrix(.83795 0 0 .83795 -2.8271 -3.0658)">
|
||||
<path d="m13.473 48.622h26.545c1.234 0 2.216-0.982 2.216-2.216 0-1.209-0.988-2.165-2.216-2.165h-26.545c-1.229 0-2.222 0.956-2.222 2.165 0 1.234 0.982 2.216 2.222 2.216z" fill-rule="nonzero"/>
|
||||
</g>
|
||||
<g transform="matrix(.83795 0 0 .83795 -2.8271 -3.0658)">
|
||||
<path d="m13.473 37.562h26.545c1.203 0 2.216-0.993 2.216-2.196 0-1.209-1.013-2.222-2.216-2.222h-26.545c-1.203 0-2.222 1.013-2.222 2.222 0 1.203 1.019 2.196 2.222 2.196z" fill-rule="nonzero"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 2.3 KiB |
@ -251,15 +251,8 @@ body {
|
||||
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar:vertical {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar:horizontal {
|
||||
height: 8px;
|
||||
width: 10px;
|
||||
border-radius: 34px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
@ -270,17 +263,13 @@ body {
|
||||
/* Handle */
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #8888881a;
|
||||
border: 2px solid rgba(0, 0, 0, 0);
|
||||
border: 4px solid rgba(0, 0, 0, 0);
|
||||
background-clip: padding-box;
|
||||
transition: all 1s;
|
||||
-moz-transition: all 1s;
|
||||
-webkit-transition: all 1s;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
background: #00000000; /* The scroll corner color */
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:vertical {
|
||||
border-left: none;
|
||||
}
|
||||
@ -292,7 +281,7 @@ body {
|
||||
/* Handle on hover */
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #5555551f;
|
||||
border: 2px solid rgba(0, 0, 0, 0);
|
||||
border: 4px solid rgba(0, 0, 0, 0);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
@ -303,7 +292,3 @@ body {
|
||||
::-webkit-scrollbar-thumb:horizontal:hover {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.ant-table-body {
|
||||
scrollbar-color: auto;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,842 +0,0 @@
|
||||
import { useContext, useState, useEffect } from 'react'
|
||||
import {
|
||||
Descriptions,
|
||||
Button,
|
||||
Typography,
|
||||
Flex,
|
||||
Space,
|
||||
Dropdown,
|
||||
message,
|
||||
Tag,
|
||||
Input,
|
||||
InputNumber,
|
||||
Select
|
||||
} from 'antd'
|
||||
import ReloadIcon from '../../Icons/ReloadIcon.jsx'
|
||||
import CloudIcon from '../../Icons/CloudIcon.jsx'
|
||||
import { ApiServerContext } from '../context/ApiServerContext.jsx'
|
||||
import BoolDisplay from '../common/BoolDisplay.jsx'
|
||||
import InfoCollapse from '../common/InfoCollapse.jsx'
|
||||
|
||||
const { Text, Paragraph } = Typography
|
||||
|
||||
const ApiContextDebug = () => {
|
||||
const {
|
||||
apiServer,
|
||||
error,
|
||||
connecting,
|
||||
connected,
|
||||
fetchLoading,
|
||||
lockObject,
|
||||
unlockObject,
|
||||
fetchObjectLock,
|
||||
updateObject,
|
||||
createObject,
|
||||
deleteObject,
|
||||
subscribeToObjectUpdates,
|
||||
subscribeToObjectEvent,
|
||||
subscribeToObjectTypeUpdates,
|
||||
subscribeToObjectLock,
|
||||
fetchObject,
|
||||
fetchObjects,
|
||||
fetchObjectsByProperty,
|
||||
fetchSpotlightData,
|
||||
fetchObjectContent,
|
||||
fetchTemplatePreview,
|
||||
fetchNotes,
|
||||
fetchHostOTP,
|
||||
sendObjectAction
|
||||
} = useContext(ApiServerContext)
|
||||
|
||||
const [msgApi, contextHolder] = message.useMessage()
|
||||
const [connectionStatus, setConnectionStatus] = useState('disconnected')
|
||||
const [socketId, setSocketId] = useState(null)
|
||||
|
||||
// Test input states
|
||||
const [testInputs, setTestInputs] = useState({
|
||||
objectId: 'test-id',
|
||||
objectType: 'user',
|
||||
hostId: 'test-host-id',
|
||||
parentId: 'test-parent-id',
|
||||
fileName: 'test.gcode',
|
||||
query: 'test query',
|
||||
action: 'start',
|
||||
eventType: 'status',
|
||||
properties: ['name', 'email'],
|
||||
filter: { active: true },
|
||||
scale: 1.0,
|
||||
templateContent: 'Test template content',
|
||||
testObject: { name: 'Test Object' }
|
||||
})
|
||||
|
||||
// Collapse states
|
||||
const [collapseStates, setCollapseStates] = useState({
|
||||
fetchTests: false,
|
||||
crudTests: false,
|
||||
subscriptionTests: false,
|
||||
specialTests: false
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (apiServer) {
|
||||
setConnectionStatus(apiServer.connected ? 'connected' : 'disconnected')
|
||||
setSocketId(apiServer.id)
|
||||
|
||||
// Listen for connection status changes
|
||||
const handleConnect = () => {
|
||||
setConnectionStatus('connected')
|
||||
setSocketId(apiServer.id)
|
||||
}
|
||||
|
||||
const handleDisconnect = () => {
|
||||
setConnectionStatus('disconnected')
|
||||
setSocketId(null)
|
||||
}
|
||||
|
||||
apiServer.on('connect', handleConnect)
|
||||
apiServer.on('disconnect', handleDisconnect)
|
||||
|
||||
return () => {
|
||||
apiServer.off('connect', handleConnect)
|
||||
apiServer.off('disconnect', handleDisconnect)
|
||||
}
|
||||
} else {
|
||||
setConnectionStatus('disconnected')
|
||||
setSocketId(null)
|
||||
}
|
||||
}, [apiServer])
|
||||
|
||||
// Helper functions
|
||||
const updateTestInput = (key, value) => {
|
||||
setTestInputs((prev) => ({ ...prev, [key]: value }))
|
||||
}
|
||||
|
||||
const toggleCollapse = (key) => {
|
||||
setCollapseStates((prev) => ({ ...prev, [key]: !prev[key] }))
|
||||
}
|
||||
|
||||
const handleReconnect = () => {
|
||||
if (apiServer) {
|
||||
apiServer.connect()
|
||||
msgApi.info('Attempting to reconnect...')
|
||||
} else {
|
||||
msgApi.warning('No API server instance available')
|
||||
}
|
||||
}
|
||||
|
||||
const handleDisconnect = () => {
|
||||
if (apiServer) {
|
||||
apiServer.disconnect()
|
||||
msgApi.info('Disconnected from API server')
|
||||
}
|
||||
}
|
||||
|
||||
const testFetchObject = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing fetchObject...', 0)
|
||||
const result = await fetchObject(
|
||||
testInputs.objectId,
|
||||
testInputs.objectType
|
||||
)
|
||||
msgApi.destroy()
|
||||
msgApi.success('fetchObject test completed')
|
||||
console.log('fetchObject result:', result)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('fetchObject test failed')
|
||||
console.error('fetchObject error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testFetchObjects = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing fetchObjects...', 0)
|
||||
const result = await fetchObjects(testInputs.objectType, {
|
||||
page: 1,
|
||||
limit: 5
|
||||
})
|
||||
msgApi.destroy()
|
||||
msgApi.success('fetchObjects test completed')
|
||||
console.log('fetchObjects result:', result)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('fetchObjects test failed')
|
||||
console.error('fetchObjects error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testLockObject = () => {
|
||||
try {
|
||||
lockObject(testInputs.objectId, testInputs.objectType)
|
||||
msgApi.success('Lock command sent')
|
||||
} catch (err) {
|
||||
msgApi.error('Lock command failed')
|
||||
console.error('Lock error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testUnlockObject = () => {
|
||||
try {
|
||||
unlockObject(testInputs.objectId, testInputs.objectType)
|
||||
msgApi.success('Unlock command sent')
|
||||
} catch (err) {
|
||||
msgApi.error('Unlock command failed')
|
||||
console.error('Unlock error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testFetchObjectLock = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing fetchObjectLock...', 0)
|
||||
const result = await fetchObjectLock(
|
||||
testInputs.objectId,
|
||||
testInputs.objectType
|
||||
)
|
||||
msgApi.destroy()
|
||||
msgApi.success('fetchObjectLock test completed')
|
||||
console.log('fetchObjectLock result:', result)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('fetchObjectLock test failed')
|
||||
console.error('fetchObjectLock error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testUpdateObject = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing updateObject...', 0)
|
||||
const testData = {
|
||||
name: 'Test Update',
|
||||
updated: new Date().toISOString()
|
||||
}
|
||||
const result = await updateObject(
|
||||
testInputs.objectId,
|
||||
testInputs.objectType,
|
||||
testData
|
||||
)
|
||||
msgApi.destroy()
|
||||
msgApi.success('updateObject test completed')
|
||||
console.log('updateObject result:', result)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('updateObject test failed')
|
||||
console.error('updateObject error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testCreateObject = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing createObject...', 0)
|
||||
const testData = {
|
||||
name: 'Test Create',
|
||||
created: new Date().toISOString()
|
||||
}
|
||||
const result = await createObject(testInputs.objectType, testData)
|
||||
msgApi.destroy()
|
||||
msgApi.success('createObject test completed')
|
||||
console.log('createObject result:', result)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('createObject test failed')
|
||||
console.error('createObject error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testDeleteObject = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing deleteObject...', 0)
|
||||
const result = await deleteObject(
|
||||
testInputs.objectId,
|
||||
testInputs.objectType
|
||||
)
|
||||
msgApi.destroy()
|
||||
msgApi.success('deleteObject test completed')
|
||||
console.log('deleteObject result:', result)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('deleteObject test failed')
|
||||
console.error('deleteObject error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testFetchObjectsByProperty = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing fetchObjectsByProperty...', 0)
|
||||
const params = {
|
||||
properties: testInputs.properties,
|
||||
filter: testInputs.filter,
|
||||
masterFilter: {}
|
||||
}
|
||||
const result = await fetchObjectsByProperty(testInputs.objectType, params)
|
||||
msgApi.destroy()
|
||||
msgApi.success('fetchObjectsByProperty test completed')
|
||||
console.log('fetchObjectsByProperty result:', result)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('fetchObjectsByProperty test failed')
|
||||
console.error('fetchObjectsByProperty error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testFetchSpotlightData = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing fetchSpotlightData...', 0)
|
||||
const result = await fetchSpotlightData(testInputs.query)
|
||||
msgApi.destroy()
|
||||
msgApi.success('fetchSpotlightData test completed')
|
||||
console.log('fetchSpotlightData result:', result)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('fetchSpotlightData test failed')
|
||||
console.error('fetchSpotlightData error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testFetchObjectContent = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing fetchObjectContent...', 0)
|
||||
await fetchObjectContent(
|
||||
testInputs.objectId,
|
||||
'gcodefile',
|
||||
testInputs.fileName
|
||||
)
|
||||
msgApi.destroy()
|
||||
msgApi.success('fetchObjectContent test completed')
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('fetchObjectContent test failed')
|
||||
console.error('fetchObjectContent error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testFetchTemplatePreview = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing fetchTemplatePreview...', 0)
|
||||
|
||||
fetchTemplatePreview(
|
||||
testInputs.objectId,
|
||||
testInputs.templateContent,
|
||||
testInputs.testObject,
|
||||
testInputs.scale,
|
||||
(result) => {
|
||||
msgApi.destroy()
|
||||
if (result.success) {
|
||||
msgApi.success('fetchTemplatePreview test completed')
|
||||
} else {
|
||||
msgApi.error('fetchTemplatePreview test failed')
|
||||
}
|
||||
console.log('fetchTemplatePreview result:', result)
|
||||
}
|
||||
)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('fetchTemplatePreview test failed')
|
||||
console.error('fetchTemplatePreview error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testFetchNotes = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing fetchNotes...', 0)
|
||||
const result = await fetchNotes(testInputs.parentId)
|
||||
msgApi.destroy()
|
||||
msgApi.success('fetchNotes test completed')
|
||||
console.log('fetchNotes result:', result)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('fetchNotes test failed')
|
||||
console.error('fetchNotes error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testFetchHostOTP = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing fetchHostOTP...', 0)
|
||||
|
||||
fetchHostOTP(testInputs.hostId, (result) => {
|
||||
msgApi.destroy()
|
||||
if (result.otp) {
|
||||
msgApi.success('fetchHostOTP test completed: ' + result.otp)
|
||||
} else {
|
||||
msgApi.error('fetchHostOTP test failed')
|
||||
}
|
||||
console.log('fetchHostOTP result:', result)
|
||||
})
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('fetchHostOTP test failed')
|
||||
console.error('fetchHostOTP error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testSendObjectAction = async () => {
|
||||
try {
|
||||
msgApi.loading('Testing sendObjectAction...', 0)
|
||||
|
||||
sendObjectAction(
|
||||
testInputs.objectId,
|
||||
'printer',
|
||||
testInputs.action,
|
||||
(result) => {
|
||||
msgApi.destroy()
|
||||
if (result.success) {
|
||||
msgApi.success('sendObjectAction test completed')
|
||||
} else {
|
||||
msgApi.error('sendObjectAction test failed')
|
||||
}
|
||||
console.log('sendObjectAction result:', result)
|
||||
}
|
||||
)
|
||||
} catch (err) {
|
||||
msgApi.destroy()
|
||||
msgApi.error('sendObjectAction test failed')
|
||||
console.error('sendObjectAction error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testSubscribeToObjectUpdates = () => {
|
||||
try {
|
||||
const callback = (data) => {
|
||||
console.log('Object update received:', data)
|
||||
}
|
||||
const unsubscribe = subscribeToObjectUpdates(
|
||||
testInputs.objectId,
|
||||
testInputs.objectType,
|
||||
callback
|
||||
)
|
||||
msgApi.success('Subscribed to object updates')
|
||||
console.log('Subscribed to object updates for test-id')
|
||||
|
||||
// Store unsubscribe function for cleanup
|
||||
setTimeout(() => {
|
||||
if (unsubscribe) {
|
||||
unsubscribe()
|
||||
console.log('Unsubscribed from object updates')
|
||||
}
|
||||
}, 10000) // Auto-unsubscribe after 10 seconds
|
||||
} catch (err) {
|
||||
msgApi.error('Subscribe to object updates failed')
|
||||
console.error('Subscribe error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testSubscribeToObjectEvent = () => {
|
||||
try {
|
||||
const callback = (event) => {
|
||||
console.log('Object event received:', event)
|
||||
}
|
||||
const unsubscribe = subscribeToObjectEvent(
|
||||
testInputs.objectId,
|
||||
'printer',
|
||||
testInputs.eventType,
|
||||
callback
|
||||
)
|
||||
msgApi.success('Subscribed to object events')
|
||||
console.log('Subscribed to object events for test-id')
|
||||
|
||||
// Store unsubscribe function for cleanup
|
||||
setTimeout(() => {
|
||||
if (unsubscribe) {
|
||||
unsubscribe()
|
||||
console.log('Unsubscribed from object events')
|
||||
}
|
||||
}, 10000) // Auto-unsubscribe after 10 seconds
|
||||
} catch (err) {
|
||||
msgApi.error('Subscribe to object events failed')
|
||||
console.error('Subscribe error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testSubscribeToObjectTypeUpdates = () => {
|
||||
try {
|
||||
const callback = (data) => {
|
||||
console.log('Object type update received:', data)
|
||||
}
|
||||
const unsubscribe = subscribeToObjectTypeUpdates(
|
||||
testInputs.objectType,
|
||||
callback
|
||||
)
|
||||
msgApi.success('Subscribed to object type updates')
|
||||
console.log('Subscribed to object type updates for user')
|
||||
|
||||
// Store unsubscribe function for cleanup
|
||||
setTimeout(() => {
|
||||
if (unsubscribe) {
|
||||
unsubscribe()
|
||||
console.log('Unsubscribed from object type updates')
|
||||
}
|
||||
}, 10000) // Auto-unsubscribe after 10 seconds
|
||||
} catch (err) {
|
||||
msgApi.error('Subscribe to object type updates failed')
|
||||
console.error('Subscribe error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const testSubscribeToObjectLock = () => {
|
||||
try {
|
||||
const callback = (lockData) => {
|
||||
console.log('Object lock update received:', lockData)
|
||||
}
|
||||
const unsubscribe = subscribeToObjectLock(
|
||||
testInputs.objectId,
|
||||
testInputs.objectType,
|
||||
callback
|
||||
)
|
||||
msgApi.success('Subscribed to object lock updates')
|
||||
console.log('Subscribed to object lock updates for test-id')
|
||||
|
||||
// Store unsubscribe function for cleanup
|
||||
setTimeout(() => {
|
||||
if (unsubscribe) {
|
||||
unsubscribe()
|
||||
console.log('Unsubscribed from object lock updates')
|
||||
}
|
||||
}, 10000) // Auto-unsubscribe after 10 seconds
|
||||
} catch (err) {
|
||||
msgApi.error('Subscribe to object lock updates failed')
|
||||
console.error('Subscribe error:', err)
|
||||
}
|
||||
}
|
||||
|
||||
const actionItems = {
|
||||
items: [
|
||||
{
|
||||
label: 'Reconnect',
|
||||
key: 'reconnect',
|
||||
disabled: connected
|
||||
},
|
||||
{
|
||||
label: 'Disconnect',
|
||||
key: 'disconnect',
|
||||
disabled: !connected
|
||||
},
|
||||
{
|
||||
type: 'divider'
|
||||
},
|
||||
{
|
||||
label: 'Reload',
|
||||
key: 'reload',
|
||||
icon: <ReloadIcon />
|
||||
}
|
||||
],
|
||||
onClick: ({ key }) => {
|
||||
switch (key) {
|
||||
case 'reconnect':
|
||||
handleReconnect()
|
||||
break
|
||||
case 'disconnect':
|
||||
handleDisconnect()
|
||||
break
|
||||
case 'reload':
|
||||
msgApi.info('Reloading API State...')
|
||||
window.location.reload()
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getConnectionStatusColor = () => {
|
||||
switch (connectionStatus) {
|
||||
case 'connected':
|
||||
return 'success'
|
||||
case 'connecting':
|
||||
return 'processing'
|
||||
case 'disconnected':
|
||||
return 'error'
|
||||
default:
|
||||
return 'default'
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex vertical gap='large' style={{ height: '100%', minHeight: 0 }}>
|
||||
{contextHolder}
|
||||
|
||||
{/* Header with Actions */}
|
||||
<Flex justify={'space-between'} align={'center'}>
|
||||
<Space>
|
||||
<Dropdown menu={actionItems}>
|
||||
<Button>Actions</Button>
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</Flex>
|
||||
|
||||
<Descriptions bordered>
|
||||
<Descriptions.Item label='Status'>
|
||||
<Space>
|
||||
<Tag color={getConnectionStatusColor()} icon={<CloudIcon />}>
|
||||
{connectionStatus.charAt(0).toUpperCase() +
|
||||
connectionStatus.slice(1)}
|
||||
</Tag>
|
||||
</Space>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Connecting'>
|
||||
<BoolDisplay value={connecting} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Connected'>
|
||||
<BoolDisplay value={connected} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Socket ID'>
|
||||
<Text code>{socketId || 'None'}</Text>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Fetch Loading'>
|
||||
<BoolDisplay value={fetchLoading} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Error'>
|
||||
<Text type={error ? 'danger' : 'secondary'}>{error || 'None'}</Text>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
<InfoCollapse
|
||||
title='Params'
|
||||
icon={<span>🔎</span>}
|
||||
active={collapseStates.params}
|
||||
onToggle={() => toggleCollapse('params')}
|
||||
collapseKey='params'
|
||||
>
|
||||
<Descriptions bordered column={2}>
|
||||
<Descriptions.Item label='Object ID'>
|
||||
<Input
|
||||
value={testInputs.objectId}
|
||||
onChange={(e) => updateTestInput('objectId', e.target.value)}
|
||||
placeholder='Enter object ID'
|
||||
size='small'
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Object Type'>
|
||||
<Select
|
||||
value={testInputs.objectType}
|
||||
onChange={(value) => updateTestInput('objectType', value)}
|
||||
style={{ width: '100%' }}
|
||||
options={[
|
||||
{ value: 'user', label: 'User' },
|
||||
{ value: 'printer', label: 'Printer' },
|
||||
{ value: 'job', label: 'Job' },
|
||||
{ value: 'filament', label: 'Filament' },
|
||||
{ value: 'gcodefile', label: 'GCode File' }
|
||||
]}
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Host ID'>
|
||||
<Input
|
||||
value={testInputs.hostId}
|
||||
onChange={(e) => updateTestInput('hostId', e.target.value)}
|
||||
placeholder='Enter host ID'
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Parent ID'>
|
||||
<Input
|
||||
value={testInputs.parentId}
|
||||
onChange={(e) => updateTestInput('parentId', e.target.value)}
|
||||
placeholder='Enter parent ID'
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='File Name'>
|
||||
<Input
|
||||
value={testInputs.fileName}
|
||||
onChange={(e) => updateTestInput('fileName', e.target.value)}
|
||||
placeholder='Enter file name'
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Query'>
|
||||
<Input
|
||||
value={testInputs.query}
|
||||
onChange={(e) => updateTestInput('query', e.target.value)}
|
||||
placeholder='Enter search query'
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Action'>
|
||||
<Select
|
||||
value={testInputs.action}
|
||||
onChange={(value) => updateTestInput('action', value)}
|
||||
style={{ width: '100%' }}
|
||||
options={[
|
||||
{ value: 'start', label: 'Start' },
|
||||
{ value: 'stop', label: 'Stop' },
|
||||
{ value: 'pause', label: 'Pause' },
|
||||
{ value: 'resume', label: 'Resume' }
|
||||
]}
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Event Type'>
|
||||
<Select
|
||||
value={testInputs.eventType}
|
||||
onChange={(value) => updateTestInput('eventType', value)}
|
||||
style={{ width: '100%' }}
|
||||
options={[
|
||||
{ value: 'status', label: 'Status' },
|
||||
{ value: 'progress', label: 'Progress' },
|
||||
{ value: 'error', label: 'Error' },
|
||||
{ value: 'complete', label: 'Complete' }
|
||||
]}
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Scale'>
|
||||
<InputNumber
|
||||
value={testInputs.scale}
|
||||
onChange={(value) => updateTestInput('scale', value)}
|
||||
min={0.1}
|
||||
max={10}
|
||||
step={0.1}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Template Content' span={1}>
|
||||
<Input.TextArea
|
||||
value={testInputs.templateContent}
|
||||
onChange={(e) =>
|
||||
updateTestInput('templateContent', e.target.value)
|
||||
}
|
||||
placeholder='Enter template content'
|
||||
rows={2}
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</InfoCollapse>
|
||||
|
||||
{/* Test Sections */}
|
||||
<div style={{ height: '100%', overflow: 'auto' }}>
|
||||
<Flex vertical gap={'large'}>
|
||||
{/* Fetch Tests */}
|
||||
<InfoCollapse
|
||||
title='Fetch Tests'
|
||||
icon={<span>📥</span>}
|
||||
active={collapseStates.fetchTests}
|
||||
onToggle={() => toggleCollapse('fetchTests')}
|
||||
collapseKey='fetchTests'
|
||||
>
|
||||
<Space direction='vertical' style={{ width: '100%' }}>
|
||||
<Button onClick={testFetchObject} block>
|
||||
Test fetchObject
|
||||
</Button>
|
||||
<Button onClick={testFetchObjects} block>
|
||||
Test fetchObjects
|
||||
</Button>
|
||||
<Button onClick={testFetchObjectLock} block>
|
||||
Test fetchObjectLock
|
||||
</Button>
|
||||
<Button onClick={testFetchObjectsByProperty} block>
|
||||
Test fetchObjectsByProperty
|
||||
</Button>
|
||||
<Button onClick={testFetchSpotlightData} block>
|
||||
Test fetchSpotlightData
|
||||
</Button>
|
||||
<Button onClick={testFetchObjectContent} block>
|
||||
Test fetchObjectContent
|
||||
</Button>
|
||||
<Button onClick={testFetchNotes} block>
|
||||
Test fetchNotes
|
||||
</Button>
|
||||
</Space>
|
||||
</InfoCollapse>
|
||||
|
||||
{/* CRUD Tests */}
|
||||
<InfoCollapse
|
||||
title='CRUD Tests'
|
||||
icon={<span>✏️</span>}
|
||||
active={collapseStates.crudTests}
|
||||
onToggle={() => toggleCollapse('crudTests')}
|
||||
collapseKey='crudTests'
|
||||
>
|
||||
<Space direction='vertical' style={{ width: '100%' }}>
|
||||
<Button onClick={testLockObject} block>
|
||||
Test Lock Object
|
||||
</Button>
|
||||
<Button onClick={testUnlockObject} block>
|
||||
Test Unlock Object
|
||||
</Button>
|
||||
<Button onClick={testUpdateObject} block>
|
||||
Test updateObject
|
||||
</Button>
|
||||
<Button onClick={testCreateObject} block>
|
||||
Test createObject
|
||||
</Button>
|
||||
<Button onClick={testDeleteObject} block>
|
||||
Test deleteObject
|
||||
</Button>
|
||||
</Space>
|
||||
</InfoCollapse>
|
||||
|
||||
{/* Special Tests */}
|
||||
<InfoCollapse
|
||||
title='Special Tests'
|
||||
icon={<span>🔧</span>}
|
||||
active={collapseStates.specialTests}
|
||||
onToggle={() => toggleCollapse('specialTests')}
|
||||
collapseKey='specialTests'
|
||||
>
|
||||
<Space direction='vertical' style={{ width: '100%' }}>
|
||||
<Button onClick={testFetchTemplatePreview} block>
|
||||
Test fetchTemplatePreview
|
||||
</Button>
|
||||
<Button onClick={testFetchHostOTP} block>
|
||||
Test fetchHostOTP
|
||||
</Button>
|
||||
<Button onClick={testSendObjectAction} block>
|
||||
Test sendObjectAction
|
||||
</Button>
|
||||
</Space>
|
||||
</InfoCollapse>
|
||||
|
||||
{/* Subscription Tests */}
|
||||
<InfoCollapse
|
||||
title='Subscription Tests'
|
||||
icon={<span>📡</span>}
|
||||
active={collapseStates.subscriptionTests}
|
||||
onToggle={() => toggleCollapse('subscriptionTests')}
|
||||
collapseKey='subscriptionTests'
|
||||
>
|
||||
<Space direction='vertical' style={{ width: '100%' }}>
|
||||
<Button onClick={testSubscribeToObjectUpdates} block>
|
||||
Test Subscribe Object Updates
|
||||
</Button>
|
||||
<Button onClick={testSubscribeToObjectEvent} block>
|
||||
Test Subscribe Object Events
|
||||
</Button>
|
||||
<Button onClick={testSubscribeToObjectTypeUpdates} block>
|
||||
Test Subscribe Object Type Updates
|
||||
</Button>
|
||||
<Button onClick={testSubscribeToObjectLock} block>
|
||||
Test Subscribe Object Lock
|
||||
</Button>
|
||||
</Space>
|
||||
</InfoCollapse>
|
||||
|
||||
{/* API Server Instance Info */}
|
||||
<InfoCollapse
|
||||
title='API Server Instance'
|
||||
icon={<span>🖥️</span>}
|
||||
active={false}
|
||||
onToggle={() => {}}
|
||||
collapseKey='apiServer'
|
||||
>
|
||||
<pre style={{ margin: 0, fontSize: 12 }}>
|
||||
{apiServer ? (
|
||||
<Paragraph>
|
||||
<pre>
|
||||
{JSON.stringify(
|
||||
{
|
||||
connected: apiServer.connected,
|
||||
id: apiServer.id,
|
||||
transport: apiServer.io.engine.transport.name,
|
||||
readyState: apiServer.io.engine.readyState
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}
|
||||
</pre>
|
||||
</Paragraph>
|
||||
) : (
|
||||
<Text type='secondary'>No API server instance</Text>
|
||||
)}
|
||||
</pre>
|
||||
</InfoCollapse>
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default ApiContextDebug
|
||||
@ -18,17 +18,17 @@ const items = [
|
||||
path: '/dashboard/developer/authcontextdebug'
|
||||
},
|
||||
{
|
||||
key: 'apicontextdebug',
|
||||
label: 'API Debug',
|
||||
icon: <Text>🌐</Text>,
|
||||
path: '/dashboard/developer/apicontextdebug'
|
||||
key: 'printservercontextdebug',
|
||||
label: 'Print Server Debug',
|
||||
icon: <Text>🖨️</Text>,
|
||||
path: '/dashboard/developer/printservercontextdebug'
|
||||
}
|
||||
]
|
||||
|
||||
const routeKeyMap = {
|
||||
'/dashboard/developer/sessionstorage': 'sessionstorage',
|
||||
'/dashboard/developer/authcontextdebug': 'authcontextdebug',
|
||||
'/dashboard/developer/apicontextdebug': 'apicontextdebug'
|
||||
'/dashboard/developer/authcontext': 'authcontextdebug',
|
||||
'/dashboard/developer/printservercontext': 'printservercontextdebug'
|
||||
}
|
||||
|
||||
const DeveloperSidebar = (props) => {
|
||||
|
||||
@ -0,0 +1,77 @@
|
||||
import { useContext } from 'react'
|
||||
import {
|
||||
Descriptions,
|
||||
Button,
|
||||
Typography,
|
||||
Flex,
|
||||
Space,
|
||||
Dropdown,
|
||||
message
|
||||
} from 'antd'
|
||||
import ReloadIcon from '../../Icons/ReloadIcon.jsx'
|
||||
import { PrintServerContext } from '../context/PrintServerContext.jsx'
|
||||
import BoolDisplay from '../common/BoolDisplay.jsx'
|
||||
|
||||
const { Text, Paragraph } = Typography
|
||||
|
||||
const PrintServerContextDebug = () => {
|
||||
const { printServer, error, connecting } = useContext(PrintServerContext)
|
||||
const [msgApi, contextHolder] = message.useMessage()
|
||||
|
||||
const actionItems = {
|
||||
items: [
|
||||
{
|
||||
label: 'Reload',
|
||||
key: 'reload',
|
||||
icon: <ReloadIcon />
|
||||
}
|
||||
],
|
||||
onClick: ({ key }) => {
|
||||
if (key === 'reload') {
|
||||
msgApi.info('Reloading Page...')
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to display socket info safely
|
||||
const getSocketInfo = () => {
|
||||
if (!printServer) return 'n/a'
|
||||
// Only show safe properties
|
||||
const { id, connected, disconnected, nsp } = printServer
|
||||
return JSON.stringify({ id, connected, disconnected, nsp }, null, 2)
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex vertical gap='large' style={{ height: '100%', minHeight: 0 }}>
|
||||
{contextHolder}
|
||||
<Flex justify={'space-between'} align={'center'}>
|
||||
<Space>
|
||||
<Dropdown menu={actionItems}>
|
||||
<Button>Actions</Button>
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</Flex>
|
||||
<div style={{ height: '100%', overflow: 'auto' }}>
|
||||
<Descriptions bordered column={1}>
|
||||
<Descriptions.Item label='Connected'>
|
||||
<BoolDisplay value={printServer?.connected || false} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Connecting'>
|
||||
<BoolDisplay value={connecting} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Error'>
|
||||
{error ? <Text type='danger'>{error}</Text> : <Text>n/a</Text>}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label='Socket'>
|
||||
<Paragraph>
|
||||
<pre>{getSocketInfo()}</pre>
|
||||
</Paragraph>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default PrintServerContextDebug
|
||||
@ -17,7 +17,6 @@ import FilamentStockIcon from '../../../Icons/FilamentStockIcon'
|
||||
import NoteIcon from '../../../Icons/NoteIcon'
|
||||
import AuditLogIcon from '../../../Icons/AuditLogIcon'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton'
|
||||
|
||||
const FilamentStockInfo = () => {
|
||||
const location = useLocation()
|
||||
@ -40,8 +39,7 @@ const FilamentStockInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
lock: null,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -77,7 +75,6 @@ const FilamentStockInfo = () => {
|
||||
type='filamentStock'
|
||||
id={filamentStockId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -90,11 +87,6 @@ const FilamentStockInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='filamentStock'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -1,98 +0,0 @@
|
||||
import { useState, useRef } from 'react'
|
||||
import { Button, Flex, Space, Modal, Dropdown, message } from 'antd'
|
||||
import NewDocumentJob from './DocumentJobs/NewDocumentJob'
|
||||
import ObjectTable from '../common/ObjectTable'
|
||||
import PlusIcon from '../../Icons/PlusIcon'
|
||||
import ReloadIcon from '../../Icons/ReloadIcon'
|
||||
import useColumnVisibility from '../hooks/useColumnVisibility'
|
||||
import GridIcon from '../../Icons/GridIcon'
|
||||
import ListIcon from '../../Icons/ListIcon'
|
||||
import useViewMode from '../hooks/useViewMode'
|
||||
import ColumnViewButton from '../common/ColumnViewButton'
|
||||
|
||||
const DocumentJobs = () => {
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
const [newDocumentJobOpen, setNewDocumentJobOpen] = useState(false)
|
||||
const tableRef = useRef()
|
||||
|
||||
const [viewMode, setViewMode] = useViewMode('documentJob')
|
||||
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
useColumnVisibility('documentJob')
|
||||
|
||||
const actionItems = {
|
||||
items: [
|
||||
{
|
||||
label: 'New Document Job',
|
||||
key: 'newDocumentJob',
|
||||
icon: <PlusIcon />
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
label: 'Reload List',
|
||||
key: 'reloadList',
|
||||
icon: <ReloadIcon />
|
||||
}
|
||||
],
|
||||
onClick: ({ key }) => {
|
||||
if (key === 'reloadList') {
|
||||
tableRef.current?.reload()
|
||||
} else if (key === 'newDocumentJob') {
|
||||
setNewDocumentJobOpen(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex vertical={'true'} gap='large'>
|
||||
{contextHolder}
|
||||
<Flex justify={'space-between'}>
|
||||
<Space size='small'>
|
||||
<Dropdown menu={actionItems}>
|
||||
<Button>Actions</Button>
|
||||
</Dropdown>
|
||||
<ColumnViewButton
|
||||
type='documentJob'
|
||||
loading={false}
|
||||
collapseState={columnVisibility}
|
||||
updateCollapseState={setColumnVisibility}
|
||||
/>
|
||||
</Space>
|
||||
<Space>
|
||||
<Button
|
||||
icon={viewMode === 'cards' ? <ListIcon /> : <GridIcon />}
|
||||
onClick={() =>
|
||||
setViewMode(viewMode === 'cards' ? 'list' : 'cards')
|
||||
}
|
||||
/>
|
||||
</Space>
|
||||
</Flex>
|
||||
<ObjectTable
|
||||
ref={tableRef}
|
||||
visibleColumns={columnVisibility}
|
||||
type='documentJob'
|
||||
cards={viewMode === 'cards'}
|
||||
/>
|
||||
</Flex>
|
||||
<Modal
|
||||
open={newDocumentJobOpen}
|
||||
onCancel={() => setNewDocumentJobOpen(false)}
|
||||
footer={null}
|
||||
destroyOnHidden={true}
|
||||
width={900}
|
||||
>
|
||||
<NewDocumentJob
|
||||
onOk={() => {
|
||||
setNewDocumentJobOpen(false)
|
||||
messageApi.success('New note type created successfully.')
|
||||
tableRef.current?.reload()
|
||||
}}
|
||||
reset={!newDocumentJobOpen}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DocumentJobs
|
||||
@ -1,195 +0,0 @@
|
||||
import { useRef, useState } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { Space, Flex, Card } from 'antd'
|
||||
import { LoadingOutlined } from '@ant-design/icons'
|
||||
import loglevel from 'loglevel'
|
||||
import config from '../../../../config.js'
|
||||
import useCollapseState from '../../hooks/useCollapseState.js'
|
||||
import NotesPanel from '../../common/NotesPanel.jsx'
|
||||
import InfoCollapse from '../../common/InfoCollapse.jsx'
|
||||
import ObjectInfo from '../../common/ObjectInfo.jsx'
|
||||
import ViewButton from '../../common/ViewButton.jsx'
|
||||
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
|
||||
import NoteIcon from '../../../Icons/NoteIcon.jsx'
|
||||
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
|
||||
import ObjectForm from '../../common/ObjectForm.jsx'
|
||||
import EditButtons from '../../common/EditButtons.jsx'
|
||||
import LockIndicator from '../../common/LockIndicator.jsx'
|
||||
import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('DocumentJobInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
|
||||
const DocumentJobInfo = () => {
|
||||
const location = useLocation()
|
||||
const objectFormRef = useRef(null)
|
||||
const actionHandlerRef = useRef(null)
|
||||
const documentJobId = new URLSearchParams(location.search).get(
|
||||
'documentJobId'
|
||||
)
|
||||
const [collapseState, updateCollapseState] = useCollapseState(
|
||||
'DocumentJobInfo',
|
||||
{
|
||||
info: true,
|
||||
notes: true,
|
||||
auditLogs: true
|
||||
}
|
||||
)
|
||||
const [objectFormState, setEditFormState] = useState({
|
||||
isEditing: false,
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
lock: null,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
})
|
||||
|
||||
const actions = {
|
||||
reload: () => {
|
||||
objectFormRef?.current?.fetchObject?.()
|
||||
return true
|
||||
},
|
||||
edit: () => {
|
||||
objectFormRef?.current?.startEditing?.()
|
||||
return false
|
||||
},
|
||||
cancelEdit: () => {
|
||||
objectFormRef?.current?.cancelEditing?.()
|
||||
return true
|
||||
},
|
||||
finishEdit: () => {
|
||||
objectFormRef?.current?.handleUpdate?.()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
gap='large'
|
||||
vertical='true'
|
||||
style={{ maxHeight: '100%', minHeight: 0 }}
|
||||
>
|
||||
<Flex justify={'space-between'}>
|
||||
<Space size='middle'>
|
||||
<Space size='small'>
|
||||
<ObjectActions
|
||||
type='documentJob'
|
||||
id={documentJobId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
items={[
|
||||
{ key: 'info', label: 'Document Job Information' },
|
||||
{ key: 'notes', label: 'Notes' },
|
||||
{ key: 'auditLogs', label: 'Audit Logs' }
|
||||
]}
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='documentJob'
|
||||
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>
|
||||
</Flex>
|
||||
<div style={{ height: '100%', overflow: 'auto' }}>
|
||||
<Flex vertical gap={'large'}>
|
||||
<ActionHandler
|
||||
actions={actions}
|
||||
loading={objectFormState.loading}
|
||||
ref={actionHandlerRef}
|
||||
>
|
||||
<InfoCollapse
|
||||
title='Document Job Information'
|
||||
icon={<InfoCircleIcon />}
|
||||
active={collapseState.info}
|
||||
onToggle={(expanded) => updateCollapseState('info', expanded)}
|
||||
collapseKey='info'
|
||||
>
|
||||
<ObjectForm
|
||||
id={documentJobId}
|
||||
type='documentJob'
|
||||
style={{ height: '100%' }}
|
||||
ref={objectFormRef}
|
||||
onStateChange={(state) => {
|
||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||
}}
|
||||
>
|
||||
{({ loading, isEditing, objectData }) => (
|
||||
<ObjectInfo
|
||||
loading={loading}
|
||||
indicator={<LoadingOutlined />}
|
||||
isEditing={isEditing}
|
||||
type='documentJob'
|
||||
objectData={objectData}
|
||||
/>
|
||||
)}
|
||||
</ObjectForm>
|
||||
</InfoCollapse>
|
||||
</ActionHandler>
|
||||
<InfoCollapse
|
||||
title='Notes'
|
||||
icon={<NoteIcon />}
|
||||
active={collapseState.notes}
|
||||
onToggle={(expanded) => updateCollapseState('notes', expanded)}
|
||||
collapseKey='notes'
|
||||
>
|
||||
<Card>
|
||||
<NotesPanel _id={documentJobId} type='documentJob' />
|
||||
</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': documentJobId }}
|
||||
visibleColumns={{ _id: false, 'parent._id': false }}
|
||||
/>
|
||||
)}
|
||||
</InfoCollapse>
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default DocumentJobInfo
|
||||
@ -1,66 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import ObjectInfo from '../../common/ObjectInfo'
|
||||
import NewObjectForm from '../../common/NewObjectForm'
|
||||
import WizardView from '../../common/WizardView'
|
||||
import TemplatePreview from '../../common/TemplatePreview'
|
||||
|
||||
const NewDocumentJob = ({ onOk, defaultValues = {} }) => {
|
||||
return (
|
||||
<NewObjectForm
|
||||
type={'documentJob'}
|
||||
defaultValues={{ objectType: 'documentJob', ...defaultValues }}
|
||||
>
|
||||
{({ handleSubmit, submitLoading, objectData, formValid }) => {
|
||||
const steps = [
|
||||
{
|
||||
title: 'Required',
|
||||
key: 'required',
|
||||
content: (
|
||||
<ObjectInfo
|
||||
type='documentJob'
|
||||
column={1}
|
||||
visibleProperties={{ name: false }}
|
||||
bordered={false}
|
||||
isEditing={true}
|
||||
required={true}
|
||||
objectData={objectData}
|
||||
/>
|
||||
)
|
||||
}
|
||||
]
|
||||
return (
|
||||
<WizardView
|
||||
steps={steps}
|
||||
submitText='Print'
|
||||
title={'Print Document'}
|
||||
formValid={formValid}
|
||||
loading={submitLoading}
|
||||
sideBar={
|
||||
<div style={{ minWidth: '400px', minHeight: '500px' }}>
|
||||
<TemplatePreview
|
||||
objectData={objectData?.object}
|
||||
documentTemplate={objectData?.documentTemplate}
|
||||
onPreviewMessage={(message) => {
|
||||
console.log(message)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
onSubmit={() => {
|
||||
handleSubmit()
|
||||
onOk()
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
</NewObjectForm>
|
||||
)
|
||||
}
|
||||
|
||||
NewDocumentJob.propTypes = {
|
||||
onOk: PropTypes.func.isRequired,
|
||||
reset: PropTypes.bool,
|
||||
defaultValues: PropTypes.object
|
||||
}
|
||||
|
||||
export default NewDocumentJob
|
||||
@ -18,7 +18,6 @@ import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('DocumentPrinterInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -93,7 +92,6 @@ const DocumentPrinterInfo = () => {
|
||||
type='documentPrinter'
|
||||
id={documentPrinterId}
|
||||
disabled={loading}
|
||||
objectData={objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={loading}
|
||||
@ -109,11 +107,6 @@ const DocumentPrinterInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='documentPrinter'
|
||||
objectData={objectData}
|
||||
disabled={loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={lock} />
|
||||
</Space>
|
||||
|
||||
@ -19,7 +19,6 @@ import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('DocumentSizeInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -44,8 +43,7 @@ const DocumentSizeInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
lock: null,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -81,7 +79,6 @@ const DocumentSizeInfo = () => {
|
||||
type='documentSize'
|
||||
id={documentSizeId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -93,11 +90,6 @@ const DocumentSizeInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='documentSize'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -19,7 +19,6 @@ import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('DocumentTemplateInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -46,8 +45,7 @@ const DocumentTemplateInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
locked: false,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -86,7 +84,6 @@ const DocumentTemplateInfo = () => {
|
||||
type='documentTemplate'
|
||||
id={documentTemplateId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -98,11 +95,6 @@ const DocumentTemplateInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='documentTemplate'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
@ -134,7 +126,7 @@ const DocumentTemplateInfo = () => {
|
||||
ref={actionHandlerRef}
|
||||
>
|
||||
<InfoCollapse
|
||||
title='Document Template Information'
|
||||
title='DocumentTemplate Information'
|
||||
icon={<InfoCircleIcon />}
|
||||
active={collapseState.info}
|
||||
onToggle={(expanded) => updateCollapseState('info', expanded)}
|
||||
|
||||
@ -20,7 +20,6 @@ import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import FilamentIcon from '../../../Icons/FilamentIcon.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('FilamentInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -45,8 +44,7 @@ const FilamentInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
lock: null,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -85,7 +83,6 @@ const FilamentInfo = () => {
|
||||
type='filament'
|
||||
id={filamentId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -98,11 +95,6 @@ const FilamentInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='filament'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
import { useRef } from 'react'
|
||||
import { Button, Flex, Space, Dropdown } from 'antd'
|
||||
import ObjectTable from '../common/ObjectTable'
|
||||
import ReloadIcon from '../../Icons/ReloadIcon'
|
||||
import useColumnVisibility from '../hooks/useColumnVisibility'
|
||||
import GridIcon from '../../Icons/GridIcon'
|
||||
import ListIcon from '../../Icons/ListIcon'
|
||||
import useViewMode from '../hooks/useViewMode'
|
||||
import ColumnViewButton from '../common/ColumnViewButton'
|
||||
|
||||
const Files = () => {
|
||||
const tableRef = useRef()
|
||||
|
||||
const [viewMode, setViewMode] = useViewMode('file')
|
||||
|
||||
const [columnVisibility, setColumnVisibility] = useColumnVisibility('file')
|
||||
|
||||
const actionItems = {
|
||||
items: [
|
||||
{
|
||||
label: 'Reload List',
|
||||
key: 'reloadList',
|
||||
icon: <ReloadIcon />
|
||||
}
|
||||
],
|
||||
onClick: ({ key }) => {
|
||||
if (key === 'reloadList') {
|
||||
tableRef.current?.reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex vertical={'true'} gap='large'>
|
||||
<Flex justify={'space-between'}>
|
||||
<Space size='small'>
|
||||
<Dropdown menu={actionItems}>
|
||||
<Button>Actions</Button>
|
||||
</Dropdown>
|
||||
<ColumnViewButton
|
||||
type='file'
|
||||
loading={false}
|
||||
collapseState={columnVisibility}
|
||||
updateCollapseState={setColumnVisibility}
|
||||
/>
|
||||
</Space>
|
||||
<Space>
|
||||
<Button
|
||||
icon={viewMode === 'cards' ? <ListIcon /> : <GridIcon />}
|
||||
onClick={() =>
|
||||
setViewMode(viewMode === 'cards' ? 'list' : 'cards')
|
||||
}
|
||||
/>
|
||||
</Space>
|
||||
</Flex>
|
||||
<ObjectTable
|
||||
ref={tableRef}
|
||||
visibleColumns={columnVisibility}
|
||||
type='file'
|
||||
cards={viewMode === 'cards'}
|
||||
/>
|
||||
</Flex>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Files
|
||||
@ -1,192 +0,0 @@
|
||||
import { useRef, useState } from 'react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { Space, Flex, Card } from 'antd'
|
||||
import loglevel from 'loglevel'
|
||||
import config from '../../../../config.js'
|
||||
import useCollapseState from '../../hooks/useCollapseState.js'
|
||||
import NotesPanel from '../../common/NotesPanel.jsx'
|
||||
import InfoCollapse from '../../common/InfoCollapse.jsx'
|
||||
import ObjectInfo from '../../common/ObjectInfo.jsx'
|
||||
import ViewButton from '../../common/ViewButton.jsx'
|
||||
import InfoCircleIcon from '../../../Icons/InfoCircleIcon.jsx'
|
||||
import NoteIcon from '../../../Icons/NoteIcon.jsx'
|
||||
import AuditLogIcon from '../../../Icons/AuditLogIcon.jsx'
|
||||
import ObjectForm from '../../common/ObjectForm.jsx'
|
||||
import EditButtons from '../../common/EditButtons.jsx'
|
||||
import LockIndicator from '../../common/LockIndicator.jsx'
|
||||
import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('FileInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
|
||||
const FileInfo = () => {
|
||||
const location = useLocation()
|
||||
const objectFormRef = useRef(null)
|
||||
const actionHandlerRef = useRef(null)
|
||||
const fileId = new URLSearchParams(location.search).get('fileId')
|
||||
const [collapseState, updateCollapseState] = useCollapseState('FileInfo', {
|
||||
info: true,
|
||||
notes: true,
|
||||
auditLogs: true
|
||||
})
|
||||
const [objectFormState, setEditFormState] = useState({
|
||||
isEditing: false,
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
lock: null,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
})
|
||||
|
||||
const actions = {
|
||||
reload: () => {
|
||||
objectFormRef?.current?.handleFetchObject?.()
|
||||
return true
|
||||
},
|
||||
edit: () => {
|
||||
objectFormRef?.current?.startEditing?.()
|
||||
return false
|
||||
},
|
||||
cancelEdit: () => {
|
||||
objectFormRef?.current?.cancelEditing?.()
|
||||
return true
|
||||
},
|
||||
finishEdit: () => {
|
||||
objectFormRef?.current?.handleUpdate?.()
|
||||
return true
|
||||
},
|
||||
delete: () => {
|
||||
objectFormRef?.current?.handleDelete?.()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
gap='large'
|
||||
vertical='true'
|
||||
style={{ maxHeight: '100%', minHeight: 0 }}
|
||||
>
|
||||
<Flex justify={'space-between'}>
|
||||
<Space size='middle'>
|
||||
<Space size='small'>
|
||||
<ObjectActions
|
||||
type='file'
|
||||
id={fileId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
items={[
|
||||
{ key: 'info', label: 'File Information' },
|
||||
{ key: 'notes', label: 'Notes' },
|
||||
{ key: 'auditLogs', label: 'Audit Logs' }
|
||||
]}
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='file'
|
||||
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>
|
||||
</Flex>
|
||||
<div style={{ height: '100%', overflow: 'auto' }}>
|
||||
<Flex vertical gap={'large'}>
|
||||
<ActionHandler
|
||||
actions={actions}
|
||||
loading={objectFormState.loading}
|
||||
ref={actionHandlerRef}
|
||||
>
|
||||
<InfoCollapse
|
||||
title='File Information'
|
||||
icon={<InfoCircleIcon />}
|
||||
active={collapseState.info}
|
||||
onToggle={(expanded) => updateCollapseState('info', expanded)}
|
||||
collapseKey='info'
|
||||
>
|
||||
<ObjectForm
|
||||
id={fileId}
|
||||
type='file'
|
||||
style={{ height: '100%' }}
|
||||
ref={objectFormRef}
|
||||
onStateChange={(state) => {
|
||||
setEditFormState((prev) => ({ ...prev, ...state }))
|
||||
}}
|
||||
>
|
||||
{({ loading, isEditing, objectData }) => (
|
||||
<ObjectInfo
|
||||
loading={loading}
|
||||
isEditing={isEditing}
|
||||
type='file'
|
||||
objectData={objectData}
|
||||
/>
|
||||
)}
|
||||
</ObjectForm>
|
||||
</InfoCollapse>
|
||||
</ActionHandler>
|
||||
<InfoCollapse
|
||||
title='Notes'
|
||||
icon={<NoteIcon />}
|
||||
active={collapseState.notes}
|
||||
onToggle={(expanded) => updateCollapseState('notes', expanded)}
|
||||
collapseKey='notes'
|
||||
>
|
||||
<Card>
|
||||
<NotesPanel _id={fileId} type='file' />
|
||||
</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': fileId }}
|
||||
visibleColumns={{ _id: false, 'parent._id': false }}
|
||||
/>
|
||||
)}
|
||||
</InfoCollapse>
|
||||
</Flex>
|
||||
</div>
|
||||
</Flex>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FileInfo
|
||||
@ -20,8 +20,6 @@ import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import HostOTP from './HostOtp.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
import PrinterIcon from '../../../Icons/PrinterIcon.jsx'
|
||||
|
||||
const log = loglevel.getLogger('HostInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -33,7 +31,7 @@ const HostInfo = () => {
|
||||
const hostId = new URLSearchParams(location.search).get('hostId')
|
||||
const [collapseState, updateCollapseState] = useCollapseState('HostInfo', {
|
||||
info: true,
|
||||
printers: true,
|
||||
stocks: true,
|
||||
notes: true,
|
||||
auditLogs: true
|
||||
})
|
||||
@ -44,8 +42,7 @@ const HostInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
locked: false,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -88,24 +85,17 @@ const HostInfo = () => {
|
||||
type='host'
|
||||
id={hostId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
items={[
|
||||
{ key: 'info', label: 'Host Information' },
|
||||
{ key: 'printers', label: 'Printers' },
|
||||
{ key: 'notes', label: 'Notes' },
|
||||
{ key: 'auditLogs', label: 'Audit Logs' }
|
||||
]}
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='host'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
@ -168,27 +158,6 @@ const HostInfo = () => {
|
||||
</InfoCollapse>
|
||||
</ActionHandler>
|
||||
|
||||
<InfoCollapse
|
||||
title='Printers'
|
||||
icon={<PrinterIcon />}
|
||||
active={collapseState.printers}
|
||||
onToggle={(expanded) => updateCollapseState('printers', expanded)}
|
||||
collapseKey='printers'
|
||||
>
|
||||
{objectFormState.loading ? (
|
||||
<InfoCollapsePlaceholder />
|
||||
) : (
|
||||
<ObjectTable
|
||||
type='printer'
|
||||
masterFilter={{ 'host._id': hostId }}
|
||||
visibleColumns={{
|
||||
host: false,
|
||||
'host._id': false
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</InfoCollapse>
|
||||
|
||||
<InfoCollapse
|
||||
title='Notes'
|
||||
icon={<NoteIcon />}
|
||||
|
||||
@ -15,8 +15,6 @@ import DocumentPrinterIcon from '../../Icons/DocumentPrinterIcon'
|
||||
import DocumentTemplateIcon from '../../Icons/DocumentTemplateIcon'
|
||||
import DocumentIcon from '../../Icons/DocumentIcon'
|
||||
import DocumentSizeIcon from '../../Icons/DocumentSizeIcon'
|
||||
import DocumentJobIcon from '../../Icons/DocumentJobIcon'
|
||||
import FileIcon from '../../Icons/FileIcon'
|
||||
|
||||
const items = [
|
||||
{
|
||||
@ -67,12 +65,6 @@ const items = [
|
||||
label: 'Document Printers',
|
||||
path: '/dashboard/management/documentprinters'
|
||||
},
|
||||
{
|
||||
key: 'documentJobs',
|
||||
icon: <DocumentJobIcon />,
|
||||
label: 'Document Jobs',
|
||||
path: '/dashboard/management/documentjobs'
|
||||
},
|
||||
{
|
||||
key: 'documentTemplates',
|
||||
icon: <DocumentTemplateIcon />,
|
||||
@ -87,14 +79,13 @@ const items = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{ type: 'divider' },
|
||||
|
||||
{
|
||||
key: 'hosts',
|
||||
icon: <HostIcon />,
|
||||
label: 'Hosts',
|
||||
path: '/dashboard/management/hosts'
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
key: 'users',
|
||||
icon: <PersonIcon />,
|
||||
@ -107,12 +98,6 @@ const items = [
|
||||
label: 'Settings',
|
||||
path: '/dashboard/management/settings'
|
||||
},
|
||||
{
|
||||
key: 'files',
|
||||
icon: <FileIcon />,
|
||||
label: 'Files',
|
||||
path: '/dashboard/management/files'
|
||||
},
|
||||
{
|
||||
key: 'auditLogs',
|
||||
icon: <AuditLogIcon />,
|
||||
@ -143,12 +128,10 @@ const routeKeyMap = {
|
||||
'/dashboard/management/notetypes': 'noteTypes',
|
||||
'/dashboard/management/settings': 'settings',
|
||||
'/dashboard/management/auditlogs': 'auditLogs',
|
||||
'/dashboard/management/files': 'files',
|
||||
'/dashboard/management/hosts': 'hosts',
|
||||
'/dashboard/management/documentsizes': 'documentSizes',
|
||||
'/dashboard/management/documentprinters': 'documentPrinters',
|
||||
'/dashboard/management/documenttemplates': 'documentTemplates',
|
||||
'/dashboard/management/documentjobs': 'documentJobs'
|
||||
'/dashboard/management/documenttemplates': 'documentTemplates'
|
||||
}
|
||||
|
||||
const ManagementSidebar = (props) => {
|
||||
|
||||
@ -15,7 +15,6 @@ import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const NoteTypeInfo = () => {
|
||||
const location = useLocation()
|
||||
@ -34,8 +33,7 @@ const NoteTypeInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
lock: null,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -71,7 +69,6 @@ const NoteTypeInfo = () => {
|
||||
type='noteType'
|
||||
id={noteTypeId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -82,11 +79,6 @@ const NoteTypeInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='noteType'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -18,7 +18,6 @@ import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('NoteInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -38,8 +37,7 @@ const NoteInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
lock: null,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -79,7 +77,6 @@ const NoteInfo = () => {
|
||||
type='note'
|
||||
id={noteId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -91,11 +88,6 @@ const NoteInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='note'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -16,7 +16,6 @@ import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
import { ApiServerContext } from '../../context/ApiServerContext'
|
||||
|
||||
const PartInfo = () => {
|
||||
@ -79,7 +78,6 @@ const PartInfo = () => {
|
||||
type='part'
|
||||
id={partId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -91,11 +89,6 @@ const PartInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='part'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -17,7 +17,6 @@ import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const ProductInfo = () => {
|
||||
const location = useLocation()
|
||||
@ -71,7 +70,6 @@ const ProductInfo = () => {
|
||||
type='product'
|
||||
id={productId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -84,11 +82,6 @@ const ProductInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='product'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -17,7 +17,6 @@ import ActionHandler from '../../common/ActionHandler'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const UserInfo = () => {
|
||||
const location = useLocation()
|
||||
@ -34,8 +33,7 @@ const UserInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
lock: null,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -71,7 +69,6 @@ const UserInfo = () => {
|
||||
type='user'
|
||||
id={userId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -83,11 +80,6 @@ const UserInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='user'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -18,7 +18,6 @@ import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('VendorInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -38,8 +37,7 @@ const VendorInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
lock: null,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -79,7 +77,6 @@ const VendorInfo = () => {
|
||||
type='vendor'
|
||||
id={vendorId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -91,11 +88,6 @@ const VendorInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='vendor'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -20,7 +20,6 @@ import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import EyeIcon from '../../../Icons/EyeIcon.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const { Text } = Typography
|
||||
|
||||
@ -47,8 +46,7 @@ const GCodeFileInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
locked: false,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -87,7 +85,6 @@ const GCodeFileInfo = () => {
|
||||
type='gcodeFile'
|
||||
id={gcodeFileId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -100,11 +97,6 @@ const GCodeFileInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='gcodeFile'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -20,7 +20,6 @@ import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import JobIcon from '../../../Icons/JobIcon.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('JobInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -42,8 +41,7 @@ const JobInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
locked: false,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -82,7 +80,6 @@ const JobInfo = () => {
|
||||
type='job'
|
||||
id={jobId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -95,11 +92,6 @@ const JobInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='job'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
|
||||
@ -87,7 +87,6 @@ const Printers = () => {
|
||||
onCancel={() => {
|
||||
setNewPrinterOpen(false)
|
||||
}}
|
||||
destroyOnHidden
|
||||
>
|
||||
<NewPrinter
|
||||
onOk={() => {
|
||||
|
||||
@ -10,6 +10,7 @@ import ViewButton from '../../common/ViewButton.jsx'
|
||||
import NoteIcon from '../../../Icons/NoteIcon.jsx'
|
||||
import ObjectForm from '../../common/ObjectForm.jsx'
|
||||
import EditButtons from '../../common/EditButtons.jsx'
|
||||
import LockIndicator from '../../common/LockIndicator.jsx'
|
||||
import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
|
||||
@ -25,7 +26,6 @@ import SubJobIcon from '../../../Icons/SubJobIcon.jsx'
|
||||
import FilamentStockIcon from '../../../Icons/FilamentStockIcon.jsx'
|
||||
import MissingPlaceholder from '../../common/MissingPlaceholder.jsx'
|
||||
import { useMediaQuery } from 'react-responsive'
|
||||
import AlertsDisplay from '../../common/AlertsDisplay.jsx'
|
||||
|
||||
const log = loglevel.getLogger('ControlPrinter')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -68,8 +68,7 @@ const ControlPrinter = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
locked: false,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -165,8 +164,8 @@ const ControlPrinter = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<AlertsDisplay alerts={objectFormState.objectData?.alerts} />
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
<Space>
|
||||
<EditButtons
|
||||
|
||||
@ -1,109 +1,564 @@
|
||||
import { useState, useContext, useEffect, useCallback } from 'react'
|
||||
import axios from 'axios'
|
||||
import {
|
||||
Form,
|
||||
Button,
|
||||
message,
|
||||
Typography,
|
||||
Flex,
|
||||
Steps,
|
||||
Divider,
|
||||
Input,
|
||||
Select,
|
||||
Space,
|
||||
Descriptions,
|
||||
List,
|
||||
InputNumber,
|
||||
notification,
|
||||
Progress,
|
||||
Modal,
|
||||
Radio
|
||||
} from 'antd'
|
||||
import { SearchOutlined, SettingOutlined } from '@ant-design/icons'
|
||||
import PropTypes from 'prop-types'
|
||||
import ObjectInfo from '../../common/ObjectInfo'
|
||||
import NewObjectForm from '../../common/NewObjectForm'
|
||||
import WizardView from '../../common/WizardView'
|
||||
import { PrintServerContext } from '../../context/PrintServerContext'
|
||||
import EditIcon from '../../../Icons/EditIcon.jsx'
|
||||
|
||||
const NewPrinter = ({ onOk }) => {
|
||||
return (
|
||||
<NewObjectForm
|
||||
type={'printer'}
|
||||
defaultValues={{
|
||||
import config from '../../../../config.js'
|
||||
|
||||
const { Title } = Typography
|
||||
|
||||
const initialNewPrinterForm = {
|
||||
moonraker: {
|
||||
port: 7125,
|
||||
protocol: 'ws'
|
||||
protocol: 'ws',
|
||||
host: '',
|
||||
port: '',
|
||||
apiKey: ''
|
||||
}
|
||||
}
|
||||
|
||||
const NewPrinter = ({ onOk, reset }) => {
|
||||
NewPrinter.propTypes = {
|
||||
onOk: PropTypes.func.isRequired,
|
||||
reset: PropTypes.bool.isRequired
|
||||
}
|
||||
|
||||
const { printServer } = useContext(PrintServerContext)
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
notification.useNotification()
|
||||
const [newPrinterLoading, setNewPrinterLoading] = useState(false)
|
||||
const [currentStep, setCurrentStep] = useState(0)
|
||||
const [nextEnabled, setNextEnabled] = useState(false)
|
||||
const [newPrinterForm] = Form.useForm()
|
||||
const [newPrinterFormValues, setNewPrinterFormValues] = useState(
|
||||
initialNewPrinterForm
|
||||
)
|
||||
const [discoveredPrinters, setDiscoveredPrinters] = useState([])
|
||||
const [discovering, setDiscovering] = useState(false)
|
||||
const [showManualSetup, setShowManualSetup] = useState(false)
|
||||
const [scanPort, setScanPort] = useState(7125)
|
||||
const [scanProtocol, setScanProtocol] = useState('ws')
|
||||
const [editingHostname, setEditingHostname] = useState(null)
|
||||
const [hostnameInput, setHostnameInput] = useState('')
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
|
||||
const newPrinterFormUpdateValues = Form.useWatch([], newPrinterForm)
|
||||
|
||||
useEffect(() => {
|
||||
newPrinterForm
|
||||
.validateFields({
|
||||
validateOnly: true
|
||||
})
|
||||
.then(() => {
|
||||
if (currentStep === 0) {
|
||||
const moonraker = newPrinterForm.getFieldValue('moonraker')
|
||||
setNextEnabled(
|
||||
!!(moonraker?.protocol && moonraker?.host && moonraker?.port)
|
||||
)
|
||||
} else if (currentStep === 1) {
|
||||
const name = newPrinterForm.getFieldValue('name')
|
||||
setNextEnabled(!!name)
|
||||
} else {
|
||||
setNextEnabled(true)
|
||||
}
|
||||
})
|
||||
.catch(() => setNextEnabled(false))
|
||||
}, [newPrinterForm, newPrinterFormUpdateValues, currentStep])
|
||||
|
||||
const summaryItems = [
|
||||
{
|
||||
key: 'name',
|
||||
label: 'Name',
|
||||
children: newPrinterFormValues.name
|
||||
},
|
||||
active: true
|
||||
{
|
||||
key: 'protocol',
|
||||
label: 'Protocol',
|
||||
children: newPrinterFormValues.moonraker?.protocol
|
||||
},
|
||||
{
|
||||
key: 'host',
|
||||
label: 'Host',
|
||||
children: newPrinterFormValues.moonraker?.host
|
||||
},
|
||||
{
|
||||
key: 'port',
|
||||
label: 'Port',
|
||||
children: newPrinterFormValues.moonraker?.port
|
||||
}
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
if (reset) {
|
||||
newPrinterForm.resetFields()
|
||||
}
|
||||
}, [reset, newPrinterForm])
|
||||
|
||||
const handlePrinterSelect = (printer) => {
|
||||
newPrinterForm.setFieldsValue({
|
||||
moonraker: {
|
||||
protocol: printer.protocol,
|
||||
host: printer.host,
|
||||
port: printer.port
|
||||
}
|
||||
})
|
||||
setNewPrinterFormValues({
|
||||
...newPrinterFormValues,
|
||||
moonraker: {
|
||||
protocol: printer.protocol,
|
||||
host: printer.host,
|
||||
port: printer.port
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleHostnameEdit = (printer, newHostname) => {
|
||||
if (newHostname && newHostname.trim() !== '') {
|
||||
const updatedPrinter = {
|
||||
...printer,
|
||||
host: newHostname.trim()
|
||||
}
|
||||
setDiscoveredPrinters((prev) =>
|
||||
prev.map((p) => (p.host === printer.host ? updatedPrinter : p))
|
||||
)
|
||||
setEditingHostname(null)
|
||||
setHostnameInput('')
|
||||
}
|
||||
}
|
||||
|
||||
const showEditHostnameDialog = (printer) => {
|
||||
setEditingHostname(printer.host)
|
||||
setHostnameInput(printer.host)
|
||||
}
|
||||
|
||||
const handleNewPrinter = async () => {
|
||||
setNewPrinterLoading(true)
|
||||
try {
|
||||
await axios.post(
|
||||
`${config.backendUrl}/printers`,
|
||||
{
|
||||
...newPrinterFormValues
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/json'
|
||||
},
|
||||
withCredentials: true
|
||||
}
|
||||
)
|
||||
|
||||
onOk()
|
||||
} catch (error) {
|
||||
messageApi.error('Error adding new printer: ' + error.message)
|
||||
} finally {
|
||||
setNewPrinterLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const notifyScanNetworkFound = useCallback(
|
||||
(data) => {
|
||||
const newPrinter = {
|
||||
protocol: scanProtocol,
|
||||
host: data.hostname || data.ip,
|
||||
port: scanPort
|
||||
}
|
||||
notificationApi.info({
|
||||
message: 'Printer Found',
|
||||
description: `Printer found: ${data.hostname || data.ip}!`
|
||||
})
|
||||
setDiscoveredPrinters((prev) => [...prev, newPrinter])
|
||||
},
|
||||
[scanProtocol, scanPort, notificationApi]
|
||||
)
|
||||
|
||||
const notifyScanNetworkComplete = useCallback(
|
||||
(data) => {
|
||||
setDiscovering(false)
|
||||
notificationApi.destroy('network-scan')
|
||||
if (data == false) {
|
||||
messageApi.error('Error discovering printers!')
|
||||
} else {
|
||||
messageApi.success('Finished discovering printers!')
|
||||
}
|
||||
},
|
||||
[messageApi, notificationApi]
|
||||
)
|
||||
|
||||
const notifyScanNetworkProgress = useCallback(
|
||||
(data) => {
|
||||
notificationApi.info({
|
||||
message: 'Scanning Network',
|
||||
description: (
|
||||
<div>
|
||||
<div style={{ marginBottom: 12 }}>
|
||||
Scanning IP: {data.currentIP}
|
||||
</div>
|
||||
<Progress
|
||||
percent={data.progress}
|
||||
size='small'
|
||||
status='active'
|
||||
showInfo={false}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
duration: 0,
|
||||
key: 'network-scan',
|
||||
icon: null,
|
||||
placement: 'bottomRight',
|
||||
style: {
|
||||
width: 360
|
||||
},
|
||||
className: 'network-scan-notification',
|
||||
closeIcon: null,
|
||||
onClose: () => {},
|
||||
btn: null
|
||||
})
|
||||
},
|
||||
[notificationApi]
|
||||
)
|
||||
|
||||
const discoverPrinters = useCallback(() => {
|
||||
if (!discovering) {
|
||||
setDiscovering(true)
|
||||
setDiscoveredPrinters([])
|
||||
messageApi.info('Discovering printers...')
|
||||
printServer.off('notify_scan_network_found')
|
||||
printServer.off('notify_scan_network_progress')
|
||||
printServer.off('notify_scan_network_complete')
|
||||
|
||||
printServer.on('notify_scan_network_found', notifyScanNetworkFound)
|
||||
printServer.on('notify_scan_network_progress', notifyScanNetworkProgress)
|
||||
printServer.on('notify_scan_network_complete', notifyScanNetworkComplete)
|
||||
|
||||
printServer.emit('bridge.scan_network.start', {
|
||||
port: scanPort,
|
||||
protocol: scanProtocol
|
||||
})
|
||||
}
|
||||
}, [
|
||||
discovering,
|
||||
printServer,
|
||||
scanPort,
|
||||
scanProtocol,
|
||||
messageApi,
|
||||
notifyScanNetworkFound,
|
||||
notifyScanNetworkProgress,
|
||||
notifyScanNetworkComplete
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
setInitialized(true)
|
||||
if (!initialized) {
|
||||
discoverPrinters()
|
||||
}
|
||||
}, [initialized, discoverPrinters])
|
||||
|
||||
const stopDiscovery = () => {
|
||||
if (discovering) {
|
||||
setDiscovering(false)
|
||||
notificationApi.destroy('network-scan')
|
||||
messageApi.info('Stopping discovery...')
|
||||
printServer.off('notify_scan_network_found')
|
||||
printServer.off('notify_scan_network_progress')
|
||||
printServer.off('notify_scan_network_complete')
|
||||
printServer.emit('bridge.scan_network.stop', (response) => {
|
||||
if (response == false) {
|
||||
messageApi.error('Error stopping discovery!')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handlePortChange = (value) => {
|
||||
stopDiscovery()
|
||||
setScanPort(value)
|
||||
}
|
||||
|
||||
const handleProtocolChange = (value) => {
|
||||
stopDiscovery()
|
||||
setScanProtocol(value)
|
||||
}
|
||||
|
||||
const steps = [
|
||||
{
|
||||
title: 'Discovery',
|
||||
key: 'discovery',
|
||||
content: (
|
||||
<>
|
||||
<Flex vertical style={{ width: '100%' }} gap='large'>
|
||||
{!showManualSetup ? (
|
||||
<>
|
||||
<Flex
|
||||
style={{ width: '100%' }}
|
||||
justify='space-between'
|
||||
align='center'
|
||||
gap='middle'
|
||||
>
|
||||
<Space.Compact>
|
||||
<InputNumber
|
||||
min={1}
|
||||
max={65535}
|
||||
value={scanPort}
|
||||
onChange={handlePortChange}
|
||||
style={{ width: '80px' }}
|
||||
placeholder='Port'
|
||||
/>
|
||||
<Select
|
||||
value={scanProtocol}
|
||||
onChange={handleProtocolChange}
|
||||
options={[
|
||||
{ value: 'ws', label: 'ws' },
|
||||
{ value: 'wss', label: 'wss' }
|
||||
]}
|
||||
/>
|
||||
<Button
|
||||
icon={<SearchOutlined />}
|
||||
onClick={discoverPrinters}
|
||||
loading={discovering}
|
||||
>
|
||||
{discovering ? 'Discovering...' : 'Discover'}
|
||||
</Button>
|
||||
</Space.Compact>
|
||||
<Button
|
||||
icon={<SettingOutlined />}
|
||||
onClick={() => setShowManualSetup(true)}
|
||||
>
|
||||
Manual Setup
|
||||
</Button>
|
||||
</Flex>
|
||||
<List
|
||||
dataSource={discoveredPrinters}
|
||||
renderItem={(printer) => (
|
||||
<List.Item
|
||||
key={`${printer.host}:${printer.port}`}
|
||||
actions={[
|
||||
<Radio
|
||||
key='select'
|
||||
defaultChecked={
|
||||
newPrinterFormValues.moonraker?.host ===
|
||||
printer.host
|
||||
}
|
||||
onChange={() => handlePrinterSelect(printer)}
|
||||
/>
|
||||
]}
|
||||
>
|
||||
<List.Item.Meta
|
||||
title={
|
||||
<Space>
|
||||
{printer.host}
|
||||
{!printer.hostname && (
|
||||
<Button
|
||||
type='text'
|
||||
icon={<EditIcon />}
|
||||
onClick={() => showEditHostnameDialog(printer)}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
}
|
||||
description={`Protocol: ${printer.protocol}, Port: ${printer.port}`}
|
||||
/>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
<Modal
|
||||
title='Edit Host'
|
||||
open={editingHostname !== null}
|
||||
onOk={() => {
|
||||
const printer = discoveredPrinters.find(
|
||||
(p) => p.host === editingHostname
|
||||
)
|
||||
if (printer) {
|
||||
handleHostnameEdit(printer, hostnameInput)
|
||||
}
|
||||
}}
|
||||
onCancel={() => {
|
||||
setEditingHostname(null)
|
||||
setHostnameInput('')
|
||||
}}
|
||||
>
|
||||
{({ handleSubmit, submitLoading, objectData, formValid }) => {
|
||||
const steps = [
|
||||
<Form.Item label='Host' required>
|
||||
<Input
|
||||
value={hostnameInput}
|
||||
onChange={(e) => setHostnameInput(e.target.value)}
|
||||
placeholder='Enter host'
|
||||
autoFocus
|
||||
/>
|
||||
</Form.Item>
|
||||
</Modal>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Flex style={{ width: '100%' }} justify='end'>
|
||||
<Button
|
||||
icon={<SearchOutlined />}
|
||||
onClick={() => setShowManualSetup(false)}
|
||||
>
|
||||
Back to Discovery
|
||||
</Button>
|
||||
</Flex>
|
||||
<Flex vertical>
|
||||
<Form.Item
|
||||
label='Protocol'
|
||||
name={['moonraker', 'protocol']}
|
||||
rules={[
|
||||
{ required: true, message: 'Protocol is required' }
|
||||
]}
|
||||
>
|
||||
<Select
|
||||
defaultValue='ws'
|
||||
options={[
|
||||
{ value: 'ws', label: 'Websocket' },
|
||||
{ value: 'wss', label: 'Websocket Secure' }
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label='Host'
|
||||
name={['moonraker', 'host']}
|
||||
rules={[{ required: true, message: 'Host is required' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label='Port'
|
||||
name={['moonraker', 'port']}
|
||||
rules={[{ required: true, message: 'Port is required' }]}
|
||||
>
|
||||
<InputNumber
|
||||
min={1}
|
||||
max={65535}
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label='API Key'
|
||||
name={['moonraker', 'apiKey']}
|
||||
rules={[{ required: false }]}
|
||||
>
|
||||
<Input.Password
|
||||
placeholder='Optional API key'
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Flex>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Required',
|
||||
key: 'required',
|
||||
content: (
|
||||
<ObjectInfo
|
||||
type='printer'
|
||||
column={1}
|
||||
bordered={false}
|
||||
isEditing={true}
|
||||
required={true}
|
||||
objectData={objectData}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Optional',
|
||||
key: 'optional',
|
||||
content: (
|
||||
<ObjectInfo
|
||||
type='printer'
|
||||
column={1}
|
||||
bordered={false}
|
||||
isEditing={true}
|
||||
required={false}
|
||||
objectData={objectData}
|
||||
visibleProperties={{
|
||||
firmware: false,
|
||||
currentFilamentStock: false,
|
||||
'currentFilamentStock._id': false,
|
||||
currentJob: false,
|
||||
'currentJob._id': false,
|
||||
currentSubJob: false,
|
||||
'currentSubJob._id': false,
|
||||
alerts: false
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<Form.Item
|
||||
label='Name'
|
||||
name='name'
|
||||
rules={[{ required: true, message: 'Name is required' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: 'Summary',
|
||||
key: 'summary',
|
||||
content: (
|
||||
<ObjectInfo
|
||||
type='printer'
|
||||
column={1}
|
||||
bordered={false}
|
||||
visibleProperties={{
|
||||
_id: false,
|
||||
createdAt: false,
|
||||
updatedAt: false,
|
||||
connectedAt: false,
|
||||
state: false,
|
||||
firmware: false,
|
||||
currentFilamentStock: false,
|
||||
'currentFilamentStock._id': false,
|
||||
currentJob: false,
|
||||
'currentJob._id': false,
|
||||
currentSubJob: false,
|
||||
'currentSubJob._id': false,
|
||||
alerts: false
|
||||
}}
|
||||
isEditing={false}
|
||||
objectData={objectData}
|
||||
/>
|
||||
<Form.Item>
|
||||
<Descriptions column={1} items={summaryItems} size={'small'} />
|
||||
</Form.Item>
|
||||
)
|
||||
}
|
||||
]
|
||||
return (
|
||||
<WizardView
|
||||
steps={steps}
|
||||
loading={submitLoading}
|
||||
formValid={formValid}
|
||||
title='New Printer'
|
||||
onSubmit={() => {
|
||||
handleSubmit()
|
||||
onOk()
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
</NewObjectForm>
|
||||
)
|
||||
}
|
||||
|
||||
NewPrinter.propTypes = {
|
||||
onOk: PropTypes.func.isRequired,
|
||||
reset: PropTypes.bool
|
||||
return (
|
||||
<Flex gap={'middle'}>
|
||||
{contextHolder}
|
||||
{notificationContextHolder}
|
||||
|
||||
<div style={{ minWidth: '160px' }}>
|
||||
<Steps current={currentStep} items={steps} direction='vertical' />
|
||||
</div>
|
||||
|
||||
<Divider type={'vertical'} style={{ height: 'unset' }} />
|
||||
|
||||
<Flex vertical={'true'} style={{ flexGrow: 1 }}>
|
||||
<Title level={2} style={{ marginTop: 0 }}>
|
||||
New Printer
|
||||
</Title>
|
||||
<Form
|
||||
name='basic'
|
||||
autoComplete='off'
|
||||
form={newPrinterForm}
|
||||
onFinish={handleNewPrinter}
|
||||
onValuesChange={(changedValues) =>
|
||||
setNewPrinterFormValues((prevValues) => ({
|
||||
...prevValues,
|
||||
...changedValues
|
||||
}))
|
||||
}
|
||||
initialValues={initialNewPrinterForm}
|
||||
>
|
||||
<div style={{ minHeight: '260px' }}>{steps[currentStep].content}</div>
|
||||
|
||||
<Flex justify={'end'}>
|
||||
<Button
|
||||
style={{
|
||||
margin: '0 8px'
|
||||
}}
|
||||
onClick={() => setCurrentStep(currentStep - 1)}
|
||||
disabled={!(currentStep > 0)}
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
{currentStep < steps.length - 1 && (
|
||||
<Button
|
||||
type='primary'
|
||||
disabled={!nextEnabled}
|
||||
onClick={() => {
|
||||
setCurrentStep(currentStep + 1)
|
||||
}}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
)}
|
||||
{currentStep === steps.length - 1 && (
|
||||
<Button
|
||||
type='primary'
|
||||
htmlType='submit'
|
||||
loading={newPrinterLoading}
|
||||
>
|
||||
Done
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
</Form>
|
||||
</Flex>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewPrinter
|
||||
|
||||
@ -19,7 +19,6 @@ import ActionHandler from '../../common/ActionHandler.jsx'
|
||||
import ObjectActions from '../../common/ObjectActions.jsx'
|
||||
import ObjectTable from '../../common/ObjectTable.jsx'
|
||||
import InfoCollapsePlaceholder from '../../common/InfoCollapsePlaceholder.jsx'
|
||||
import DocumentPrintButton from '../../common/DocumentPrintButton.jsx'
|
||||
|
||||
const log = loglevel.getLogger('PrinterInfo')
|
||||
log.setLevel(config.logLevel)
|
||||
@ -41,8 +40,7 @@ const PrinterInfo = () => {
|
||||
editLoading: false,
|
||||
formValid: false,
|
||||
locked: false,
|
||||
loading: false,
|
||||
objectData: {}
|
||||
loading: false
|
||||
})
|
||||
|
||||
const actions = {
|
||||
@ -82,7 +80,6 @@ const PrinterInfo = () => {
|
||||
type='printer'
|
||||
id={printerId}
|
||||
disabled={objectFormState.loading}
|
||||
objectData={objectFormState.objectData}
|
||||
/>
|
||||
<ViewButton
|
||||
disabled={objectFormState.loading}
|
||||
@ -94,11 +91,6 @@ const PrinterInfo = () => {
|
||||
visibleState={collapseState}
|
||||
updateVisibleState={updateCollapseState}
|
||||
/>
|
||||
<DocumentPrintButton
|
||||
type='printer'
|
||||
objectData={objectFormState.objectData}
|
||||
disabled={objectFormState.loading}
|
||||
/>
|
||||
</Space>
|
||||
<LockIndicator lock={objectFormState.lock} />
|
||||
</Space>
|
||||
@ -154,15 +146,6 @@ const PrinterInfo = () => {
|
||||
isEditing={isEditing}
|
||||
type='printer'
|
||||
objectData={objectData}
|
||||
visibleProperties={{
|
||||
currentFilamentStock: false,
|
||||
'currentFilamentStock._id': false,
|
||||
currentJob: false,
|
||||
'currentJob._id': false,
|
||||
currentSubJob: false,
|
||||
'currentSubJob._id': false,
|
||||
alerts: false
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { Flex, Alert } from 'antd'
|
||||
import ExclamationOctagonIcon from '../../Icons/ExclamationOctagonIcon'
|
||||
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
||||
|
||||
const AlertsDisplay = ({ alerts = [] }) => {
|
||||
const getAlertType = (type, priority) => {
|
||||
if (type === 'error' || priority === '9') return 'error'
|
||||
if (type === 'warning' || priority === '8') return 'warning'
|
||||
return 'info'
|
||||
}
|
||||
|
||||
const getAlertIcon = (type, priority) => {
|
||||
if (type === 'error' || priority === '9') return <ExclamationOctagonIcon />
|
||||
if (type === 'warning' || priority === '8')
|
||||
return <ExclamationOctagonIcon />
|
||||
return <InfoCircleIcon />
|
||||
}
|
||||
|
||||
if (alerts.length == 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex gap='small'>
|
||||
{alerts.map((alert, index) => (
|
||||
<Alert
|
||||
key={`${alert.createdAt}-${index}`}
|
||||
message={alert.message}
|
||||
style={{ padding: '4px 10px 4px 8px' }}
|
||||
type={getAlertType(alert.type, alert.priority)}
|
||||
icon={getAlertIcon(alert.type, alert.priority)}
|
||||
showIcon
|
||||
/>
|
||||
))}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
AlertsDisplay.propTypes = {
|
||||
alerts: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
priority: PropTypes.string.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
createdAt: PropTypes.string.isRequired,
|
||||
updatedAt: PropTypes.string.isRequired,
|
||||
message: PropTypes.string.isRequired
|
||||
})
|
||||
).isRequired
|
||||
}
|
||||
|
||||
export default AlertsDisplay
|
||||
@ -1,136 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import { useState, useEffect, useContext } from 'react'
|
||||
// import { getModelByName } from '../../../database/ObjectModels'
|
||||
import DocumentPrinterIcon from '../../Icons/DocumentPrinterIcon'
|
||||
import { Button, Dropdown, Modal } from 'antd'
|
||||
import { ApiServerContext } from '../context/ApiServerContext'
|
||||
import DocumentTemplateIcon from '../../Icons/DocumentTemplateIcon'
|
||||
import NewDocumentJob from '../Management/DocumentJobs/NewDocumentJob'
|
||||
import { message } from 'antd'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
|
||||
const DocumentPrintButton = ({
|
||||
type,
|
||||
objectData,
|
||||
disabled = false,
|
||||
...buttonProps
|
||||
}) => {
|
||||
const { fetchObjects } = useContext(ApiServerContext)
|
||||
const [documentTemplates, setDocumentTemplates] = useState([])
|
||||
const [currentDocumentTemplate, setCurrentDocumentTemplate] = useState(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [messageApi, contextHolder] = message.useMessage()
|
||||
const [newDocumentJobOpen, setNewDocumentJobOpen] = useState(false)
|
||||
|
||||
const { token } = useContext(AuthContext)
|
||||
|
||||
// Get the model by name
|
||||
//const model = getModelByName(type)
|
||||
|
||||
// Fetch document templates when component mounts or type changes
|
||||
useEffect(() => {
|
||||
const loadDocumentTemplates = async () => {
|
||||
if (!type || token == null) return
|
||||
|
||||
setLoading(true)
|
||||
try {
|
||||
const result = await fetchObjects('documentTemplate', {
|
||||
filter: {
|
||||
objectType: type,
|
||||
global: false,
|
||||
active: true
|
||||
},
|
||||
limit: 100 // Get more templates to show in dropdown
|
||||
})
|
||||
|
||||
if (result && result.data) {
|
||||
setDocumentTemplates(result.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching document templates:', error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
loadDocumentTemplates()
|
||||
}, [type, fetchObjects, token])
|
||||
|
||||
// Handle template selection
|
||||
const handleTemplateSelect = (template) => {
|
||||
setCurrentDocumentTemplate(template)
|
||||
setNewDocumentJobOpen(true)
|
||||
// TODO: Implement the actual printing logic here
|
||||
// This could open a print dialog, navigate to a print page, etc.
|
||||
}
|
||||
|
||||
// Create dropdown menu items
|
||||
const menuItems = documentTemplates.map((template) => ({
|
||||
key: template._id,
|
||||
label: template.name,
|
||||
icon: <DocumentTemplateIcon />,
|
||||
onClick: () => handleTemplateSelect(template)
|
||||
}))
|
||||
|
||||
// If no templates available, show disabled state
|
||||
if (documentTemplates.length === 0 && !loading) {
|
||||
return (
|
||||
<Button
|
||||
{...buttonProps}
|
||||
icon={<DocumentPrinterIcon />}
|
||||
disabled={true}
|
||||
title='No document templates available for this object type'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextHolder}
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: menuItems,
|
||||
loading: loading
|
||||
}}
|
||||
trigger={['hover']}
|
||||
disabled={disabled || loading}
|
||||
>
|
||||
<Button
|
||||
{...buttonProps}
|
||||
icon={<DocumentPrinterIcon />}
|
||||
disabled={disabled || loading}
|
||||
loading={loading}
|
||||
title={loading ? 'Loading templates...' : 'Print document'}
|
||||
/>
|
||||
</Dropdown>
|
||||
<Modal
|
||||
open={newDocumentJobOpen}
|
||||
onCancel={() => setNewDocumentJobOpen(false)}
|
||||
footer={null}
|
||||
destroyOnHidden={true}
|
||||
width={900}
|
||||
>
|
||||
<NewDocumentJob
|
||||
onOk={() => {
|
||||
setNewDocumentJobOpen(false)
|
||||
messageApi.success('New document job created successfully.')
|
||||
}}
|
||||
reset={!newDocumentJobOpen}
|
||||
defaultValues={{
|
||||
objectType: type,
|
||||
object: objectData,
|
||||
documentTemplate: currentDocumentTemplate
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
DocumentPrintButton.propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
objectData: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
export default DocumentPrintButton
|
||||
@ -2,7 +2,6 @@ import { useState, useEffect, useContext } from 'react'
|
||||
import { Form, message } from 'antd'
|
||||
import { ApiServerContext } from '../context/ApiServerContext'
|
||||
import PropTypes from 'prop-types'
|
||||
import merge from 'lodash/merge'
|
||||
|
||||
/**
|
||||
* NewObjectForm is a reusable form component for creating new objects.
|
||||
@ -67,9 +66,7 @@ const NewObjectForm = ({ type, style, defaultValues = {}, children }) => {
|
||||
layout='vertical'
|
||||
style={style}
|
||||
onValuesChange={(values) => {
|
||||
setObjectData((prev) => {
|
||||
return merge({}, prev, values)
|
||||
})
|
||||
setObjectData((prev) => ({ ...prev, ...values }))
|
||||
}}
|
||||
>
|
||||
{contextHolder}
|
||||
|
||||
@ -39,8 +39,7 @@ import CheckIcon from '../../Icons/CheckIcon'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import QuestionCircleIcon from '../../Icons/QuestionCircleIcon'
|
||||
import { AuthContext } from '../context/AuthContext'
|
||||
import { ElectronContext } from '../context/ElectronContext'
|
||||
|
||||
import unionBy from 'lodash/unionBy'
|
||||
const logger = loglevel.getLogger('DasboardTable')
|
||||
logger.setLevel(config.logLevel)
|
||||
|
||||
@ -59,7 +58,6 @@ const ObjectTable = forwardRef(
|
||||
ref
|
||||
) => {
|
||||
const { token } = useContext(AuthContext)
|
||||
const { isElectron } = useContext(ElectronContext)
|
||||
const {
|
||||
fetchObjects,
|
||||
connected,
|
||||
@ -75,15 +73,6 @@ const ObjectTable = forwardRef(
|
||||
if (cards) {
|
||||
adjustedScrollHeight = 'calc(var(--unit-100vh) - 280px)'
|
||||
}
|
||||
if (isElectron) {
|
||||
adjustedScrollHeight = 'calc(var(--unit-100vh) - 244px)'
|
||||
}
|
||||
if (isMobile && isElectron) {
|
||||
adjustedScrollHeight = 'calc(var(--unit-100vh) - 282px)'
|
||||
}
|
||||
if (cards && isElectron) {
|
||||
adjustedScrollHeight = 'calc(var(--unit-100vh) - 260px)'
|
||||
}
|
||||
const [, contextHolder] = message.useMessage()
|
||||
const tableRef = useRef(null)
|
||||
const model = getModelByName(type)
|
||||
@ -119,16 +108,7 @@ const ObjectTable = forwardRef(
|
||||
const renderActions = (objectData) => {
|
||||
return (
|
||||
<Flex gap='small' align='center' justify='center'>
|
||||
{rowActions.map((action, index) => {
|
||||
var disabled = false
|
||||
if (action.disabled) {
|
||||
if (typeof action.disabled === 'function') {
|
||||
disabled = action.disabled(objectData)
|
||||
} else {
|
||||
disabled = action.disabled
|
||||
}
|
||||
}
|
||||
return (
|
||||
{rowActions.map((action, index) => (
|
||||
<Tooltip key={index} title={action.label} arrow={false}>
|
||||
<Button
|
||||
icon={
|
||||
@ -138,7 +118,6 @@ const ObjectTable = forwardRef(
|
||||
<QuestionCircleIcon />
|
||||
)
|
||||
}
|
||||
disabled={disabled}
|
||||
type={'text'}
|
||||
size={'small'}
|
||||
onClick={() => {
|
||||
@ -148,8 +127,7 @@ const ObjectTable = forwardRef(
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
})}
|
||||
))}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
@ -225,6 +203,8 @@ const ObjectTable = forwardRef(
|
||||
const loadNextPage = useCallback(() => {
|
||||
const highestPage = Math.max(...pages.map((p) => p.pageNum))
|
||||
const nextPage = highestPage + 1
|
||||
logger.debug('Next page', nextPage)
|
||||
|
||||
if (hasMore) {
|
||||
setPages((prev) => {
|
||||
const filteredPages = prev.map((page) => ({
|
||||
@ -301,6 +281,7 @@ const ObjectTable = forwardRef(
|
||||
|
||||
const reload = useCallback(async () => {
|
||||
setLazyLoading(true)
|
||||
console.log('Pages during reload', pagesRef.current)
|
||||
for (let i = 0; i < pagesRef.current.length; i++) {
|
||||
const page = pagesRef.current[i]
|
||||
await fetchData(page.pageNum)
|
||||
@ -309,14 +290,14 @@ const ObjectTable = forwardRef(
|
||||
|
||||
// Update event handler for real-time updates
|
||||
const updateEventHandler = useCallback((id, updatedData) => {
|
||||
console.log('GOT UPDATE FOR', id)
|
||||
setPages((prevPages) =>
|
||||
prevPages.map((page) => {
|
||||
const updatedItems = page.items.map((item) => {
|
||||
if (item._id === id) {
|
||||
return { ...item, ...updatedData }
|
||||
}
|
||||
return item
|
||||
})
|
||||
const updatedItems = unionBy(
|
||||
[{ ...updatedData, _id: id }],
|
||||
page.items,
|
||||
'_id'
|
||||
)
|
||||
return {
|
||||
...page,
|
||||
items: updatedItems
|
||||
@ -329,6 +310,7 @@ const ObjectTable = forwardRef(
|
||||
updateEventHandlerRef.current = updateEventHandler
|
||||
|
||||
const newEventHandler = useCallback(() => {
|
||||
console.log('GOT NEW EVENT')
|
||||
reload()
|
||||
}, [reload])
|
||||
|
||||
@ -349,6 +331,7 @@ const ObjectTable = forwardRef(
|
||||
|
||||
// Subscribe to new items only
|
||||
newItemIds.forEach((itemId) => {
|
||||
console.log('SUB', itemId)
|
||||
const unsubscribe = subscribeToObjectUpdates(
|
||||
itemId,
|
||||
type,
|
||||
@ -374,6 +357,7 @@ const ObjectTable = forwardRef(
|
||||
subscribedIdsRef.current.splice(index, 1)
|
||||
const unsubscribe = unsubscribesRef.current[index]
|
||||
if (unsubscribe) {
|
||||
console.log('UNSUB', itemId)
|
||||
unsubscribe()
|
||||
}
|
||||
unsubscribesRef.current.splice(index, 1)
|
||||
@ -385,9 +369,12 @@ const ObjectTable = forwardRef(
|
||||
// Cleanup effect for component unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
console.log('API: Call unsub', connected)
|
||||
if (connected == true && unsubscribesRef.current) {
|
||||
console.log('API: Got object unsub')
|
||||
// Clean up all subscriptions when component unmounts
|
||||
unsubscribesRef.current.forEach((unsubscribe) => {
|
||||
console.log('CALLING UNSUB on unmount')
|
||||
if (unsubscribe) unsubscribe()
|
||||
})
|
||||
unsubscribesRef.current = []
|
||||
@ -396,6 +383,8 @@ const ObjectTable = forwardRef(
|
||||
// Clean up type subscription
|
||||
}
|
||||
if (connected == true && subscribeToObjectTypeUpdatesRef.current) {
|
||||
console.log('UNSUBBING type subscription on unmount')
|
||||
console.log('API: Got type unsub')
|
||||
subscribeToObjectTypeUpdatesRef.current()
|
||||
subscribeToObjectTypeUpdatesRef.current = null
|
||||
}
|
||||
@ -407,6 +396,10 @@ const ObjectTable = forwardRef(
|
||||
connected == true &&
|
||||
subscribeToObjectTypeUpdatesRef.current == null
|
||||
) {
|
||||
console.log(
|
||||
'API: Subbing to updates',
|
||||
subscribeToObjectTypeUpdatesRef.current
|
||||
)
|
||||
subscribeToObjectTypeUpdatesRef.current = subscribeToObjectTypeUpdates(
|
||||
type,
|
||||
newEventHandler
|
||||
@ -528,6 +521,7 @@ const ObjectTable = forwardRef(
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
console.log('Pages', pages)
|
||||
pagesRef.current = pages
|
||||
}, [pages])
|
||||
// Add columns in the order specified by model.columns
|
||||
@ -771,7 +765,6 @@ const ObjectTable = forwardRef(
|
||||
onChange={handleTableChange}
|
||||
showSorterTooltip={false}
|
||||
style={{ height: '100%' }}
|
||||
size={isElectron ? 'small' : 'middle'}
|
||||
/>
|
||||
{cards ? (
|
||||
<Spin indicator={<LoadingOutlined />} spinning={loading}>
|
||||
|
||||
@ -24,16 +24,6 @@ import config from '../../../config'
|
||||
import loglevel from 'loglevel'
|
||||
import { ElectronContext } from './ElectronContext'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import {
|
||||
getAuthCookies,
|
||||
setAuthCookies,
|
||||
clearAuthCookies,
|
||||
areCookiesEnabled,
|
||||
validateAuthCookies,
|
||||
setupCookieSync,
|
||||
checkAuthCookiesExpiry
|
||||
} from '../../../utils/cookies'
|
||||
|
||||
const logger = loglevel.getLogger('ApiServerContext')
|
||||
logger.setLevel(config.logLevel)
|
||||
|
||||
@ -47,7 +37,7 @@ const AuthProvider = ({ children }) => {
|
||||
notification.useNotification()
|
||||
const [authenticated, setAuthenticated] = useState(false)
|
||||
const [initialized, setInitialized] = useState(false)
|
||||
const [retreivedTokenFromCookies, setRetreivedTokenFromCookies] =
|
||||
const [retreivedTokenFromSession, setRetreivedTokenFromSession] =
|
||||
useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [token, setToken] = useState(null)
|
||||
@ -70,32 +60,13 @@ const AuthProvider = ({ children }) => {
|
||||
if (isElectron == true && import.meta.env.MODE != 'development') {
|
||||
redirectType = 'app-scheme'
|
||||
}
|
||||
|
||||
// Check if cookies are enabled and show warning if not
|
||||
// Read token from session storage if present
|
||||
useEffect(() => {
|
||||
if (!areCookiesEnabled()) {
|
||||
messageApi.warning(
|
||||
'Cookies are disabled. Login state may not persist between tabs.'
|
||||
)
|
||||
}
|
||||
}, [messageApi])
|
||||
|
||||
// Read token from cookies if present
|
||||
useEffect(() => {
|
||||
try {
|
||||
// First validate existing cookies to clean up expired ones
|
||||
if (validateAuthCookies()) {
|
||||
const {
|
||||
token: storedToken,
|
||||
expiresAt: storedExpiresAt,
|
||||
user: storedUser
|
||||
} = getAuthCookies()
|
||||
console.log('Retrieved from cookies:', {
|
||||
storedUser,
|
||||
storedToken,
|
||||
storedExpiresAt
|
||||
})
|
||||
|
||||
const storedToken = sessionStorage.getItem('authToken')
|
||||
const storedUser = JSON.parse(sessionStorage.getItem('user'))
|
||||
const storedExpiresAt = sessionStorage.getItem('authExpiresAt')
|
||||
console.log('stored user', storedUser, storedToken)
|
||||
if (storedToken && storedExpiresAt && storedUser) {
|
||||
setToken(storedToken)
|
||||
setUserProfile(storedUser)
|
||||
setExpiresAt(storedExpiresAt)
|
||||
@ -105,63 +76,17 @@ const AuthProvider = ({ children }) => {
|
||||
setUserProfile(null)
|
||||
setShowUnauthorizedModal(true)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reading auth cookies:', error)
|
||||
clearAuthCookies()
|
||||
setAuthenticated(false)
|
||||
setUserProfile(null)
|
||||
setShowUnauthorizedModal(true)
|
||||
}
|
||||
setRetreivedTokenFromCookies(true)
|
||||
setRetreivedTokenFromSession(true)
|
||||
}, [])
|
||||
|
||||
// Set up cookie synchronization between tabs
|
||||
useEffect(() => {
|
||||
const cleanupCookieSync = setupCookieSync(() => {
|
||||
// When cookies change in another tab, re-validate and update state
|
||||
try {
|
||||
if (validateAuthCookies()) {
|
||||
const {
|
||||
token: newToken,
|
||||
expiresAt: newExpiresAt,
|
||||
user: newUser
|
||||
} = getAuthCookies()
|
||||
if (
|
||||
newToken !== token ||
|
||||
newExpiresAt !== expiresAt ||
|
||||
JSON.stringify(newUser) !== JSON.stringify(userProfile)
|
||||
) {
|
||||
setToken(newToken)
|
||||
setExpiresAt(newExpiresAt)
|
||||
setUserProfile(newUser)
|
||||
setAuthenticated(true)
|
||||
console.log('Auth state synchronized from another tab')
|
||||
}
|
||||
} else {
|
||||
// Cookies are invalid, clear state
|
||||
setToken(null)
|
||||
setExpiresAt(null)
|
||||
setUserProfile(null)
|
||||
setAuthenticated(false)
|
||||
setShowUnauthorizedModal(true)
|
||||
console.log(
|
||||
'Auth state cleared due to invalid cookies from another tab'
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error syncing auth state:', error)
|
||||
}
|
||||
})
|
||||
|
||||
return cleanupCookieSync
|
||||
}, [token, expiresAt, userProfile])
|
||||
|
||||
const logout = useCallback((redirectUri = '/login') => {
|
||||
setAuthenticated(false)
|
||||
setToken(null)
|
||||
setExpiresAt(null)
|
||||
setUserProfile(null)
|
||||
clearAuthCookies()
|
||||
sessionStorage.removeItem('authToken')
|
||||
sessionStorage.removeItem('authExpiresAt')
|
||||
sessionStorage.removeItem('user')
|
||||
window.location.href = `${config.backendUrl}/auth/logout?redirect_uri=${encodeURIComponent(redirectUri)}`
|
||||
}, [])
|
||||
|
||||
@ -203,20 +128,18 @@ const AuthProvider = ({ children }) => {
|
||||
|
||||
if (response.status === 200 && response.data) {
|
||||
logger.debug('Got auth token!')
|
||||
const authData = response.data
|
||||
|
||||
setToken(authData.access_token)
|
||||
setExpiresAt(authData.expires_at)
|
||||
setUserProfile(authData)
|
||||
|
||||
// Store in cookies for persistence between tabs
|
||||
const cookieSuccess = setAuthCookies(authData)
|
||||
if (!cookieSuccess) {
|
||||
messageApi.warning(
|
||||
'Authentication successful but failed to save login state. You may need to log in again if you close this tab.'
|
||||
)
|
||||
setToken(response.data.access_token)
|
||||
setExpiresAt(response.data.expires_at)
|
||||
setUserProfile(response.data)
|
||||
sessionStorage.setItem('authToken', response.data.access_token)
|
||||
sessionStorage.setItem('authExpiresAt', response.data.expires_at)
|
||||
const userObject = {
|
||||
...response.data,
|
||||
access_token: undefined,
|
||||
refresh_token: undefined,
|
||||
id_token: undefined
|
||||
}
|
||||
|
||||
sessionStorage.setItem('user', JSON.stringify(userObject))
|
||||
const searchParams = new URLSearchParams(location.search)
|
||||
searchParams.delete('authCode')
|
||||
const newSearch = searchParams.toString()
|
||||
@ -244,9 +167,8 @@ const AuthProvider = ({ children }) => {
|
||||
setLoading(false)
|
||||
}
|
||||
},
|
||||
[isElectron, navigate, location.search, location.pathname, messageApi]
|
||||
[isElectron]
|
||||
)
|
||||
|
||||
// Function to check if the user is logged in
|
||||
const checkAuthStatus = useCallback(async () => {
|
||||
setLoading(true)
|
||||
@ -261,19 +183,12 @@ const AuthProvider = ({ children }) => {
|
||||
|
||||
if (response.status === 200 && response.data) {
|
||||
logger.debug('Got auth token!')
|
||||
const authData = response.data
|
||||
|
||||
setToken(authData.access_token)
|
||||
setExpiresAt(authData.expires_at)
|
||||
setUserProfile(authData)
|
||||
|
||||
// Update cookies with fresh data
|
||||
const cookieSuccess = setAuthCookies(authData)
|
||||
if (!cookieSuccess) {
|
||||
messageApi.warning(
|
||||
'Failed to update login state. You may need to log in again if you close this tab.'
|
||||
)
|
||||
}
|
||||
setToken(response.data.access_token)
|
||||
setExpiresAt(response.data.expires_at)
|
||||
setUserProfile(response.data)
|
||||
sessionStorage.setItem('authToken', response.data.access_token)
|
||||
sessionStorage.setItem('authExpiresAt', response.data.expires_at)
|
||||
sessionStorage.setItem('user', response.data)
|
||||
} else {
|
||||
setAuthenticated(false)
|
||||
setAuthError('Failed to authenticate user.')
|
||||
@ -291,13 +206,15 @@ const AuthProvider = ({ children }) => {
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [token, messageApi])
|
||||
}, [token])
|
||||
|
||||
const setUnauthenticated = () => {
|
||||
setToken(null)
|
||||
setExpiresAt(null)
|
||||
setUserProfile(null)
|
||||
clearAuthCookies()
|
||||
sessionStorage.removeItem('authToken')
|
||||
sessionStorage.removeItem('authExpiresAt')
|
||||
sessionStorage.removeItem('user')
|
||||
setShowUnauthorizedModal(true)
|
||||
}
|
||||
|
||||
@ -310,23 +227,15 @@ const AuthProvider = ({ children }) => {
|
||||
}
|
||||
})
|
||||
if (response.status === 200 && response.data) {
|
||||
const authData = response.data
|
||||
|
||||
setToken(authData.access_token)
|
||||
setExpiresAt(authData.expires_at)
|
||||
|
||||
// Update cookies with fresh token data
|
||||
const cookieSuccess = setAuthCookies(authData)
|
||||
if (!cookieSuccess) {
|
||||
messageApi.warning(
|
||||
'Failed to update login state. You may need to log in again if you close this tab.'
|
||||
)
|
||||
}
|
||||
setToken(response.data.access_token)
|
||||
setExpiresAt(response.data.expires_at)
|
||||
sessionStorage.setItem('authToken', response.data.access_token)
|
||||
sessionStorage.setItem('authExpiresAt', response.data.expires_at)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Token refresh failed', error)
|
||||
}
|
||||
}, [token, messageApi])
|
||||
}, [token])
|
||||
|
||||
const handleSessionExpiredModalOk = () => {
|
||||
setShowSessionExpiredModal(false)
|
||||
@ -406,55 +315,6 @@ const AuthProvider = ({ children }) => {
|
||||
notificationApi.destroy('token-expiration')
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check cookies directly if expiresAt is not set in state
|
||||
const expiryInfo = checkAuthCookiesExpiry(5) // Check if expiring within 5 minutes
|
||||
if (expiryInfo.isExpiringSoon && expiryInfo.minutesRemaining <= 1) {
|
||||
// Show notification for cookies expiring soon
|
||||
const seconds = Math.floor((expiryInfo.timeRemaining % 60000) / 1000)
|
||||
const totalSeconds = 60
|
||||
const remainingSeconds = totalSeconds - seconds
|
||||
const progress = (remainingSeconds / totalSeconds) * 100
|
||||
|
||||
notificationApi.info({
|
||||
message: 'Session Expiring Soon',
|
||||
description: (
|
||||
<div>
|
||||
<div style={{ marginBottom: 8 }}>
|
||||
Your session will expire in {seconds} seconds
|
||||
</div>
|
||||
<Progress
|
||||
percent={progress}
|
||||
size='small'
|
||||
status='active'
|
||||
showInfo={false}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
duration: 0,
|
||||
key: 'token-expiration',
|
||||
icon: null,
|
||||
placement: 'bottomRight',
|
||||
style: {
|
||||
width: 360
|
||||
},
|
||||
className: 'token-expiration-notification',
|
||||
closeIcon: null,
|
||||
onClose: () => {},
|
||||
btn: (
|
||||
<Button
|
||||
type='primary'
|
||||
size='small'
|
||||
onClick={() => {
|
||||
notificationApi.destroy('token-expiration')
|
||||
refreshToken()
|
||||
}}
|
||||
>
|
||||
Reload Session
|
||||
</Button>
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,12 +335,12 @@ const AuthProvider = ({ children }) => {
|
||||
getLoginToken(authCode)
|
||||
} else if (
|
||||
token == null &&
|
||||
retreivedTokenFromCookies == true &&
|
||||
retreivedTokenFromSession == true &&
|
||||
initialized == false &&
|
||||
authCode == null
|
||||
) {
|
||||
setInitialized(true)
|
||||
console.log('Showing unauth', token, authCode)
|
||||
console.log('Showing unauth')
|
||||
setShowUnauthorizedModal(true)
|
||||
setAuthenticated(false)
|
||||
}
|
||||
@ -492,7 +352,7 @@ const AuthProvider = ({ children }) => {
|
||||
location.pathname,
|
||||
navigate,
|
||||
token,
|
||||
retreivedTokenFromCookies
|
||||
retreivedTokenFromSession
|
||||
])
|
||||
|
||||
return (
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
import Icon from '@ant-design/icons'
|
||||
import CustomIconSvg from '../../../assets/icons/documentjobicon.svg?react'
|
||||
|
||||
const DocumentJobIcon = (props) => <Icon component={CustomIconSvg} {...props} />
|
||||
|
||||
export default DocumentJobIcon
|
||||
@ -1,6 +0,0 @@
|
||||
import Icon from '@ant-design/icons'
|
||||
import CustomIconSvg from '../../../assets/icons/fileicon.svg?react'
|
||||
|
||||
const FileIcon = (props) => <Icon component={CustomIconSvg} {...props} />
|
||||
|
||||
export default FileIcon
|
||||
@ -1,119 +0,0 @@
|
||||
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
|
||||
import ReloadIcon from '../../components/Icons/ReloadIcon'
|
||||
import EditIcon from '../../components/Icons/EditIcon'
|
||||
import DocumentJobIcon from '../../components/Icons/DocumentJobIcon'
|
||||
|
||||
export const DocumentJob = {
|
||||
name: 'documentJob',
|
||||
label: 'Document Job',
|
||||
prefix: 'DSZ',
|
||||
icon: DocumentJobIcon,
|
||||
actions: [
|
||||
{
|
||||
name: 'info',
|
||||
label: 'Info',
|
||||
default: true,
|
||||
row: true,
|
||||
icon: InfoCircleIcon,
|
||||
url: (_id) =>
|
||||
`/dashboard/management/documentjobs/info?documentJobId=${_id}`
|
||||
},
|
||||
|
||||
{
|
||||
name: 'reload',
|
||||
label: 'Reload',
|
||||
icon: ReloadIcon,
|
||||
url: (_id) =>
|
||||
`/dashboard/management/documentjobs/info?documentJobId=${_id}&action=reload`
|
||||
},
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
row: true,
|
||||
icon: EditIcon,
|
||||
url: (_id) =>
|
||||
`/dashboard/management/documentjobs/info?documentJobId=${_id}&action=edit`
|
||||
}
|
||||
],
|
||||
columns: ['name', '_id', 'width', 'height', 'createdAt', 'updatedAt'],
|
||||
filters: ['name', '_id', 'width', 'height'],
|
||||
sorters: ['name', 'width', 'height', 'createdAt', 'updatedAt'],
|
||||
properties: [
|
||||
{
|
||||
name: '_id',
|
||||
label: 'ID',
|
||||
type: 'id',
|
||||
objectType: 'documentJob',
|
||||
showCopy: true
|
||||
},
|
||||
{
|
||||
name: 'createdAt',
|
||||
label: 'Created At',
|
||||
type: 'dateTime',
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
required: true,
|
||||
type: 'text',
|
||||
columnWidth: 200,
|
||||
columnFixed: 'left',
|
||||
value: (objectData) => {
|
||||
return `${objectData?.documentTemplate?.name || 'No template'} (${objectData?.object?.name || 'No name'})`
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'updatedAt',
|
||||
label: 'Updated At',
|
||||
type: 'dateTime',
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'objectType',
|
||||
label: 'Object Type',
|
||||
required: true,
|
||||
columnWidth: 150,
|
||||
type: 'objectType'
|
||||
},
|
||||
{
|
||||
name: 'object',
|
||||
label: 'Object',
|
||||
required: true,
|
||||
columnWidth: 150,
|
||||
type: 'object',
|
||||
objectType: (objectData) => {
|
||||
return objectData?.objectType
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'documentTemplate',
|
||||
label: 'Template',
|
||||
required: true,
|
||||
columnWidth: 150,
|
||||
type: 'object',
|
||||
objectType: 'documentTemplate',
|
||||
masterFilter: (objectData) => {
|
||||
return {
|
||||
active: true,
|
||||
global: false,
|
||||
objectType: objectData.objectType
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'documentPrinter',
|
||||
label: 'Printer',
|
||||
required: true,
|
||||
columnWidth: 150,
|
||||
type: 'object',
|
||||
objectType: 'documentPrinter',
|
||||
masterFilter: () => {
|
||||
return {
|
||||
active: true,
|
||||
online: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,119 +0,0 @@
|
||||
import FileIcon from '../../components/Icons/FileIcon'
|
||||
import InfoCircleIcon from '../../components/Icons/InfoCircleIcon'
|
||||
import EditIcon from '../../components/Icons/EditIcon'
|
||||
import ReloadIcon from '../../components/Icons/ReloadIcon'
|
||||
import BinIcon from '../../components/Icons/BinIcon'
|
||||
|
||||
export const File = {
|
||||
name: 'file',
|
||||
label: 'File',
|
||||
prefix: 'VEN',
|
||||
icon: FileIcon,
|
||||
actions: [
|
||||
{
|
||||
name: 'info',
|
||||
label: 'Info',
|
||||
default: true,
|
||||
row: true,
|
||||
icon: InfoCircleIcon,
|
||||
url: (_id) => `/dashboard/management/files/info?fileId=${_id}`
|
||||
},
|
||||
{
|
||||
name: 'reload',
|
||||
label: 'Reload',
|
||||
icon: ReloadIcon,
|
||||
url: (_id) =>
|
||||
`/dashboard/management/files/info?fileId=${_id}&action=reload`
|
||||
},
|
||||
{
|
||||
name: 'edit',
|
||||
label: 'Edit',
|
||||
row: true,
|
||||
icon: EditIcon,
|
||||
url: (_id) => `/dashboard/management/files/info?fileId=${_id}&action=edit`
|
||||
},
|
||||
{ type: 'divider' },
|
||||
{
|
||||
name: 'delete',
|
||||
label: 'Delete',
|
||||
icon: BinIcon,
|
||||
danger: true,
|
||||
url: (_id) =>
|
||||
`/dashboard/management/files/info?fileId=${_id}&action=delete`
|
||||
}
|
||||
],
|
||||
url: (id) => `/dashboard/management/files/info?fileId=${id}`,
|
||||
columns: ['name', '_id', 'type', 'size', 'temp', 'createdAt'],
|
||||
filters: ['name', '_id', 'type', 'temp'],
|
||||
sorters: ['name', 'type', 'size', 'createdAt', 'temp'],
|
||||
group: ['type'],
|
||||
properties: [
|
||||
{
|
||||
name: '_id',
|
||||
label: 'ID',
|
||||
columnFixed: 'left',
|
||||
type: 'id',
|
||||
objectType: 'file',
|
||||
showCopy: true
|
||||
},
|
||||
{
|
||||
name: 'createdAt',
|
||||
label: 'Created At',
|
||||
type: 'dateTime',
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
columnFixed: 'left',
|
||||
required: true,
|
||||
type: 'text'
|
||||
},
|
||||
{
|
||||
name: 'updatedAt',
|
||||
label: 'Updated At',
|
||||
type: 'dateTime',
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
label: 'Type',
|
||||
type: 'text',
|
||||
readOnly: true,
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'size',
|
||||
label: 'Size',
|
||||
type: 'number',
|
||||
readOnly: true,
|
||||
required: true,
|
||||
suffix: () => {
|
||||
return 'gb'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
label: 'Email',
|
||||
columnWidth: 300,
|
||||
type: 'email',
|
||||
readOnly: false,
|
||||
required: false
|
||||
},
|
||||
{
|
||||
name: 'phone',
|
||||
label: 'Phone',
|
||||
type: 'phone',
|
||||
readOnly: false,
|
||||
required: false
|
||||
},
|
||||
{
|
||||
name: 'website',
|
||||
label: 'Website',
|
||||
columnWidth: 300,
|
||||
type: 'url',
|
||||
readOnly: false,
|
||||
required: false
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { Route } from 'react-router-dom'
|
||||
import SessionStorage from '../components/Dashboard/Developer/SessionStorage.jsx'
|
||||
import AuthContextDebug from '../components/Dashboard/Developer/AuthContextDebug.jsx'
|
||||
import ApiContextDebug from '../components/Dashboard/Developer/ApiContextDebug.jsx'
|
||||
import PrintServerContextDebug from '../components/Dashboard/Developer/PrintServerContextDebug.jsx'
|
||||
|
||||
const DeveloperRoutes = [
|
||||
<Route
|
||||
@ -15,9 +15,9 @@ const DeveloperRoutes = [
|
||||
element={<AuthContextDebug />}
|
||||
/>,
|
||||
<Route
|
||||
key='apicontextdebug'
|
||||
path='developer/apicontextdebug'
|
||||
element={<ApiContextDebug />}
|
||||
key='printservercontextdebug'
|
||||
path='developer/printservercontextdebug'
|
||||
element={<PrintServerContextDebug />}
|
||||
/>
|
||||
]
|
||||
|
||||
|
||||
@ -24,11 +24,7 @@ import DocumentTemplates from '../components/Dashboard/Management/DocumentTempla
|
||||
import DocumentTemplateInfo from '../components/Dashboard/Management/DocumentTemplates/DocumentTemplateInfo.jsx'
|
||||
import DocumentPrinters from '../components/Dashboard/Management/DocumentPrinters.jsx'
|
||||
import DocumentPrinterInfo from '../components/Dashboard/Management/DocumentPrinters/DocumentPrinterInfo.jsx'
|
||||
import DocumentJobs from '../components/Dashboard/Management/DocumentJobs.jsx'
|
||||
import DocumentJobInfo from '../components/Dashboard/Management/DocumentJobs/DocumentJobInfo.jsx'
|
||||
import DocumentTemplateDesign from '../components/Dashboard/Management/DocumentTemplates/DocumentTemplateDesign.jsx'
|
||||
import Files from '../components/Dashboard/Management/Files.jsx'
|
||||
import FileInfo from '../components/Dashboard/Management/Files/FileInfo.jsx'
|
||||
|
||||
const ManagementRoutes = [
|
||||
<Route key='filaments' path='management/filaments' element={<Filaments />} />,
|
||||
@ -66,12 +62,6 @@ const ManagementRoutes = [
|
||||
path='management/vendors/info'
|
||||
element={<VendorInfo />}
|
||||
/>,
|
||||
<Route key='files' path='management/files' element={<Files />} />,
|
||||
<Route
|
||||
key='files-info'
|
||||
path='management/files/info'
|
||||
element={<FileInfo />}
|
||||
/>,
|
||||
<Route key='materials' path='management/materials' element={<Materials />} />,
|
||||
<Route key='notetypes' path='management/notetypes' element={<NoteTypes />} />,
|
||||
<Route
|
||||
@ -110,16 +100,6 @@ const ManagementRoutes = [
|
||||
path='management/documentprinters/info'
|
||||
element={<DocumentPrinterInfo />}
|
||||
/>,
|
||||
<Route
|
||||
key='documentjobs'
|
||||
path='management/documentjobs'
|
||||
element={<DocumentJobs />}
|
||||
/>,
|
||||
<Route
|
||||
key='documentjobs-info'
|
||||
path='management/documentjobs/info'
|
||||
element={<DocumentJobInfo />}
|
||||
/>,
|
||||
<Route
|
||||
key='documenttemplates-design'
|
||||
path='management/documenttemplates/design'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user