UI - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: auth screens, error pages и новый канон внешних контуров
This commit is contained in:
parent
df68c96795
commit
c6ace8b9cc
|
|
@ -20,9 +20,9 @@
|
|||
<path d="M251.986 120.208L219.029 103.439C217.488 102.654 216.238 100.767 216.238 99.2268C216.238 97.6866 217.488 97.0743 219.029 97.8598L251.986 114.629C253.527 115.414 254.777 117.301 254.777 118.841C254.777 120.381 253.527 120.993 251.986 120.208Z" fill="#E4E6E7"/>
|
||||
<path d="M194.035 105.963L161.078 89.1941C159.537 88.4085 158.287 86.5219 158.287 84.9818C158.287 83.4416 159.537 82.8292 161.078 83.6148L194.035 100.384C195.576 101.169 196.826 103.056 196.826 104.596C196.826 106.136 195.576 106.748 194.035 105.963Z" fill="#E4E6E7"/>
|
||||
<path d="M150.992 100.192L147.799 98.565C147.168 98.2433 146.66 97.4764 146.66 96.8454V93.6538C146.66 93.0228 147.174 92.7754 147.799 93.0909L150.992 94.7176C151.623 95.0393 152.13 95.8063 152.13 96.4372V99.6289C152.13 100.26 151.617 100.507 150.992 100.192Z" fill="#E4E6E7"/>
|
||||
<path d="M65.971 0.698973L203.091 70.5264C206.383 72.2027 208.462 75.5861 208.462 79.285V197.427C208.456 201.095 204.576 203.47 201.302 201.806L64.1951 131.966C60.9031 130.29 58.8301 126.907 58.8301 123.208V5.07826C58.8301 1.4103 62.7099 -0.964911 65.9772 0.698973H65.971Z" fill="#2892CC" stroke="#2892CC" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M62.8831 2.28247L200.003 72.1099C203.295 73.7862 205.374 77.1696 205.374 80.8685V199.01C205.368 202.678 201.488 205.054 198.214 203.39L61.1072 133.55C57.8152 131.874 55.7422 128.49 55.7422 124.791V6.66176C55.7422 2.99379 59.6221 0.618585 62.8893 2.28247H62.8831Z" fill="#0F0F10" stroke="#2892CC" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M198.381 200.569L63.0869 131.725C60.5437 130.432 58.4583 126.783 58.4274 123.573L58.2912 19.6141C58.2665 16.41 60.3023 14.8574 62.8518 16.1502L198.146 84.9941C200.689 86.2869 202.775 89.9363 202.806 93.1466L202.942 197.105C202.966 200.309 200.931 201.862 198.381 200.569Z" fill="#0F0F10" stroke="#2892CC" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M65.971 0.698973L203.091 70.5264C206.383 72.2027 208.462 75.5861 208.462 79.285V197.427C208.456 201.095 204.576 203.47 201.302 201.806L64.1951 131.966C60.9031 130.29 58.8301 126.907 58.8301 123.208V5.07826C58.8301 1.4103 62.7099 -0.964911 65.9772 0.698973H65.971Z" fill="#C3FF66" stroke="#C3FF66" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M62.8831 2.28247L200.003 72.1099C203.295 73.7862 205.374 77.1696 205.374 80.8685V199.01C205.368 202.678 201.488 205.054 198.214 203.39L61.1072 133.55C57.8152 131.874 55.7422 128.49 55.7422 124.791V6.66176C55.7422 2.99379 59.6221 0.618585 62.8893 2.28247H62.8831Z" fill="#0F0F10" stroke="#C3FF66" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M198.381 200.569L63.0869 131.725C60.5437 130.432 58.4583 126.783 58.4274 123.573L58.2912 19.6141C58.2665 16.41 60.3023 14.8574 62.8518 16.1502L198.146 84.9941C200.689 86.2869 202.775 89.9363 202.806 93.1466L202.942 197.105C202.966 200.309 200.931 201.862 198.381 200.569Z" fill="#0F0F10" stroke="#C3FF66" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M153.084 208.425C153.084 208.957 153.356 209.482 153.901 209.761L157.168 211.425L158.041 211.87C159.328 212.526 160.844 212.526 162.131 211.87L163.016 211.418L166.295 209.754C166.84 209.476 167.118 208.95 167.118 208.418C167.118 207.886 166.846 207.355 166.295 207.076L162.131 204.967C160.844 204.317 159.328 204.317 158.047 204.973L153.907 207.082C153.362 207.361 153.09 207.893 153.09 208.418L153.084 208.425Z" fill="#0F0F10" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M153.084 208.425V214.431C153.084 214.963 153.357 215.488 153.901 215.767L158.035 217.876C159.322 218.532 160.838 218.532 162.125 217.876L166.289 215.761C166.834 215.482 167.112 214.956 167.112 214.424V208.418C167.112 208.944 166.834 209.476 166.289 209.754L163.01 211.418L162.125 211.87C160.838 212.526 159.322 212.526 158.035 211.87L157.162 211.425L153.895 209.761C153.35 209.482 153.078 208.95 153.078 208.425H153.084Z" fill="#0F0F10" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M163.418 213.682C163.418 214.214 163.69 214.74 164.235 215.018L167.502 216.682L168.375 217.128C169.662 217.783 171.178 217.783 172.465 217.128L173.35 216.676L176.629 215.012C177.174 214.734 177.452 214.208 177.452 213.676C177.452 213.144 177.18 212.612 176.629 212.334L172.465 210.225C171.178 209.575 169.662 209.575 168.381 210.231L164.241 212.34C163.696 212.618 163.424 213.15 163.424 213.676L163.418 213.682Z" fill="#0F0F10" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
<path d="M371.205 121.55C371.205 118.6 373.42 115.655 377.839 113.404L446.921 78.2211C455.77 73.7181 470.114 73.7181 478.957 78.2211L548.039 113.404C552.47 115.662 554.673 118.618 554.673 121.575C554.673 124.531 552.458 127.47 548.039 129.721L478.957 164.904C470.108 169.407 455.764 169.407 446.921 164.904L377.839 129.721C373.408 127.463 371.205 124.507 371.205 121.55Z" stroke="#4E555A" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="3 5 3 5"/>
|
||||
<path d="M554.68 121.575V232.053" stroke="#4E555A" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="3 5 3 5"/>
|
||||
<path d="M371.205 121.55V231.082" stroke="#4E555A" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="3 5 3 5"/>
|
||||
<path d="M131.613 92.7631C131.613 91.4147 132.782 91.1301 133.772 92.2373L150.071 110.453C151.334 111.864 152.132 113.843 152.132 115.563V131.379C152.132 132.727 150.962 133.012 149.972 131.905L140.808 121.661V109.798C140.808 108.078 140.01 106.099 138.747 104.689L131.613 96.7156V92.7693V92.7631ZM108.971 81.2272C108.971 79.8788 110.14 79.5943 111.13 80.7015L120.289 90.9384V102.808C120.289 104.528 121.087 106.507 122.349 107.917L129.49 115.897V119.843C129.49 121.191 128.321 121.476 127.33 120.369L111.031 102.153C109.769 100.742 108.971 98.763 108.971 97.0434V81.2272ZM120.289 86.9921C120.289 85.6436 121.458 85.3591 122.448 86.4663L131.613 96.7032V108.573C131.613 110.293 132.411 112.272 133.673 113.682L140.808 121.655V125.608C140.808 126.956 139.638 127.241 138.648 126.134L129.49 115.897V104.027C129.49 102.307 128.692 100.328 127.429 98.9176L120.289 90.9384V86.9921Z" fill="#2892CC"/>
|
||||
<path d="M131.613 92.7631C131.613 91.4147 132.782 91.1301 133.772 92.2373L150.071 110.453C151.334 111.864 152.132 113.843 152.132 115.563V131.379C152.132 132.727 150.962 133.012 149.972 131.905L140.808 121.661V109.798C140.808 108.078 140.01 106.099 138.747 104.689L131.613 96.7156V92.7693V92.7631ZM108.971 81.2272C108.971 79.8788 110.14 79.5943 111.13 80.7015L120.289 90.9384V102.808C120.289 104.528 121.087 106.507 122.349 107.917L129.49 115.897V119.843C129.49 121.191 128.321 121.476 127.33 120.369L111.031 102.153C109.769 100.742 108.971 98.763 108.971 97.0434V81.2272ZM120.289 86.9921C120.289 85.6436 121.458 85.3591 122.448 86.4663L131.613 96.7032V108.573C131.613 110.293 132.411 112.272 133.673 113.682L140.808 121.655V125.608C140.808 126.956 139.638 127.241 138.648 126.134L129.49 115.897V104.027C129.49 102.307 128.692 100.328 127.429 98.9176L120.289 90.9384V86.9921Z" fill="#C3FF66"/>
|
||||
<path d="M0.154297 120.443C0.154297 121.179 0.537952 121.921 1.29289 122.305L5.84725 124.63L7.06009 125.249C8.84842 126.164 10.9709 126.164 12.7592 125.249L13.9968 124.624L18.5698 122.299C19.3309 121.915 19.7145 121.179 19.7145 120.443C19.7145 119.701 19.3371 118.958 18.5698 118.569L12.7592 115.624C10.9709 114.721 8.85461 114.721 7.06628 115.637L1.29908 118.581C0.537952 118.971 0.160485 119.707 0.160485 120.443H0.154297Z" fill="#0F0F10" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M0.154625 120.443V128.812C0.154625 129.548 0.538281 130.29 1.29322 130.674L7.05423 133.612C8.84256 134.527 10.965 134.527 12.7534 133.612L18.5639 130.661C19.325 130.278 19.7087 129.542 19.7087 128.806V120.437C19.7087 121.173 19.325 121.909 18.5639 122.292L13.991 124.618L12.7534 125.243C10.965 126.158 8.84256 126.152 7.05423 125.243L5.84139 124.624L1.28703 122.299C0.525905 121.909 0.148438 121.173 0.148438 120.437L0.154625 120.443Z" fill="#0F0F10" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M346.904 96.3506C346.904 97.0867 347.288 97.8289 348.043 98.2124L352.597 100.538L353.81 101.157C355.598 102.072 357.721 102.072 359.509 101.157L360.747 100.532L365.32 98.2062C366.081 97.8227 366.465 97.0867 366.465 96.3506C366.465 95.6084 366.087 94.8661 365.32 94.4764L359.509 91.5322C357.721 90.6291 355.605 90.6291 353.816 91.5445L348.049 94.4888C347.288 94.8785 346.91 95.6145 346.91 96.3506H346.904Z" fill="#0F0F10" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
|
@ -20,9 +20,9 @@
|
|||
<path d="M251.986 120.208L219.029 103.439C217.488 102.654 216.238 100.767 216.238 99.2268C216.238 97.6866 217.488 97.0743 219.029 97.8598L251.986 114.629C253.527 115.414 254.777 117.301 254.777 118.841C254.777 120.381 253.527 120.993 251.986 120.208Z" fill="#CCD0D2"/>
|
||||
<path d="M194.035 105.963L161.078 89.1941C159.537 88.4085 158.287 86.5219 158.287 84.9818C158.287 83.4416 159.537 82.8292 161.078 83.6148L194.035 100.384C195.576 101.169 196.826 103.056 196.826 104.596C196.826 106.136 195.576 106.748 194.035 105.963Z" fill="#CCD0D2"/>
|
||||
<path d="M150.992 100.192L147.799 98.565C147.168 98.2433 146.66 97.4764 146.66 96.8454V93.6538C146.66 93.0228 147.174 92.7754 147.799 93.0909L150.992 94.7176C151.623 95.0393 152.13 95.8063 152.13 96.4372V99.6289C152.13 100.26 151.617 100.507 150.992 100.192Z" fill="#CCD0D2"/>
|
||||
<path d="M65.971 0.698973L203.091 70.5264C206.383 72.2027 208.462 75.5861 208.462 79.285V197.427C208.456 201.095 204.576 203.47 201.302 201.806L64.1951 131.966C60.9031 130.29 58.8301 126.907 58.8301 123.208V5.07826C58.8301 1.4103 62.7099 -0.964911 65.9772 0.698973H65.971Z" fill="#2892CC" stroke="#2892CC" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M62.8831 2.28247L200.003 72.1099C203.295 73.7862 205.374 77.1696 205.374 80.8685V199.01C205.368 202.678 201.488 205.054 198.214 203.39L61.1072 133.55C57.8152 131.874 55.7422 128.49 55.7422 124.791V6.66176C55.7422 2.99379 59.6221 0.618585 62.8893 2.28247H62.8831Z" fill="white" stroke="#2892CC" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M198.381 200.569L63.0869 131.725C60.5437 130.432 58.4583 126.783 58.4274 123.573L58.2912 19.6141C58.2665 16.41 60.3023 14.8574 62.8518 16.1502L198.146 84.9941C200.689 86.2869 202.775 89.9363 202.806 93.1466L202.942 197.105C202.966 200.309 200.931 201.862 198.381 200.569Z" fill="white" stroke="#2892CC" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M65.971 0.698973L203.091 70.5264C206.383 72.2027 208.462 75.5861 208.462 79.285V197.427C208.456 201.095 204.576 203.47 201.302 201.806L64.1951 131.966C60.9031 130.29 58.8301 126.907 58.8301 123.208V5.07826C58.8301 1.4103 62.7099 -0.964911 65.9772 0.698973H65.971Z" fill="#C3FF66" stroke="#C3FF66" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M62.8831 2.28247L200.003 72.1099C203.295 73.7862 205.374 77.1696 205.374 80.8685V199.01C205.368 202.678 201.488 205.054 198.214 203.39L61.1072 133.55C57.8152 131.874 55.7422 128.49 55.7422 124.791V6.66176C55.7422 2.99379 59.6221 0.618585 62.8893 2.28247H62.8831Z" fill="white" stroke="#C3FF66" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M198.381 200.569L63.0869 131.725C60.5437 130.432 58.4583 126.783 58.4274 123.573L58.2912 19.6141C58.2665 16.41 60.3023 14.8574 62.8518 16.1502L198.146 84.9941C200.689 86.2869 202.775 89.9363 202.806 93.1466L202.942 197.105C202.966 200.309 200.931 201.862 198.381 200.569Z" fill="white" stroke="#C3FF66" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M153.084 208.425C153.084 208.957 153.356 209.482 153.901 209.761L157.168 211.425L158.041 211.87C159.328 212.526 160.844 212.526 162.131 211.87L163.016 211.418L166.295 209.754C166.84 209.476 167.118 208.95 167.118 208.418C167.118 207.886 166.846 207.355 166.295 207.076L162.131 204.967C160.844 204.317 159.328 204.317 158.047 204.973L153.907 207.082C153.362 207.361 153.09 207.893 153.09 208.418L153.084 208.425Z" fill="white" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M153.084 208.425V214.431C153.084 214.963 153.357 215.488 153.901 215.767L158.035 217.876C159.322 218.532 160.838 218.532 162.125 217.876L166.289 215.761C166.834 215.482 167.112 214.956 167.112 214.424V208.418C167.112 208.944 166.834 209.476 166.289 209.754L163.01 211.418L162.125 211.87C160.838 212.526 159.322 212.526 158.035 211.87L157.162 211.425L153.895 209.761C153.35 209.482 153.078 208.95 153.078 208.425H153.084Z" fill="white" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M163.418 213.682C163.418 214.214 163.69 214.74 164.235 215.018L167.502 216.682L168.375 217.128C169.662 217.783 171.178 217.783 172.465 217.128L173.35 216.676L176.629 215.012C177.174 214.734 177.452 214.208 177.452 213.676C177.452 213.144 177.18 212.612 176.629 212.334L172.465 210.225C171.178 209.575 169.662 209.575 168.381 210.231L164.241 212.34C163.696 212.618 163.424 213.15 163.424 213.676L163.418 213.682Z" fill="white" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
<path d="M371.205 121.55C371.205 118.6 373.42 115.655 377.839 113.404L446.921 78.2211C455.77 73.7181 470.114 73.7181 478.957 78.2211L548.039 113.404C552.47 115.662 554.673 118.618 554.673 121.575C554.673 124.531 552.458 127.47 548.039 129.721L478.957 164.904C470.108 169.407 455.764 169.407 446.921 164.904L377.839 129.721C373.408 127.463 371.205 124.507 371.205 121.55Z" stroke="#99A1A6" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="3 5 3 5"/>
|
||||
<path d="M554.68 121.575V232.053" stroke="#99A1A6" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="3 5 3 5"/>
|
||||
<path d="M371.205 121.55V231.082" stroke="#99A1A6" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="3 5 3 5"/>
|
||||
<path d="M131.613 92.7631C131.613 91.4147 132.782 91.1301 133.772 92.2373L150.071 110.453C151.334 111.864 152.132 113.843 152.132 115.563V131.379C152.132 132.727 150.962 133.012 149.972 131.905L140.808 121.661V109.798C140.808 108.078 140.01 106.099 138.747 104.689L131.613 96.7156V92.7693V92.7631ZM108.971 81.2272C108.971 79.8788 110.14 79.5943 111.13 80.7015L120.289 90.9384V102.808C120.289 104.528 121.087 106.507 122.349 107.917L129.49 115.897V119.843C129.49 121.191 128.321 121.476 127.33 120.369L111.031 102.153C109.769 100.742 108.971 98.763 108.971 97.0434V81.2272ZM120.289 86.9921C120.289 85.6436 121.458 85.3591 122.448 86.4663L131.613 96.7032V108.573C131.613 110.293 132.411 112.272 133.673 113.682L140.808 121.655V125.608C140.808 126.956 139.638 127.241 138.648 126.134L129.49 115.897V104.027C129.49 102.307 128.692 100.328 127.429 98.9176L120.289 90.9384V86.9921Z" fill="#2892CC"/>
|
||||
<path d="M131.613 92.7631C131.613 91.4147 132.782 91.1301 133.772 92.2373L150.071 110.453C151.334 111.864 152.132 113.843 152.132 115.563V131.379C152.132 132.727 150.962 133.012 149.972 131.905L140.808 121.661V109.798C140.808 108.078 140.01 106.099 138.747 104.689L131.613 96.7156V92.7693V92.7631ZM108.971 81.2272C108.971 79.8788 110.14 79.5943 111.13 80.7015L120.289 90.9384V102.808C120.289 104.528 121.087 106.507 122.349 107.917L129.49 115.897V119.843C129.49 121.191 128.321 121.476 127.33 120.369L111.031 102.153C109.769 100.742 108.971 98.763 108.971 97.0434V81.2272ZM120.289 86.9921C120.289 85.6436 121.458 85.3591 122.448 86.4663L131.613 96.7032V108.573C131.613 110.293 132.411 112.272 133.673 113.682L140.808 121.655V125.608C140.808 126.956 139.638 127.241 138.648 126.134L129.49 115.897V104.027C129.49 102.307 128.692 100.328 127.429 98.9176L120.289 90.9384V86.9921Z" fill="#C3FF66"/>
|
||||
<path d="M0.154297 120.443C0.154297 121.179 0.537952 121.921 1.29289 122.305L5.84725 124.63L7.06009 125.249C8.84842 126.164 10.9709 126.164 12.7592 125.249L13.9968 124.624L18.5698 122.299C19.3309 121.915 19.7145 121.179 19.7145 120.443C19.7145 119.701 19.3371 118.958 18.5698 118.569L12.7592 115.624C10.9709 114.721 8.85461 114.721 7.06628 115.637L1.29908 118.581C0.537952 118.971 0.160485 119.707 0.160485 120.443H0.154297Z" fill="white" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M0.154625 120.443V128.812C0.154625 129.548 0.538281 130.29 1.29322 130.674L7.05423 133.612C8.84256 134.527 10.965 134.527 12.7534 133.612L18.5639 130.661C19.325 130.278 19.7087 129.542 19.7087 128.806V120.437C19.7087 121.173 19.325 121.909 18.5639 122.292L13.991 124.618L12.7534 125.243C10.965 126.158 8.84256 126.152 7.05423 125.243L5.84139 124.624L1.28703 122.299C0.525905 121.909 0.148438 121.173 0.148438 120.437L0.154625 120.443Z" fill="white" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M346.904 96.3506C346.904 97.0867 347.288 97.8289 348.043 98.2124L352.597 100.538L353.81 101.157C355.598 102.072 357.721 102.072 359.509 101.157L360.747 100.532L365.32 98.2062C366.081 97.8227 366.465 97.0867 366.465 96.3506C366.465 95.6084 366.087 94.8661 365.32 94.4764L359.509 91.5322C357.721 90.6291 355.605 90.6291 353.816 91.5445L348.049 94.4888C347.288 94.8785 346.91 95.6145 346.91 96.3506H346.904Z" fill="white" stroke="#808A8F" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
|
@ -4,11 +4,9 @@
|
|||
* See the LICENSE file for details.
|
||||
*/
|
||||
|
||||
// plane imports
|
||||
import { isRouteErrorResponse } from "react-router";
|
||||
import { Banner } from "@plane/propel/banner";
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { Card, ECardVariant } from "@plane/propel/card";
|
||||
import { InfoFillIcon } from "@plane/propel/icons";
|
||||
|
||||
interface ErrorActionsProps {
|
||||
|
|
@ -19,12 +17,12 @@ interface ErrorActionsProps {
|
|||
function ErrorActions({ onGoHome, onReload }: ErrorActionsProps) {
|
||||
return (
|
||||
<div className="flex gap-3 pt-2">
|
||||
<Button variant="primary" size="lg" onClick={onGoHome}>
|
||||
Go to home
|
||||
<Button variant="primary" size="lg" onClick={onGoHome} className="nodedc-error-primary">
|
||||
На главную
|
||||
</Button>
|
||||
{onReload && (
|
||||
<Button variant="secondary" size="lg" onClick={onReload}>
|
||||
Reload page
|
||||
<Button variant="secondary" size="lg" onClick={onReload} className="nodedc-empty-state-secondary">
|
||||
Обновить страницу
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -37,19 +35,17 @@ interface DevErrorComponentProps {
|
|||
onReload: () => void;
|
||||
}
|
||||
|
||||
const ErrorShell = ({ children }: { children: React.ReactNode }) => (
|
||||
<div className="nodedc-error-shell transition-none">{children}</div>
|
||||
);
|
||||
|
||||
export function DevErrorComponent({ error, onGoHome, onReload }: DevErrorComponentProps) {
|
||||
if (isRouteErrorResponse(error)) {
|
||||
return (
|
||||
<div className="flex min-h-screen items-start justify-center bg-surface-2 p-6 transition-none">
|
||||
<div className="mt-12 w-full max-w-4xl space-y-4 transition-none">
|
||||
<Banner
|
||||
variant="error"
|
||||
icon={<InfoFillIcon className="size-5" />}
|
||||
title="Route Error Response"
|
||||
animationDuration={0}
|
||||
/>
|
||||
|
||||
<Card variant={ECardVariant.WITH_SHADOW} className="!p-6 transition-none">
|
||||
<Banner variant="error" icon={<InfoFillIcon className="size-5" />} title="Ошибка маршрута" animationDuration={0} />
|
||||
<ErrorShell>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h2 className="mb-2 text-20 font-semibold text-danger-primary">
|
||||
|
|
@ -59,15 +55,15 @@ export function DevErrorComponent({ error, onGoHome, onReload }: DevErrorCompone
|
|||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-13 font-medium tracking-wide text-tertiary uppercase">Error Data</h3>
|
||||
<div className="rounded-md bg-layer-1 p-4">
|
||||
<h3 className="text-13 font-medium tracking-wide text-tertiary uppercase">Данные ошибки</h3>
|
||||
<div className="rounded-[1.1rem] bg-white/5 p-4">
|
||||
<p className="font-code text-13 text-secondary">{error.data}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ErrorActions onGoHome={onGoHome} onReload={onReload} />
|
||||
</div>
|
||||
</Card>
|
||||
</ErrorShell>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -80,27 +76,27 @@ export function DevErrorComponent({ error, onGoHome, onReload }: DevErrorCompone
|
|||
<Banner
|
||||
variant="error"
|
||||
icon={<InfoFillIcon className="size-5" />}
|
||||
title="Runtime Error"
|
||||
title="Ошибка выполнения"
|
||||
animationDuration={0}
|
||||
/>
|
||||
<Card variant={ECardVariant.WITH_SHADOW} className="!p-6 transition-none">
|
||||
<ErrorShell>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h2 className="mb-2 text-20 font-semibold text-danger-primary">Error</h2>
|
||||
<h2 className="mb-2 text-20 font-semibold text-danger-primary">Ошибка</h2>
|
||||
<div className="bg-subtle-1 h-px w-full" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-13 font-medium tracking-wide text-tertiary uppercase">Message</h3>
|
||||
<div className="rounded-md bg-layer-1 p-4">
|
||||
<h3 className="text-13 font-medium tracking-wide text-tertiary uppercase">Сообщение</h3>
|
||||
<div className="rounded-[1.1rem] bg-white/5 p-4">
|
||||
<p className="text-13 font-medium text-primary">{error.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{error.stack && (
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-13 font-medium tracking-wide text-tertiary uppercase">Stack Trace</h3>
|
||||
<div className="max-h-96 overflow-auto rounded-md border border-subtle bg-layer-1">
|
||||
<h3 className="text-13 font-medium tracking-wide text-tertiary uppercase">Стек вызовов</h3>
|
||||
<div className="max-h-96 overflow-auto rounded-[1.1rem] bg-white/5">
|
||||
<pre className="p-4 font-code text-11 break-words whitespace-pre-wrap text-secondary">
|
||||
{error.stack}
|
||||
</pre>
|
||||
|
|
@ -110,20 +106,20 @@ export function DevErrorComponent({ error, onGoHome, onReload }: DevErrorCompone
|
|||
|
||||
<ErrorActions onGoHome={onGoHome} onReload={onReload} />
|
||||
</div>
|
||||
</Card>
|
||||
</ErrorShell>
|
||||
|
||||
<Card variant={ECardVariant.WITHOUT_SHADOW} className="bg-layer-1 !p-4 transition-none">
|
||||
<div className="nodedc-external-panel p-4 transition-none">
|
||||
<div className="flex items-start gap-3">
|
||||
<InfoFillIcon className="mt-0.5 size-5 flex-shrink-0 text-tertiary" />
|
||||
<div className="space-y-1">
|
||||
<p className="text-13 font-medium text-secondary">Development Mode</p>
|
||||
<p className="text-13 font-medium text-secondary">Режим разработки</p>
|
||||
<p className="text-11 text-tertiary">
|
||||
This detailed error view is only visible in development. In production, users will see a friendly
|
||||
error page.
|
||||
Этот подробный экран ошибок виден только в разработке. В production пользователи увидят упрощённую
|
||||
страницу ошибки.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -132,29 +128,24 @@ export function DevErrorComponent({ error, onGoHome, onReload }: DevErrorCompone
|
|||
return (
|
||||
<div className="flex min-h-screen items-start justify-center bg-surface-2 p-6 transition-none">
|
||||
<div className="mt-12 w-full max-w-4xl space-y-4 transition-none">
|
||||
<Banner
|
||||
variant="error"
|
||||
icon={<InfoFillIcon className="size-5" />}
|
||||
title="Unknown Error"
|
||||
animationDuration={0}
|
||||
/>
|
||||
|
||||
<Card variant={ECardVariant.WITH_SHADOW} className="!p-6">
|
||||
<Banner variant="error" icon={<InfoFillIcon className="size-5" />} title="Неизвестная ошибка" animationDuration={0} />
|
||||
<ErrorShell>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h2 className="mb-2 text-20 font-semibold text-primary">Unknown Error</h2>
|
||||
<h2 className="mb-2 text-20 font-semibold text-primary">Неизвестная ошибка</h2>
|
||||
<div className="bg-subtle-1 h-px w-full" />
|
||||
</div>
|
||||
|
||||
<div className="rounded-md bg-layer-1 p-4">
|
||||
<div className="rounded-[1.1rem] bg-white/5 p-4">
|
||||
<p className="text-13 text-secondary">
|
||||
An unknown error occurred. Please try refreshing the page or contact support if the problem persists.
|
||||
Произошла неизвестная ошибка. Обновите страницу. Если проблема сохранится, обратитесь в службу
|
||||
поддержки.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ErrorActions onGoHome={onGoHome} onReload={onReload} />
|
||||
</div>
|
||||
</Card>
|
||||
</ErrorShell>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -16,18 +16,8 @@ import DefaultLayout from "@/layouts/default-layout";
|
|||
const linkMap = [
|
||||
{
|
||||
key: "mail_to",
|
||||
label: "Contact Support",
|
||||
value: "mailto:support@plane.so",
|
||||
},
|
||||
{
|
||||
key: "status",
|
||||
label: "Status Page",
|
||||
value: "https://status.plane.so/",
|
||||
},
|
||||
{
|
||||
key: "twitter_handle",
|
||||
label: "@planepowers",
|
||||
value: "https://x.com/planepowers",
|
||||
label: "Служба поддержки",
|
||||
value: "https://nodedc.dctouch.ru/",
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -45,22 +35,20 @@ export function ProdErrorComponent({ onGoHome }: ProdErrorComponentProps) {
|
|||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<div className="relative container mx-auto flex h-full w-full max-w-xl flex-col items-center justify-center gap-2 gap-y-6 bg-surface-1 px-6 text-center">
|
||||
<div className="relative w-full">
|
||||
<div className="relative container mx-auto flex h-full w-full max-w-3xl items-center justify-center px-6 py-10">
|
||||
<div className="nodedc-error-shell relative flex w-full flex-col gap-6 text-left">
|
||||
<img
|
||||
src={maintenanceModeImage}
|
||||
height="176"
|
||||
width="288"
|
||||
alt="ProjectSettingImg"
|
||||
className="h-full w-full object-fill object-center"
|
||||
className="mx-auto h-full w-full max-w-[18rem] object-fill object-center"
|
||||
/>
|
||||
</div>
|
||||
<div className="relative mt-4 flex w-full flex-col gap-4">
|
||||
<div className="flex flex-col gap-2.5">
|
||||
<h1 className="text-left text-18 font-semibold text-primary">🚧 Looks like something went wrong!</h1>
|
||||
<span className="text-left text-14 font-medium text-secondary">
|
||||
We track these errors automatically and working on getting things back up and running. If the problem
|
||||
persists feel free to contact us. In the meantime, try refreshing.
|
||||
<h1 className="text-18 font-semibold text-primary">🚧 Похоже, что-то пошло не так.</h1>
|
||||
<span className="text-14 font-medium text-secondary">
|
||||
Мы уже зафиксировали ошибку и пытаемся восстановить работу. Если проблема сохраняется, обратитесь в
|
||||
службу поддержки и обновите страницу.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -71,7 +59,7 @@ export function ProdErrorComponent({ onGoHome }: ProdErrorComponentProps) {
|
|||
href={link.value}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-13 text-accent-primary hover:underline"
|
||||
className="nodedc-error-link text-13"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
|
|
@ -80,8 +68,8 @@ export function ProdErrorComponent({ onGoHome }: ProdErrorComponentProps) {
|
|||
</div>
|
||||
|
||||
<div className="flex items-center justify-start gap-6">
|
||||
<Button variant="primary" size="lg" onClick={onGoHome}>
|
||||
Go to home
|
||||
<Button variant="primary" size="lg" onClick={onGoHome} className="nodedc-error-primary">
|
||||
На главную
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,20 +8,18 @@ export function MaintenanceMessage() {
|
|||
const linkMap = [
|
||||
{
|
||||
key: "mail_to",
|
||||
label: "Contact Support",
|
||||
value: "mailto:support@plane.so",
|
||||
label: "Служба поддержки",
|
||||
value: "https://nodedc.dctouch.ru/",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col gap-2.5">
|
||||
<h1 className="text-left text-18 font-semibold text-primary">
|
||||
🚧 Looks like NODE.DC didn't start up correctly!
|
||||
</h1>
|
||||
<h1 className="text-left text-18 font-semibold text-primary">🚧 NODE.DC запустился с ошибкой.</h1>
|
||||
<span className="text-left text-14 font-medium text-secondary">
|
||||
Some services might have failed to start. Please check your container logs to identify and resolve the issue.
|
||||
If you're stuck, reach out to our support team for more help.
|
||||
Часть сервисов могла не подняться. Проверьте логи контейнеров и устраните причину. Если нужна помощь,
|
||||
переходите в службу поддержки.
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-1 flex items-center justify-start gap-6">
|
||||
|
|
@ -31,7 +29,7 @@ export function MaintenanceMessage() {
|
|||
href={link.value}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-13 text-accent-primary hover:underline"
|
||||
className="nodedc-error-link text-13"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -29,13 +29,13 @@ export const ExternalContoursIssueContentProperties = observer(function External
|
|||
if (!issue || !issue?.id) return <></>;
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col divide-y-2 divide-subtle-1">
|
||||
<div className="nodedc-external-section flex w-full flex-col px-4 py-4">
|
||||
<div className="w-full overflow-y-auto">
|
||||
<h5 className="mb-2 text-body-sm-medium">{t("external_contours_page.properties.section_title")}</h5>
|
||||
<div className={`divide-y-2 divide-subtle-1 ${!isEditable ? "opacity-60" : ""}`}>
|
||||
<div className={`${!isEditable ? "opacity-60" : ""}`}>
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex h-8 items-center gap-2">
|
||||
<div className="flex w-2/5 flex-shrink-0 items-center gap-1 text-13 text-tertiary">
|
||||
<div className="nodedc-external-panel flex min-h-12 items-center gap-3 px-4 py-3">
|
||||
<div className="flex w-2/5 flex-shrink-0 items-center gap-1.5 text-13 text-tertiary">
|
||||
<PriorityPropertyIcon className="h-4 w-4 flex-shrink-0" />
|
||||
<span>{t("priority")}</span>
|
||||
</div>
|
||||
|
|
@ -44,14 +44,14 @@ export const ExternalContoursIssueContentProperties = observer(function External
|
|||
onChange={(val) => issue?.id && issueOperations.update(workspaceSlug, targetProjectId, issue.id, { priority: val })}
|
||||
disabled={!isEditable}
|
||||
buttonVariant="border-with-text"
|
||||
className="w-3/5 flex-grow rounded-sm px-2 hover:bg-layer-1"
|
||||
className="w-3/5 flex-grow rounded-full px-3 hover:bg-white/6"
|
||||
buttonContainerClassName="w-full text-left"
|
||||
buttonClassName="h-auto w-min whitespace-nowrap"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex min-h-8 items-center gap-2">
|
||||
<div className="flex w-2/5 flex-shrink-0 items-center gap-1 text-13 text-tertiary">
|
||||
<div className="nodedc-external-panel flex min-h-12 items-center gap-3 px-4 py-3">
|
||||
<div className="flex w-2/5 flex-shrink-0 items-center gap-1.5 text-13 text-tertiary">
|
||||
<LabelPropertyIcon className="h-4 w-4 flex-shrink-0" />
|
||||
<span>{t("labels")}</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import { useEffect, useMemo, useRef } from "react";
|
|||
import { observer } from "mobx-react";
|
||||
import type { EditorRefApi } from "@plane/editor";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Badge } from "@plane/propel/badge";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { TExternalContourRequest, TIssue, TNameDescriptionLoader } from "@plane/types";
|
||||
import { EFileAssetType } from "@plane/types";
|
||||
|
|
@ -139,8 +138,8 @@ export const ExternalContoursIssueMainContent = observer(function ExternalContou
|
|||
|
||||
if (!hasDirectTargetAccess) {
|
||||
return (
|
||||
<>
|
||||
<div className="space-y-4 pb-4">
|
||||
<div className="space-y-4">
|
||||
<div className="nodedc-external-section space-y-4 p-5">
|
||||
{isSourceEditable ? (
|
||||
<>
|
||||
<IssueTitleInput
|
||||
|
|
@ -190,23 +189,23 @@ export const ExternalContoursIssueMainContent = observer(function ExternalContou
|
|||
)}
|
||||
</div>
|
||||
|
||||
<div className="py-4">
|
||||
<ExternalContoursRequestTraceability contourRequest={contourRequest} />
|
||||
</div>
|
||||
<ExternalContoursRequestTraceability contourRequest={contourRequest} />
|
||||
|
||||
<div className="py-4">
|
||||
<div className="mb-2 text-body-sm-medium">{t("external_contours_page.properties.section_title")}</div>
|
||||
<div className="nodedc-external-section flex flex-col gap-3 px-4 py-4">
|
||||
<div className="text-body-sm-medium">{t("external_contours_page.properties.section_title")}</div>
|
||||
<div className="flex flex-col gap-3 text-13 text-secondary">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<div className="nodedc-external-panel flex flex-wrap items-center gap-2 px-4 py-3">
|
||||
<span className="text-tertiary">{t("priority")}</span>
|
||||
<Badge variant="neutral">{issue.priority || t("none")}</Badge>
|
||||
<span className="rounded-full bg-white/6 px-3 py-1.5 text-12 font-medium text-primary">
|
||||
{issue.priority || t("none")}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<div className="nodedc-external-panel flex flex-wrap items-center gap-2 px-4 py-3">
|
||||
<span className="text-tertiary">{t("labels")}</span>
|
||||
{issue.label_details?.length ? (
|
||||
issue.label_details.map((label) => (
|
||||
<div key={label.id} className="flex items-center gap-1 rounded-sm border border-strong px-2 py-1 text-11">
|
||||
<div key={label.id} className="flex items-center gap-1 rounded-full bg-white/6 px-3 py-1.5 text-11">
|
||||
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: label.color }} />
|
||||
<span>{label.name}</span>
|
||||
</div>
|
||||
|
|
@ -230,8 +229,12 @@ export const ExternalContoursIssueMainContent = observer(function ExternalContou
|
|||
|
||||
<ExternalContoursMirroredActivity activity={mirroredActivity} />
|
||||
|
||||
{!isSourceEditable && <div className="py-4 text-13 text-secondary">{t("external_contours_page.readonly_source_view")}</div>}
|
||||
</>
|
||||
{!isSourceEditable && (
|
||||
<div className="nodedc-external-empty px-4 py-4 text-13 text-secondary">
|
||||
{t("external_contours_page.readonly_source_view")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,14 +53,15 @@ export const ExternalContoursListItem = observer(function ExternalContoursListIt
|
|||
onClick={(e) => handleIssueRedirection(e, request.id)}
|
||||
>
|
||||
<Row
|
||||
data-active={selectedInboxIssueId === request.id}
|
||||
className={cn(
|
||||
"relative flex cursor-pointer flex-col gap-2 border border-t-transparent border-r-transparent border-b-subtle-1 border-l-transparent py-4 transition-all hover:bg-accent-primary/5",
|
||||
{ "border border-accent-strong": selectedInboxIssueId === request.id }
|
||||
"nodedc-external-card relative flex cursor-pointer flex-col gap-4 px-4 py-4 transition-all hover:bg-white/5",
|
||||
{ "ring-1 ring-accent-primary/35": selectedInboxIssueId === request.id }
|
||||
)}
|
||||
>
|
||||
<div className="space-y-1">
|
||||
<div className="space-y-2">
|
||||
<div className="relative flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-2 text-11 font-medium text-tertiary">
|
||||
<div className="flex min-w-0 items-center gap-2 text-11 font-medium text-tertiary">
|
||||
<span>
|
||||
{issue.project_detail?.identifier || "REQ"}-{issue.sequence_id}
|
||||
</span>
|
||||
|
|
@ -71,9 +72,11 @@ export const ExternalContoursListItem = observer(function ExternalContoursListIt
|
|||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
<ExternalContourStatePill request={request} />
|
||||
<div className="shrink-0">
|
||||
<ExternalContourStatePill request={request} />
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="w-full truncate text-13">{issue.name}</h3>
|
||||
<h3 className="w-full text-15 leading-6 font-semibold text-primary">{issue.name}</h3>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
|
|
@ -93,7 +96,7 @@ export const ExternalContoursListItem = observer(function ExternalContoursListIt
|
|||
)}
|
||||
|
||||
{visibleLabels.map((label) => (
|
||||
<div key={label.id} className="relative flex !h-[17.5px] items-center gap-1 rounded-sm border border-strong px-1 text-11">
|
||||
<div key={label.id} className="relative flex h-6 items-center gap-1 rounded-full bg-white/6 px-2 text-11">
|
||||
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: label.color }} />
|
||||
<span className="max-w-28 truncate normal-case">{label.name}</span>
|
||||
</div>
|
||||
|
|
@ -107,7 +110,7 @@ export const ExternalContoursListItem = observer(function ExternalContoursListIt
|
|||
key={assignee.id}
|
||||
src={assignee.avatar_url || ""}
|
||||
name={assignee.display_name || "NODE.DC"}
|
||||
size="md"
|
||||
size="lg"
|
||||
showTooltip
|
||||
/>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -65,20 +65,20 @@ export const ExternalContoursMirroredActivity = observer(function ExternalContou
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-3 py-4">
|
||||
<div className="nodedc-external-section space-y-3 px-4 py-4">
|
||||
<div className="text-body-sm-medium">{t("external_contours_page.mirror.activity_title")}</div>
|
||||
|
||||
{activity.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
{activity.map((item) => (
|
||||
<div key={item.id} className="rounded-md border border-subtle bg-surface-1 px-4 py-3">
|
||||
<div key={item.id} className="nodedc-external-panel px-4 py-3">
|
||||
<div className="text-13 text-primary">{renderMessage(item)}</div>
|
||||
<div className="mt-1 text-11 text-secondary">{renderFormattedDate(item.created_at)}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="rounded-md border border-dashed border-subtle px-4 py-6 text-13 text-secondary">
|
||||
<div className="nodedc-external-empty px-4 py-6 text-13 text-secondary">
|
||||
{t("external_contours_page.mirror.activity_empty")}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const ExternalContoursMirroredAttachments = observer(function ExternalCon
|
|||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="space-y-3 py-4">
|
||||
<div className="nodedc-external-section space-y-3 px-4 py-4">
|
||||
<div className="text-body-sm-medium">{t("external_contours_page.mirror.attachments_title")}</div>
|
||||
|
||||
{attachments.length > 0 ? (
|
||||
|
|
@ -36,7 +36,7 @@ export const ExternalContoursMirroredAttachments = observer(function ExternalCon
|
|||
href={attachment.download_url || "#"}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="flex min-h-[60px] items-center justify-between gap-3 rounded-md border-[2px] border-subtle bg-surface-1 px-4 py-2 text-13 transition-colors hover:bg-surface-2"
|
||||
className="nodedc-external-panel flex min-h-[72px] items-center justify-between gap-3 px-4 py-3 text-13 transition-colors hover:bg-white/6"
|
||||
>
|
||||
<div className="flex items-center gap-3 overflow-hidden">
|
||||
<div className="h-7 w-7 flex-shrink-0">{fileIcon}</div>
|
||||
|
|
@ -55,7 +55,7 @@ export const ExternalContoursMirroredAttachments = observer(function ExternalCon
|
|||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className="rounded-md border border-dashed border-subtle px-4 py-6 text-13 text-secondary">
|
||||
<div className="nodedc-external-empty px-4 py-6 text-13 text-secondary">
|
||||
{t("external_contours_page.mirror.attachments_empty")}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const ExternalContoursMirroredComments = observer(function ExternalContou
|
|||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="space-y-3 py-4">
|
||||
<div className="nodedc-external-section space-y-3 px-4 py-4">
|
||||
<div className="text-body-sm-medium">{t("external_contours_page.mirror.comments_title")}</div>
|
||||
|
||||
{comments.length > 0 ? (
|
||||
|
|
@ -27,7 +27,7 @@ export const ExternalContoursMirroredComments = observer(function ExternalContou
|
|||
{comments.map((comment) => {
|
||||
const actorName = comment.actor_detail?.display_name || t("external_contours_page.mirror.system_actor");
|
||||
return (
|
||||
<div key={comment.id} className="rounded-md border border-subtle bg-surface-1 p-4">
|
||||
<div key={comment.id} className="nodedc-external-panel p-4">
|
||||
<div className="mb-3 flex items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Avatar src={comment.actor_detail?.avatar_url || ""} name={actorName} size="md" />
|
||||
|
|
@ -49,7 +49,7 @@ export const ExternalContoursMirroredComments = observer(function ExternalContou
|
|||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className="rounded-md border border-dashed border-subtle px-4 py-6 text-13 text-secondary">
|
||||
<div className="nodedc-external-empty px-4 py-6 text-13 text-secondary">
|
||||
{t("external_contours_page.mirror.comments_empty")}
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,9 @@ type Props = {
|
|||
};
|
||||
|
||||
const TraceabilityCell = ({ label, children }: { label: string; children: ReactNode }) => (
|
||||
<div className="rounded-md border border-subtle bg-surface-1 p-3">
|
||||
<div className="nodedc-external-panel p-4">
|
||||
<div className="text-11 font-medium text-tertiary">{label}</div>
|
||||
<div className="mt-1 min-h-6 text-13 font-medium text-secondary">{children}</div>
|
||||
<div className="mt-2 min-h-6 text-13 font-medium text-secondary">{children}</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ export const ExternalContoursRequestTraceability = observer(function ExternalCon
|
|||
const assigneeDetails = issue.assignee_details ?? [];
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-subtle bg-surface-2 p-4">
|
||||
<div className="nodedc-external-section p-5">
|
||||
<div className="mb-3">
|
||||
<h5 className="text-body-sm-medium">{t("external_contours_page.traceability.title")}</h5>
|
||||
<p className="mt-1 text-12 text-tertiary">{t("external_contours_page.traceability.description")}</p>
|
||||
|
|
@ -73,7 +73,7 @@ export const ExternalContoursRequestTraceability = observer(function ExternalCon
|
|||
{assigneeDetails.map((assignee) => (
|
||||
<div key={assignee.id} className="flex items-center gap-2">
|
||||
<Avatar src={assignee.avatar_url || ""} name={assignee.display_name || t("common.none")} size="sm" showTooltip />
|
||||
<span className="text-12 font-medium text-secondary">{assignee.display_name}</span>
|
||||
<span className="text-13 font-medium text-secondary">{assignee.display_name}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -90,13 +90,13 @@ export const ExternalContoursRequestTraceability = observer(function ExternalCon
|
|||
{requestedAt ? renderFormattedDate(requestedAt) : t("common.none")}
|
||||
</TraceabilityCell>
|
||||
|
||||
<TraceabilityCell label={t("external_contours_page.traceability.last_updated")}>
|
||||
{lastUpdatedAt ? renderFormattedDate(lastUpdatedAt) : t("common.none")}
|
||||
</TraceabilityCell>
|
||||
|
||||
<TraceabilityCell label={t("external_contours_page.traceability.due_date")}>
|
||||
{dueDate}
|
||||
</TraceabilityCell>
|
||||
|
||||
<TraceabilityCell label={t("external_contours_page.traceability.last_updated")}>
|
||||
{lastUpdatedAt ? renderFormattedDate(lastUpdatedAt) : t("common.none")}
|
||||
</TraceabilityCell>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -97,11 +97,15 @@ export const ExternalContoursRoot = observer(function ExternalContoursRoot(props
|
|||
inboxIssueId={inboxIssueId.toString()}
|
||||
/>
|
||||
) : (
|
||||
<EmptyStateCompact
|
||||
assetKey="intake"
|
||||
title={t("external_contours_page.empty_state.detail_title")}
|
||||
assetClassName="size-20"
|
||||
/>
|
||||
<div className="flex h-full w-full items-center justify-center px-8">
|
||||
<div className="nodedc-external-section max-w-xl px-8 py-10">
|
||||
<EmptyStateCompact
|
||||
assetKey="intake"
|
||||
title={t("external_contours_page.empty_state.detail_title")}
|
||||
assetClassName="size-20"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import { useTranslation } from "@plane/i18n";
|
|||
import { EmptyStateDetailed } from "@plane/propel/empty-state";
|
||||
import type { TInboxIssueCurrentTab } from "@plane/types";
|
||||
import { EInboxIssueCurrentTab } from "@plane/types";
|
||||
import { EHeaderVariant, Header } from "@plane/ui";
|
||||
import { cn } from "@plane/utils";
|
||||
import { useProjectExternalContours } from "@/hooks/store/use-project-external-contours";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
|
|
@ -42,18 +41,20 @@ export const ExternalContoursSidebar = observer(function ExternalContoursSidebar
|
|||
}
|
||||
}, [currentTab, filteredRequestIds, inboxIssueId, projectId, router, workspaceSlug]);
|
||||
|
||||
const currentCount = currentTab === EInboxIssueCurrentTab.CLOSED ? closedRequestIds.length : openRequestIds.length;
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex-shrink-0 border-r border-strong bg-surface-1">
|
||||
<div className="nodedc-external-sidebar-shell h-full w-full flex-shrink-0 border-r border-strong/40">
|
||||
<div className="relative flex h-full w-full flex-col overflow-hidden">
|
||||
<Header variant={EHeaderVariant.SECONDARY}>
|
||||
{tabNavigationOptions.map((option) => (
|
||||
<div
|
||||
<div className="px-4 py-4">
|
||||
<div className="nodedc-filter-row-shell flex items-center gap-2 p-1">
|
||||
{tabNavigationOptions.map((option) => {
|
||||
const count = option.key === EInboxIssueCurrentTab.CLOSED ? closedRequestIds.length : openRequestIds.length;
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
key={option.key}
|
||||
data-active={currentTab === option.key}
|
||||
className={cn(
|
||||
"relative flex h-full cursor-pointer items-center gap-1 px-3 text-13 font-medium transition-all",
|
||||
currentTab === option.key ? "text-accent-primary" : "hover:text-secondary"
|
||||
"nodedc-external-tab flex flex-1 items-center justify-center gap-2 text-13 font-medium transition-all"
|
||||
)}
|
||||
onClick={() => {
|
||||
if (currentTab !== option.key) {
|
||||
|
|
@ -62,33 +63,34 @@ export const ExternalContoursSidebar = observer(function ExternalContoursSidebar
|
|||
}
|
||||
}}
|
||||
>
|
||||
<div>{t(option.i18n_label)}</div>
|
||||
{currentTab === option.key && (
|
||||
<div className="rounded-full bg-accent-primary/20 px-1.5 py-0.5 text-11 font-semibold text-accent-primary">
|
||||
{currentCount}
|
||||
<div>{t(option.i18n_label)}</div>
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-full px-1.5 py-0.5 text-11 font-semibold",
|
||||
currentTab === option.key ? "bg-accent-primary/15 text-accent-primary" : "bg-white/5 text-secondary"
|
||||
)}
|
||||
>
|
||||
{count}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
"absolute right-0 bottom-0 left-0 rounded-t-md border",
|
||||
currentTab === option.key ? "border-accent-strong" : "border-transparent"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</Header>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="vertical-scrollbar scrollbar-md h-full w-full overflow-hidden overflow-y-auto">
|
||||
<div className="vertical-scrollbar scrollbar-md h-full w-full overflow-hidden overflow-y-auto px-4 pb-4">
|
||||
{filteredRequestIds.length > 0 ? (
|
||||
filteredRequestIds.map((requestId) => (
|
||||
<ExternalContoursListItem
|
||||
key={requestId}
|
||||
setIsMobileSidebar={setIsMobileSidebar}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
requestId={requestId}
|
||||
/>
|
||||
))
|
||||
<div className="space-y-3">
|
||||
{filteredRequestIds.map((requestId) => (
|
||||
<ExternalContoursListItem
|
||||
key={requestId}
|
||||
setIsMobileSidebar={setIsMobileSidebar}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
requestId={requestId}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
{currentTab === EInboxIssueCurrentTab.OPEN ? (
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export const ExternalContoursSourceReplyBox = observer(function ExternalContours
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-3 py-4">
|
||||
<div className="nodedc-external-section space-y-3 px-4 py-4">
|
||||
<div className="text-body-sm-medium">{t("external_contours_page.reply.title")}</div>
|
||||
<TextArea
|
||||
value={comment}
|
||||
|
|
@ -55,9 +55,15 @@ export const ExternalContoursSourceReplyBox = observer(function ExternalContours
|
|||
rows={4}
|
||||
placeholder={t("external_contours_page.reply.placeholder")}
|
||||
disabled={isSubmitting}
|
||||
className="nodedc-modal-input min-h-[7rem] resize-none !rounded-[1.2rem] !border-0 !bg-white/4"
|
||||
/>
|
||||
<div className="flex justify-end">
|
||||
<Button variant="primary" onClick={handleSubmit} disabled={isSubmitting || !comment.trim()}>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleSubmit}
|
||||
disabled={isSubmitting || !comment.trim()}
|
||||
className="nodedc-modal-primary-button"
|
||||
>
|
||||
{t("external_contours_page.reply.submit")}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -23,21 +23,18 @@ export function AuthBanner(props: TAuthBanner) {
|
|||
|
||||
if (!message) return <></>;
|
||||
return (
|
||||
<div
|
||||
role="alert"
|
||||
className="relative flex items-center gap-2 rounded-md border border-accent-strong/50 bg-accent-primary/10 p-2"
|
||||
>
|
||||
<div role="alert" className="nodedc-auth-banner relative flex items-center gap-2 p-3">
|
||||
<div className="grid size-4 flex-shrink-0 place-items-center">
|
||||
<Info size={16} className="text-accent-primary" />
|
||||
<Info size={16} className="text-current" />
|
||||
</div>
|
||||
<p className="w-full text-13 font-medium text-accent-primary">{message}</p>
|
||||
<p className="w-full text-13 font-medium text-current">{message}</p>
|
||||
<button
|
||||
type="button"
|
||||
className="relative ml-auto grid size-6 place-items-center rounded-xs text-accent-primary/80 transition-all hover:bg-accent-primary/20"
|
||||
className="relative ml-auto grid size-6 place-items-center rounded-full text-current/80 transition-all hover:bg-white/10"
|
||||
onClick={() => handleBannerData?.(undefined)}
|
||||
aria-label={t("aria_labels.auth_forms.close_alert")}
|
||||
>
|
||||
<CloseIcon className="size-4" />
|
||||
<CloseIcon className="size-4 text-current" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -83,9 +83,9 @@ type TAuthHeaderBase = {
|
|||
|
||||
export function AuthHeaderBase(props: TAuthHeaderBase) {
|
||||
return (
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-h4-semibold text-primary">{props.header}</span>
|
||||
<span className="text-h4-semibold text-placeholder">{props.subHeader}</span>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-[2rem] leading-10 font-semibold text-primary">{props.header}</span>
|
||||
<span className="text-[1.9rem] leading-10 font-semibold text-placeholder">{props.subHeader}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,8 +157,8 @@ export const AuthRoot = observer(function AuthRoot(props: TAuthRoot) {
|
|||
|
||||
function AuthContainer({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="mt-10 flex w-full flex-grow flex-col items-center justify-center py-6">
|
||||
<div className="relative flex w-full max-w-[22.5rem] flex-col gap-6">{children}</div>
|
||||
<div className="mt-6 flex w-full flex-grow flex-col items-center justify-center py-8">
|
||||
<div className="nodedc-auth-shell relative flex w-full max-w-[28rem] flex-col gap-6">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,9 +56,10 @@ export const AuthEmailForm = observer(function AuthEmailForm(props: TAuthEmailFo
|
|||
</label>
|
||||
<div
|
||||
className={cn(
|
||||
`relative flex items-center rounded-md border bg-surface-1`,
|
||||
!isFocused && Boolean(emailError?.email) ? `border-danger-strong` : `border-strong`
|
||||
"nodedc-auth-input-shell relative flex items-center",
|
||||
!isFocused && Boolean(emailError?.email) && "border-danger-strong/0"
|
||||
)}
|
||||
data-error={!isFocused && Boolean(emailError?.email)}
|
||||
onFocus={() => {
|
||||
setIsFocused(true);
|
||||
}}
|
||||
|
|
@ -73,7 +74,7 @@ export const AuthEmailForm = observer(function AuthEmailForm(props: TAuthEmailFo
|
|||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className={`h-10 w-full border-0 disable-autofill-style placeholder:text-placeholder autofill:bg-danger-primary focus:bg-none active:bg-transparent`}
|
||||
className="nodedc-auth-input h-12 w-full pr-12 disable-autofill-style autofill:bg-danger-primary focus:bg-none active:bg-transparent"
|
||||
autoComplete="off"
|
||||
autoFocus
|
||||
ref={inputRef}
|
||||
|
|
@ -100,7 +101,7 @@ export const AuthEmailForm = observer(function AuthEmailForm(props: TAuthEmailFo
|
|||
</p>
|
||||
)}
|
||||
</div>
|
||||
<Button type="submit" variant="primary" className="w-full" size="xl" disabled={isButtonDisabled}>
|
||||
<Button type="submit" variant="primary" className="nodedc-auth-primary-button" size="xl" disabled={isButtonDisabled}>
|
||||
{isSubmitting ? <Spinner height="20px" width="20px" /> : t("common.continue")}
|
||||
</Button>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
<Link
|
||||
data-ph-element={AUTH_TRACKER_ELEMENTS.FORGOT_PASSWORD_FROM_SIGNIN}
|
||||
href={`/accounts/forgot-password?email=${encodeURIComponent(email)}`}
|
||||
className="text-11 font-medium text-accent-primary"
|
||||
className="nodedc-auth-link text-11 font-medium"
|
||||
>
|
||||
{t("auth.common.forgot_password")}
|
||||
</Link>
|
||||
|
|
@ -174,7 +174,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
<label htmlFor="email" className="text-13 font-medium text-tertiary">
|
||||
{t("auth.common.email.label")}
|
||||
</label>
|
||||
<div className={`relative flex items-center rounded-md border border-strong bg-surface-1`}>
|
||||
<div className="nodedc-auth-input-shell relative flex items-center">
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
|
|
@ -182,7 +182,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
value={passwordFormData.email}
|
||||
onChange={(e) => handleFormChange("email", e.target.value)}
|
||||
placeholder={t("auth.common.email.placeholder")}
|
||||
className={`h-10 w-full border-0 disable-autofill-style placeholder:text-placeholder`}
|
||||
className="nodedc-auth-input h-12 w-full pr-12 disable-autofill-style"
|
||||
disabled
|
||||
/>
|
||||
{passwordFormData.email.length > 0 && (
|
||||
|
|
@ -202,7 +202,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
<label htmlFor="password" className="text-13 font-medium text-tertiary">
|
||||
{mode === EAuthModes.SIGN_IN ? t("auth.common.password.label") : t("auth.common.password.set_password")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<div className="nodedc-auth-input-shell relative flex items-center">
|
||||
<Input
|
||||
type={showPassword?.password ? "text" : "password"}
|
||||
id="password"
|
||||
|
|
@ -210,7 +210,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
value={passwordFormData.password}
|
||||
onChange={(e) => handleFormChange("password", e.target.value)}
|
||||
placeholder={t("auth.common.password.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 disable-autofill-style placeholder:text-placeholder"
|
||||
className="nodedc-auth-input h-12 w-full pr-12 disable-autofill-style"
|
||||
onFocus={() => setIsPasswordInputFocused(true)}
|
||||
onBlur={() => setIsPasswordInputFocused(false)}
|
||||
autoComplete="off"
|
||||
|
|
@ -239,7 +239,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
<label htmlFor="confirm-password" className="text-13 font-medium text-tertiary">
|
||||
{t("auth.common.password.confirm_password.label")}
|
||||
</label>
|
||||
<div className="relative flex items-center rounded-md bg-surface-1">
|
||||
<div className="nodedc-auth-input-shell relative flex items-center">
|
||||
<Input
|
||||
type={showPassword?.retypePassword ? "text" : "password"}
|
||||
id="confirm-password"
|
||||
|
|
@ -247,7 +247,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
value={passwordFormData.confirm_password}
|
||||
onChange={(e) => handleFormChange("confirm_password", e.target.value)}
|
||||
placeholder={t("auth.common.password.confirm_password.placeholder")}
|
||||
className="h-10 w-full border border-strong !bg-surface-1 pr-12 disable-autofill-style placeholder:text-placeholder"
|
||||
className="nodedc-auth-input h-12 w-full pr-12 disable-autofill-style"
|
||||
onFocus={() => setIsRetryPasswordInputFocused(true)}
|
||||
onBlur={() => setIsRetryPasswordInputFocused(false)}
|
||||
autoComplete="off"
|
||||
|
|
@ -280,7 +280,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
<div className="space-y-2.5">
|
||||
{mode === EAuthModes.SIGN_IN ? (
|
||||
<>
|
||||
<Button type="submit" variant="primary" className="w-full" size="xl" disabled={isButtonDisabled}>
|
||||
<Button type="submit" variant="primary" className="nodedc-auth-primary-button" size="xl" disabled={isButtonDisabled}>
|
||||
{isSubmitting ? (
|
||||
<Spinner height="20px" width="20px" />
|
||||
) : isSMTPConfigured ? (
|
||||
|
|
@ -295,7 +295,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
data-ph-element={AUTH_TRACKER_ELEMENTS.SIGN_IN_WITH_UNIQUE_CODE}
|
||||
onClick={redirectToUniqueCodeSignIn}
|
||||
variant="secondary"
|
||||
className="w-full"
|
||||
className="nodedc-empty-state-secondary w-full"
|
||||
size="xl"
|
||||
>
|
||||
{t("auth.common.sign_in_with_unique_code")}
|
||||
|
|
@ -303,7 +303,7 @@ export const AuthPasswordForm = observer(function AuthPasswordForm(props: Props)
|
|||
)}
|
||||
</>
|
||||
) : (
|
||||
<Button type="submit" variant="primary" className="w-full" size="xl" disabled={isButtonDisabled}>
|
||||
<Button type="submit" variant="primary" className="nodedc-auth-primary-button" size="xl" disabled={isButtonDisabled}>
|
||||
{isSubmitting ? <Spinner height="20px" width="20px" /> : t("auth_actions.sign_up")}
|
||||
</Button>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ type AuthBaseProps = {
|
|||
|
||||
export function AuthBase({ authType }: AuthBaseProps) {
|
||||
return (
|
||||
<div className="relative z-10 flex h-screen w-screen flex-col items-center overflow-hidden overflow-y-auto px-8 pt-6 pb-10">
|
||||
<div className="relative z-10 flex h-screen w-screen flex-col items-center overflow-hidden overflow-y-auto bg-canvas px-8 pt-8 pb-10">
|
||||
<AuthHeader type={authType} />
|
||||
<AuthRoot authMode={authType} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export const AuthHeader = observer(function AuthHeader({ type }: AuthHeaderProps
|
|||
<Link
|
||||
data-ph-element={AUTH_TRACKER_ELEMENTS.NAVIGATE_TO_SIGN_UP}
|
||||
href={authContentMap[type].linkHref}
|
||||
className="text-body-sm-semibold text-accent-primary hover:underline"
|
||||
className="nodedc-auth-link text-body-sm-semibold"
|
||||
>
|
||||
{t(authContentMap[type].linkText)}
|
||||
</Link>
|
||||
|
|
@ -71,9 +71,9 @@ export function AuthHeaderBase(props: TAuthHeaderBase) {
|
|||
return (
|
||||
<>
|
||||
<PageHead title={pageTitle + " - NODE.DC"} />
|
||||
<div className="sticky top-0 flex w-full flex-shrink-0 items-center justify-between gap-6">
|
||||
<div className="sticky top-0 flex w-full flex-shrink-0 items-center justify-between gap-6 px-2 py-1">
|
||||
<Link href="/">
|
||||
<PlaneLockup height={20} width={95} className="text-primary" />
|
||||
<PlaneLockup height={40} width={190} className="text-primary transition-opacity hover:opacity-90" />
|
||||
</Link>
|
||||
{additionalAction}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
import type { ReactNode } from "react";
|
||||
import Link from "next/link";
|
||||
// plane imports
|
||||
import { SUPPORT_EMAIL } from "@plane/constants";
|
||||
|
||||
export enum EPageTypes {
|
||||
PUBLIC = "PUBLIC",
|
||||
|
|
@ -37,7 +35,6 @@ export enum EErrorAlertType {
|
|||
}
|
||||
|
||||
export enum EAuthenticationErrorCodes {
|
||||
// Global
|
||||
INSTANCE_NOT_CONFIGURED = "5000",
|
||||
INVALID_EMAIL = "5005",
|
||||
EMAIL_REQUIRED = "5010",
|
||||
|
|
@ -45,32 +42,27 @@ export enum EAuthenticationErrorCodes {
|
|||
MAGIC_LINK_LOGIN_DISABLED = "5016",
|
||||
PASSWORD_LOGIN_DISABLED = "5018",
|
||||
USER_ACCOUNT_DEACTIVATED = "5019",
|
||||
// Password strength
|
||||
INVALID_PASSWORD = "5020",
|
||||
PASSWORD_TOO_WEAK = "5021",
|
||||
SMTP_NOT_CONFIGURED = "5025",
|
||||
// Sign Up
|
||||
USER_ALREADY_EXIST = "5030",
|
||||
AUTHENTICATION_FAILED_SIGN_UP = "5035",
|
||||
REQUIRED_EMAIL_PASSWORD_SIGN_UP = "5040",
|
||||
INVALID_EMAIL_SIGN_UP = "5045",
|
||||
INVALID_EMAIL_MAGIC_SIGN_UP = "5050",
|
||||
MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED = "5055",
|
||||
// Sign In
|
||||
USER_DOES_NOT_EXIST = "5060",
|
||||
AUTHENTICATION_FAILED_SIGN_IN = "5065",
|
||||
REQUIRED_EMAIL_PASSWORD_SIGN_IN = "5070",
|
||||
INVALID_EMAIL_SIGN_IN = "5075",
|
||||
INVALID_EMAIL_MAGIC_SIGN_IN = "5080",
|
||||
MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED = "5085",
|
||||
// Both Sign in and Sign up for magic
|
||||
INVALID_MAGIC_CODE_SIGN_IN = "5090",
|
||||
INVALID_MAGIC_CODE_SIGN_UP = "5092",
|
||||
EXPIRED_MAGIC_CODE_SIGN_IN = "5095",
|
||||
EXPIRED_MAGIC_CODE_SIGN_UP = "5097",
|
||||
EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN = "5100",
|
||||
EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP = "5102",
|
||||
// Oauth
|
||||
OAUTH_NOT_CONFIGURED = "5104",
|
||||
GOOGLE_NOT_CONFIGURED = "5105",
|
||||
GITHUB_NOT_CONFIGURED = "5110",
|
||||
|
|
@ -78,16 +70,12 @@ export enum EAuthenticationErrorCodes {
|
|||
GOOGLE_OAUTH_PROVIDER_ERROR = "5115",
|
||||
GITHUB_OAUTH_PROVIDER_ERROR = "5120",
|
||||
GITLAB_OAUTH_PROVIDER_ERROR = "5121",
|
||||
// Reset Password
|
||||
INVALID_PASSWORD_TOKEN = "5125",
|
||||
EXPIRED_PASSWORD_TOKEN = "5130",
|
||||
// Change password
|
||||
INCORRECT_OLD_PASSWORD = "5135",
|
||||
MISSING_PASSWORD = "5138",
|
||||
INVALID_NEW_PASSWORD = "5140",
|
||||
// set password
|
||||
PASSWORD_ALREADY_SET = "5145",
|
||||
// Admin
|
||||
ADMIN_ALREADY_EXIST = "5150",
|
||||
REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME = "5155",
|
||||
INVALID_ADMIN_EMAIL = "5160",
|
||||
|
|
@ -97,7 +85,6 @@ export enum EAuthenticationErrorCodes {
|
|||
ADMIN_USER_ALREADY_EXIST = "5180",
|
||||
ADMIN_USER_DOES_NOT_EXIST = "5185",
|
||||
ADMIN_USER_DEACTIVATED = "5190",
|
||||
// Rate limit
|
||||
RATE_LIMIT_EXCEEDED = "5900",
|
||||
}
|
||||
|
||||
|
|
@ -108,267 +95,246 @@ export type TAuthErrorInfo = {
|
|||
message: ReactNode;
|
||||
};
|
||||
|
||||
// TODO: move all error messages to translation files
|
||||
const authLinkClass = "nodedc-auth-link font-medium";
|
||||
|
||||
const errorCodeMessages: {
|
||||
[key in EAuthenticationErrorCodes]: { title: string; message: (email?: string) => ReactNode };
|
||||
} = {
|
||||
// global
|
||||
[EAuthenticationErrorCodes.INSTANCE_NOT_CONFIGURED]: {
|
||||
title: `Instance not configured`,
|
||||
message: () => `Instance not configured. Please contact your administrator.`,
|
||||
title: "Пространство не настроено",
|
||||
message: () => "Пространство не настроено. Обратитесь к администратору.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_EMAIL]: {
|
||||
title: `Invalid email`,
|
||||
message: () => `Invalid email. Please try again.`,
|
||||
title: "Некорректный e-mail",
|
||||
message: () => "Некорректный e-mail. Проверьте адрес и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.EMAIL_REQUIRED]: {
|
||||
title: `Email required`,
|
||||
message: () => `Email required. Please try again.`,
|
||||
title: "Нужен e-mail",
|
||||
message: () => "Укажите e-mail и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.SIGNUP_DISABLED]: {
|
||||
title: `Sign up disabled`,
|
||||
message: () => `Sign up disabled. Please contact your administrator.`,
|
||||
title: "Регистрация отключена",
|
||||
message: () => "Регистрация отключена. Обратитесь к администратору.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.MAGIC_LINK_LOGIN_DISABLED]: {
|
||||
title: `Magic link login disabled`,
|
||||
message: () => `Magic link login disabled. Please contact your administrator.`,
|
||||
title: "Вход по коду отключён",
|
||||
message: () => "Вход по коду отключён. Обратитесь к администратору.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.PASSWORD_LOGIN_DISABLED]: {
|
||||
title: `Password login disabled`,
|
||||
message: () => `Password login disabled. Please contact your administrator.`,
|
||||
title: "Вход по паролю отключён",
|
||||
message: () => "Вход по паролю отключён. Обратитесь к администратору.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.USER_ACCOUNT_DEACTIVATED]: {
|
||||
title: `User account deactivated`,
|
||||
message: () => `User account deactivated. Please contact ${SUPPORT_EMAIL ? SUPPORT_EMAIL : "administrator"}.`,
|
||||
title: "Аккаунт деактивирован",
|
||||
message: () => "Аккаунт деактивирован. Обратитесь к администратору.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_PASSWORD]: {
|
||||
title: `Invalid password`,
|
||||
message: () => `Invalid password. Please try again.`,
|
||||
title: "Неверный пароль",
|
||||
message: () => "Неверный пароль. Попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.PASSWORD_TOO_WEAK]: {
|
||||
title: `Password too weak`,
|
||||
message: () => `Password must include upper-case, lower-case, number, special character, and must not be predictable.`,
|
||||
title: "Слишком простой пароль",
|
||||
message: () => "Пароль должен содержать строчные и заглавные буквы, цифру и специальный символ.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.SMTP_NOT_CONFIGURED]: {
|
||||
title: `SMTP not configured`,
|
||||
message: () => `SMTP not configured. Please contact your administrator.`,
|
||||
title: "Почта не настроена",
|
||||
message: () => "Почтовый сервис не настроен. Обратитесь к администратору.",
|
||||
},
|
||||
|
||||
// sign up
|
||||
[EAuthenticationErrorCodes.USER_ALREADY_EXIST]: {
|
||||
title: `User already exists`,
|
||||
title: "Аккаунт уже существует",
|
||||
message: (email = undefined) => (
|
||||
<div>
|
||||
Your account is already registered.
|
||||
<Link
|
||||
className="font-medium underline underline-offset-4 transition-all hover:font-bold"
|
||||
href={`/sign-in${email ? `?email=${encodeURIComponent(email)}` : ``}`}
|
||||
>
|
||||
Sign In
|
||||
Аккаунт уже зарегистрирован.
|
||||
<Link className={authLinkClass} href={`/sign-in${email ? `?email=${encodeURIComponent(email)}` : ``}`}>
|
||||
Войти
|
||||
</Link>
|
||||
now.
|
||||
сейчас.
|
||||
</div>
|
||||
),
|
||||
},
|
||||
[EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP]: {
|
||||
title: `Email and password required`,
|
||||
message: () => `Email and password required. Please try again.`,
|
||||
},
|
||||
[EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_UP]: {
|
||||
title: `Authentication failed`,
|
||||
message: () => `Authentication failed. Please try again.`,
|
||||
title: "Не удалось выполнить вход",
|
||||
message: () => "Не удалось выполнить вход. Проверьте данные и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_UP]: {
|
||||
title: "Нужны e-mail и пароль",
|
||||
message: () => "Укажите e-mail и пароль, затем попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_UP]: {
|
||||
title: `Invalid email`,
|
||||
message: () => `Invalid email. Please try again.`,
|
||||
},
|
||||
[EAuthenticationErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED]: {
|
||||
title: `Email and code required`,
|
||||
message: () => `Email and code required. Please try again.`,
|
||||
title: "Некорректный e-mail",
|
||||
message: () => "Некорректный e-mail. Проверьте адрес и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_UP]: {
|
||||
title: `Invalid email`,
|
||||
message: () => `Invalid email. Please try again.`,
|
||||
title: "Некорректный e-mail",
|
||||
message: () => "Некорректный e-mail. Проверьте адрес и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.MAGIC_SIGN_UP_EMAIL_CODE_REQUIRED]: {
|
||||
title: "Нужны e-mail и код",
|
||||
message: () => "Укажите e-mail и код подтверждения, затем попробуйте снова.",
|
||||
},
|
||||
|
||||
[EAuthenticationErrorCodes.USER_DOES_NOT_EXIST]: {
|
||||
title: `User does not exist`,
|
||||
title: "Аккаунт не найден",
|
||||
message: (email = undefined) => (
|
||||
<div>
|
||||
No account found.
|
||||
<Link
|
||||
className="font-medium underline underline-offset-4 transition-all hover:font-bold"
|
||||
href={`/${email ? `?email=${encodeURIComponent(email)}` : ``}`}
|
||||
>
|
||||
Create one
|
||||
Аккаунт не найден.
|
||||
<Link className={authLinkClass} href={`/${email ? `?email=${encodeURIComponent(email)}` : ``}`}>
|
||||
Создать аккаунт
|
||||
</Link>
|
||||
to get started.
|
||||
для начала работы.
|
||||
</div>
|
||||
),
|
||||
},
|
||||
[EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN]: {
|
||||
title: `Email and password required`,
|
||||
message: () => `Email and password required. Please try again.`,
|
||||
},
|
||||
[EAuthenticationErrorCodes.AUTHENTICATION_FAILED_SIGN_IN]: {
|
||||
title: `Authentication failed`,
|
||||
message: () => `Authentication failed. Please try again.`,
|
||||
title: "Не удалось выполнить вход",
|
||||
message: () => "Не удалось выполнить вход. Проверьте данные и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.REQUIRED_EMAIL_PASSWORD_SIGN_IN]: {
|
||||
title: "Нужны e-mail и пароль",
|
||||
message: () => "Укажите e-mail и пароль, затем попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_EMAIL_SIGN_IN]: {
|
||||
title: `Invalid email`,
|
||||
message: () => `Invalid email. Please try again.`,
|
||||
},
|
||||
[EAuthenticationErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED]: {
|
||||
title: `Email and code required`,
|
||||
message: () => `Email and code required. Please try again.`,
|
||||
title: "Некорректный e-mail",
|
||||
message: () => "Некорректный e-mail. Проверьте адрес и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_EMAIL_MAGIC_SIGN_IN]: {
|
||||
title: `Invalid email`,
|
||||
message: () => `Invalid email. Please try again.`,
|
||||
title: "Некорректный e-mail",
|
||||
message: () => "Некорректный e-mail. Проверьте адрес и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.MAGIC_SIGN_IN_EMAIL_CODE_REQUIRED]: {
|
||||
title: "Нужны e-mail и код",
|
||||
message: () => "Укажите e-mail и код подтверждения, затем попробуйте снова.",
|
||||
},
|
||||
|
||||
// Both Sign in and Sign up
|
||||
[EAuthenticationErrorCodes.INVALID_MAGIC_CODE_SIGN_IN]: {
|
||||
title: `Authentication failed`,
|
||||
message: () => `Invalid magic code. Please try again.`,
|
||||
title: "Неверный код подтверждения",
|
||||
message: () => "Код подтверждения неверный. Попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_MAGIC_CODE_SIGN_UP]: {
|
||||
title: `Authentication failed`,
|
||||
message: () => `Invalid magic code. Please try again.`,
|
||||
title: "Неверный код подтверждения",
|
||||
message: () => "Код подтверждения неверный. Попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE_SIGN_IN]: {
|
||||
title: `Expired magic code`,
|
||||
message: () => `Expired magic code. Please try again.`,
|
||||
title: "Код подтверждения истёк",
|
||||
message: () => "Код подтверждения истёк. Запросите новый и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.EXPIRED_MAGIC_CODE_SIGN_UP]: {
|
||||
title: `Expired magic code`,
|
||||
message: () => `Expired magic code. Please try again.`,
|
||||
title: "Код подтверждения истёк",
|
||||
message: () => "Код подтверждения истёк. Запросите новый и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_IN]: {
|
||||
title: `Expired magic code`,
|
||||
message: () => `Expired magic code. Please try again.`,
|
||||
title: "Лимит попыток исчерпан",
|
||||
message: () => "Лимит попыток ввода кода исчерпан. Запросите новый код.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.EMAIL_CODE_ATTEMPT_EXHAUSTED_SIGN_UP]: {
|
||||
title: `Expired magic code`,
|
||||
message: () => `Expired magic code. Please try again.`,
|
||||
title: "Лимит попыток исчерпан",
|
||||
message: () => "Лимит попыток ввода кода исчерпан. Запросите новый код.",
|
||||
},
|
||||
|
||||
// Oauth
|
||||
[EAuthenticationErrorCodes.OAUTH_NOT_CONFIGURED]: {
|
||||
title: `OAuth not configured`,
|
||||
message: () => `OAuth not configured. Please contact your administrator.`,
|
||||
title: "OAuth не настроен",
|
||||
message: () => "OAuth не настроен. Обратитесь к администратору.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.GOOGLE_NOT_CONFIGURED]: {
|
||||
title: `Google not configured`,
|
||||
message: () => `Google not configured. Please contact your administrator.`,
|
||||
title: "Google OAuth не настроен",
|
||||
message: () => "Google OAuth не настроен. Обратитесь к администратору.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.GITHUB_NOT_CONFIGURED]: {
|
||||
title: `GitHub not configured`,
|
||||
message: () => `GitHub not configured. Please contact your administrator.`,
|
||||
title: "GitHub OAuth не настроен",
|
||||
message: () => "GitHub OAuth не настроен. Обратитесь к администратору.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.GITLAB_NOT_CONFIGURED]: {
|
||||
title: `GitLab not configured`,
|
||||
message: () => `GitLab not configured. Please contact your administrator.`,
|
||||
title: "GitLab OAuth не настроен",
|
||||
message: () => "GitLab OAuth не настроен. Обратитесь к администратору.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.GOOGLE_OAUTH_PROVIDER_ERROR]: {
|
||||
title: `Google OAuth provider error`,
|
||||
message: () => `Google OAuth provider error. Please try again.`,
|
||||
title: "Ошибка Google OAuth",
|
||||
message: () => "Не удалось авторизоваться через Google. Попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.GITHUB_OAUTH_PROVIDER_ERROR]: {
|
||||
title: `GitHub OAuth provider error`,
|
||||
message: () => `GitHub OAuth provider error. Please try again.`,
|
||||
title: "Ошибка GitHub OAuth",
|
||||
message: () => "Не удалось авторизоваться через GitHub. Попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.GITLAB_OAUTH_PROVIDER_ERROR]: {
|
||||
title: `GitLab OAuth provider error`,
|
||||
message: () => `GitLab OAuth provider error. Please try again.`,
|
||||
title: "Ошибка GitLab OAuth",
|
||||
message: () => "Не удалось авторизоваться через GitLab. Попробуйте снова.",
|
||||
},
|
||||
|
||||
// Reset Password
|
||||
[EAuthenticationErrorCodes.INVALID_PASSWORD_TOKEN]: {
|
||||
title: `Invalid password token`,
|
||||
message: () => `Invalid password token.`,
|
||||
title: "Некорректный токен",
|
||||
message: () => "Токен сброса пароля некорректен.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.EXPIRED_PASSWORD_TOKEN]: {
|
||||
title: `Expired password token`,
|
||||
message: () => `Expired password token. Please try again.`,
|
||||
title: "Токен истёк",
|
||||
message: () => "Токен сброса пароля истёк. Запросите новый.",
|
||||
},
|
||||
|
||||
// Change password
|
||||
[EAuthenticationErrorCodes.MISSING_PASSWORD]: {
|
||||
title: `Password required`,
|
||||
message: () => `Password required. Please try again.`,
|
||||
title: "Нужен пароль",
|
||||
message: () => "Укажите пароль и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INCORRECT_OLD_PASSWORD]: {
|
||||
title: `Incorrect old password`,
|
||||
message: () => `Incorrect old password. Please try again.`,
|
||||
title: "Неверный старый пароль",
|
||||
message: () => "Неверный старый пароль. Попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_NEW_PASSWORD]: {
|
||||
title: `Invalid new password`,
|
||||
message: () => `Invalid new password. Please try again.`,
|
||||
title: "Некорректный новый пароль",
|
||||
message: () => "Некорректный новый пароль. Проверьте требования и попробуйте снова.",
|
||||
},
|
||||
|
||||
// set password
|
||||
[EAuthenticationErrorCodes.PASSWORD_ALREADY_SET]: {
|
||||
title: `Password already set`,
|
||||
message: () => `Password already set. Please try again.`,
|
||||
title: "Пароль уже установлен",
|
||||
message: () => "Пароль уже установлен. Попробуйте войти в систему.",
|
||||
},
|
||||
|
||||
// admin
|
||||
[EAuthenticationErrorCodes.ADMIN_ALREADY_EXIST]: {
|
||||
title: `Admin already exists`,
|
||||
message: () => `Admin already exists. Please try again.`,
|
||||
title: "Администратор уже существует",
|
||||
message: () => "Администратор уже существует. Проверьте данные и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD_FIRST_NAME]: {
|
||||
title: `Email, password and first name required`,
|
||||
message: () => `Email, password and first name required. Please try again.`,
|
||||
title: "Нужны имя, e-mail и пароль",
|
||||
message: () => "Укажите имя, e-mail и пароль, затем попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_ADMIN_EMAIL]: {
|
||||
title: `Invalid admin email`,
|
||||
message: () => `Invalid admin email. Please try again.`,
|
||||
title: "Некорректный e-mail администратора",
|
||||
message: () => "Некорректный e-mail администратора. Проверьте адрес и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.INVALID_ADMIN_PASSWORD]: {
|
||||
title: `Invalid admin password`,
|
||||
message: () => `Invalid admin password. Please try again.`,
|
||||
title: "Некорректный пароль администратора",
|
||||
message: () => "Некорректный пароль администратора. Проверьте данные и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.REQUIRED_ADMIN_EMAIL_PASSWORD]: {
|
||||
title: `Email and password required`,
|
||||
message: () => `Email and password required. Please try again.`,
|
||||
title: "Нужны e-mail и пароль",
|
||||
message: () => "Укажите e-mail и пароль, затем попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.ADMIN_AUTHENTICATION_FAILED]: {
|
||||
title: `Authentication failed`,
|
||||
message: () => `Authentication failed. Please try again.`,
|
||||
title: "Не удалось выполнить вход",
|
||||
message: () => "Не удалось выполнить вход. Проверьте данные и попробуйте снова.",
|
||||
},
|
||||
[EAuthenticationErrorCodes.ADMIN_USER_ALREADY_EXIST]: {
|
||||
title: `Admin user already exists`,
|
||||
title: "Администратор уже существует",
|
||||
message: () => (
|
||||
<div>
|
||||
Admin user already exists.
|
||||
<Link className="font-medium underline underline-offset-4 transition-all hover:font-bold" href={`/admin`}>
|
||||
Sign In
|
||||
Администратор уже существует.
|
||||
<Link className={authLinkClass} href="/admin">
|
||||
Войти
|
||||
</Link>
|
||||
now.
|
||||
сейчас.
|
||||
</div>
|
||||
),
|
||||
},
|
||||
[EAuthenticationErrorCodes.ADMIN_USER_DOES_NOT_EXIST]: {
|
||||
title: `Admin user does not exist`,
|
||||
title: "Администратор не найден",
|
||||
message: () => (
|
||||
<div>
|
||||
Admin user does not exist.
|
||||
<Link className="font-medium underline underline-offset-4 transition-all hover:font-bold" href={`/admin`}>
|
||||
Sign In
|
||||
Администратор не найден.
|
||||
<Link className={authLinkClass} href="/admin">
|
||||
Войти
|
||||
</Link>
|
||||
now.
|
||||
сейчас.
|
||||
</div>
|
||||
),
|
||||
},
|
||||
[EAuthenticationErrorCodes.ADMIN_USER_DEACTIVATED]: {
|
||||
title: `Admin user deactivated`,
|
||||
message: () => <div>Your account is deactivated</div>,
|
||||
title: "Аккаунт администратора деактивирован",
|
||||
message: () => <div>Аккаунт администратора деактивирован.</div>,
|
||||
},
|
||||
[EAuthenticationErrorCodes.RATE_LIMIT_EXCEEDED]: {
|
||||
title: "",
|
||||
message: () => `Rate limit exceeded. Please try again later.`,
|
||||
message: () => "Слишком много попыток. Повторите позже.",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -427,13 +393,14 @@ export const authErrorHandler = (errorCode: EAuthenticationErrorCodes, email?: s
|
|||
EAuthenticationErrorCodes.PASSWORD_TOO_WEAK,
|
||||
];
|
||||
|
||||
if (bannerAlertErrorCodes.includes(errorCode))
|
||||
if (bannerAlertErrorCodes.includes(errorCode)) {
|
||||
return {
|
||||
type: EErrorAlertType.BANNER_ALERT,
|
||||
code: errorCode,
|
||||
title: errorCodeMessages[errorCode]?.title || "Error",
|
||||
message: errorCodeMessages[errorCode]?.message(email) || "Something went wrong. Please try again.",
|
||||
title: errorCodeMessages[errorCode]?.title || "Ошибка",
|
||||
message: errorCodeMessages[errorCode]?.message(email) || "Что-то пошло не так. Попробуйте снова.",
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -795,4 +795,239 @@
|
|||
outline: none !important;
|
||||
border-radius: 0.95rem !important;
|
||||
}
|
||||
|
||||
.nodedc-auth-shell {
|
||||
width: 100%;
|
||||
max-width: 28rem;
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.75rem !important;
|
||||
padding: 1.75rem !important;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.04) 0%, rgba(255, 255, 255, 0.015) 100%),
|
||||
rgba(10, 10, 12, 0.82) !important;
|
||||
-webkit-backdrop-filter: blur(34px);
|
||||
backdrop-filter: blur(34px);
|
||||
}
|
||||
|
||||
.nodedc-auth-banner {
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.15rem !important;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.038) 0%, rgba(255, 255, 255, 0.014) 100%),
|
||||
rgba(var(--nodedc-accent-rgb), 0.12) !important;
|
||||
color: rgb(var(--nodedc-accent-rgb)) !important;
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
backdrop-filter: blur(24px);
|
||||
}
|
||||
|
||||
.nodedc-auth-input-shell {
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.15rem !important;
|
||||
min-height: 3rem;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.028) 0%, rgba(255, 255, 255, 0.012) 100%),
|
||||
rgba(255, 255, 255, 0.03) !important;
|
||||
-webkit-backdrop-filter: blur(18px);
|
||||
backdrop-filter: blur(18px);
|
||||
}
|
||||
|
||||
.nodedc-auth-input-shell[data-error="true"] {
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, rgba(255, 255, 255, 0.012) 100%),
|
||||
rgba(255, 82, 82, 0.08) !important;
|
||||
}
|
||||
|
||||
.nodedc-auth-input {
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
background: transparent !important;
|
||||
color: var(--text-color-primary) !important;
|
||||
}
|
||||
|
||||
.nodedc-auth-input::placeholder {
|
||||
color: var(--text-color-placeholder) !important;
|
||||
}
|
||||
|
||||
.nodedc-auth-link {
|
||||
color: rgb(var(--nodedc-accent-rgb)) !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.nodedc-auth-link:hover {
|
||||
color: color-mix(in srgb, rgb(var(--nodedc-accent-rgb)) 82%, white) !important;
|
||||
}
|
||||
|
||||
.nodedc-auth-primary-button {
|
||||
width: 100%;
|
||||
min-height: 3.25rem;
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.25rem !important;
|
||||
background: rgb(var(--nodedc-card-active-rgb)) !important;
|
||||
color: #0b1117 !important;
|
||||
}
|
||||
|
||||
.nodedc-auth-primary-button:hover {
|
||||
background: color-mix(in srgb, rgb(var(--nodedc-card-active-rgb)) 82%, white) !important;
|
||||
color: #0b1117 !important;
|
||||
}
|
||||
|
||||
.nodedc-error-shell {
|
||||
width: 100%;
|
||||
max-width: 36rem;
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.9rem !important;
|
||||
padding: 2rem !important;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.04) 0%, rgba(255, 255, 255, 0.015) 100%),
|
||||
rgba(10, 10, 12, 0.82) !important;
|
||||
-webkit-backdrop-filter: blur(36px);
|
||||
backdrop-filter: blur(36px);
|
||||
}
|
||||
|
||||
.nodedc-error-link {
|
||||
color: rgb(var(--nodedc-accent-rgb)) !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.nodedc-error-link:hover {
|
||||
color: color-mix(in srgb, rgb(var(--nodedc-accent-rgb)) 82%, white) !important;
|
||||
}
|
||||
|
||||
.nodedc-error-primary {
|
||||
min-height: 3rem;
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.2rem !important;
|
||||
background: rgb(var(--nodedc-card-active-rgb)) !important;
|
||||
color: #0b1117 !important;
|
||||
padding-inline: 1.35rem !important;
|
||||
}
|
||||
|
||||
.nodedc-error-primary:hover {
|
||||
background: color-mix(in srgb, rgb(var(--nodedc-card-active-rgb)) 82%, white) !important;
|
||||
color: #0b1117 !important;
|
||||
}
|
||||
|
||||
.nodedc-empty-state-primary {
|
||||
min-height: 3rem;
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.2rem !important;
|
||||
background: rgb(var(--nodedc-card-active-rgb)) !important;
|
||||
color: #0b1117 !important;
|
||||
padding-inline: 1.35rem !important;
|
||||
}
|
||||
|
||||
.nodedc-empty-state-primary:hover {
|
||||
background: color-mix(in srgb, rgb(var(--nodedc-card-active-rgb)) 82%, white) !important;
|
||||
color: #0b1117 !important;
|
||||
}
|
||||
|
||||
.nodedc-empty-state-secondary {
|
||||
min-height: 3rem;
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.2rem !important;
|
||||
background: rgba(255, 255, 255, 0.06) !important;
|
||||
color: var(--text-color-primary) !important;
|
||||
padding-inline: 1.25rem !important;
|
||||
}
|
||||
|
||||
.nodedc-empty-state-secondary:hover {
|
||||
background: rgba(255, 255, 255, 0.1) !important;
|
||||
color: var(--text-color-primary) !important;
|
||||
}
|
||||
|
||||
.nodedc-external-sidebar-shell {
|
||||
border: 0 !important;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, rgba(255, 255, 255, 0.01) 100%),
|
||||
rgba(8, 8, 11, 0.82) !important;
|
||||
-webkit-backdrop-filter: blur(26px);
|
||||
backdrop-filter: blur(26px);
|
||||
}
|
||||
|
||||
.nodedc-external-tab {
|
||||
min-height: 2.8rem;
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 999px !important;
|
||||
background: transparent !important;
|
||||
color: rgba(255, 255, 255, 0.78) !important;
|
||||
padding-inline: 1rem !important;
|
||||
}
|
||||
|
||||
.nodedc-external-tab:hover {
|
||||
background: rgba(255, 255, 255, 0.05) !important;
|
||||
color: var(--text-color-primary) !important;
|
||||
}
|
||||
|
||||
.nodedc-external-tab[data-active="true"] {
|
||||
background: rgba(255, 255, 255, 0.06) !important;
|
||||
color: rgb(var(--nodedc-accent-rgb)) !important;
|
||||
}
|
||||
|
||||
.nodedc-external-card {
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.9rem !important;
|
||||
background: rgb(var(--nodedc-card-passive-rgb)) !important;
|
||||
color: var(--text-color-primary) !important;
|
||||
}
|
||||
|
||||
.nodedc-external-card[data-active="true"] {
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.028) 0%, rgba(255, 255, 255, 0.01) 100%),
|
||||
rgba(255, 255, 255, 0.04) !important;
|
||||
box-shadow: inset 0 0 0 1px rgba(var(--nodedc-accent-rgb), 0.3);
|
||||
}
|
||||
|
||||
.nodedc-external-panel {
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.6rem !important;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, rgba(255, 255, 255, 0.012) 100%),
|
||||
rgba(255, 255, 255, 0.028) !important;
|
||||
-webkit-backdrop-filter: blur(22px);
|
||||
backdrop-filter: blur(22px);
|
||||
}
|
||||
|
||||
.nodedc-external-section {
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.5rem !important;
|
||||
background:
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.028) 0%, rgba(255, 255, 255, 0.012) 100%),
|
||||
rgba(255, 255, 255, 0.024) !important;
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
backdrop-filter: blur(20px);
|
||||
}
|
||||
|
||||
.nodedc-external-empty {
|
||||
border: 0 !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 1.35rem !important;
|
||||
background: rgba(255, 255, 255, 0.035) !important;
|
||||
color: var(--text-color-secondary) !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,16 @@ export function EmptyStateDetailed({
|
|||
{actions.map((action, index) => {
|
||||
const { label, variant, ...rest } = action;
|
||||
return (
|
||||
<Button key={index} variant={variant} size="xl" {...rest}>
|
||||
<Button
|
||||
key={index}
|
||||
variant={variant}
|
||||
size="xl"
|
||||
className={cn({
|
||||
"nodedc-empty-state-primary": variant === "primary",
|
||||
"nodedc-empty-state-secondary": variant === "secondary",
|
||||
})}
|
||||
{...rest}
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue