phirepass-widgets 0.0.53 → 0.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/cjs/{index-DqslB2R4.js → index-YW0ts9D0.js} +0 -37
  2. package/dist/cjs/loader.cjs.js +2 -2
  3. package/dist/cjs/phirepass-sftp-client.cjs.entry.js +462 -83
  4. package/dist/cjs/phirepass-terminal.cjs.entry.js +3 -3
  5. package/dist/cjs/phirepass-widgets.cjs.js +2 -2
  6. package/dist/cjs/{protocol-D_0VKXs_.js → protocol-DPi8rcp9.js} +5 -1
  7. package/dist/collection/common/protocol.js +4 -0
  8. package/dist/collection/components/phirepass-sftp-client/phirepass-sftp-client.css +53 -40
  9. package/dist/collection/components/phirepass-sftp-client/phirepass-sftp-client.js +462 -81
  10. package/dist/collection/components/phirepass-terminal/phirepass-terminal.js +1 -1
  11. package/dist/components/index.js +1 -1
  12. package/dist/components/p-D7u6YzKp.js +1 -0
  13. package/dist/components/phirepass-sftp-client.js +1 -1
  14. package/dist/components/phirepass-terminal.js +2 -2
  15. package/dist/esm/{index-jdexunMF.js → index-PKnTMZa7.js} +0 -37
  16. package/dist/esm/loader.js +3 -3
  17. package/dist/esm/phirepass-sftp-client.entry.js +462 -83
  18. package/dist/esm/phirepass-terminal.entry.js +3 -3
  19. package/dist/esm/phirepass-widgets.js +3 -3
  20. package/dist/esm/{protocol-BYaVbj9C.js → protocol-D7u6YzKp.js} +4 -0
  21. package/dist/phirepass-widgets/p-21fb3b58.entry.js +1 -0
  22. package/dist/phirepass-widgets/p-D7u6YzKp.js +1 -0
  23. package/dist/phirepass-widgets/p-PKnTMZa7.js +2 -0
  24. package/dist/phirepass-widgets/{p-a6553a86.entry.js → p-fec100bd.entry.js} +2 -2
  25. package/dist/phirepass-widgets/phirepass-widgets.esm.js +1 -1
  26. package/dist/types/common/protocol.d.ts +37 -2
  27. package/dist/types/components/phirepass-sftp-client/phirepass-sftp-client.d.ts +28 -5
  28. package/package.json +1 -1
  29. package/dist/components/p-BYaVbj9C.js +0 -1
  30. package/dist/phirepass-widgets/p-BYaVbj9C.js +0 -1
  31. package/dist/phirepass-widgets/p-ba7d75c5.entry.js +0 -1
  32. package/dist/phirepass-widgets/p-jdexunMF.js +0 -2
@@ -1,5 +1,5 @@
1
- import { r as registerInstance, c as createEvent, h, H as Host } from './index-jdexunMF.js';
2
- import { _ as __wbg_init, E as ErrorType, C as Channel, a as ConnectionState, P as ProtocolMessageType } from './protocol-BYaVbj9C.js';
1
+ import { r as registerInstance, c as createEvent, h, H as Host } from './index-PKnTMZa7.js';
2
+ import { _ as __wbg_init, E as ErrorType, C as Channel, a as ConnectionState, P as ProtocolMessageType } from './protocol-D7u6YzKp.js';
3
3
 
4
4
  const phirepassSftpClientLogoSvg = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIgogICAgc3Ryb2tlPSJyZ2IoNDYsIDE4NCwgMTM4KSIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiCiAgICBjbGFzcz0ibHVjaWRlIGx1Y2lkZS10ZXJtaW5hbCB3LTMuNSBoLTMuNSB0ZXh0LXByaW1hcnkiPgogICAgPHBvbHlsaW5lIHBvaW50cz0iNCAxNyAxMCAxMSA0IDUiPjwvcG9seWxpbmU+CiAgICA8bGluZSB4MT0iMTIiIHgyPSIyMCIgeTE9IjE5IiB5Mj0iMTkiPjwvbGluZT4KPC9zdmc+Cg==';
5
5
 
@@ -17,7 +17,7 @@ const phirepassSftpClientRefreshSvg = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0
17
17
 
18
18
  const phirepassSftpClientUploadSvg = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIgogICAgc3Ryb2tlPSJyZ2IoMTg5LCAyMTksIDIwOSkiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIgogICAgY2xhc3M9Imx1Y2lkZSBsdWNpZGUtdXBsb2FkIHctMy41IGgtMy41Ij4KICAgIDxwYXRoIGQ9Ik0yMSAxNXY0YTIgMiAwIDAgMS0yIDJINWEyIDIgMCAwIDEtMi0ydi00Ij48L3BhdGg+CiAgICA8cG9seWxpbmUgcG9pbnRzPSIxNyA4IDEyIDMgNyA4Ij48L3BvbHlsaW5lPgogICAgPGxpbmUgeDE9IjEyIiB4Mj0iMTIiIHkxPSIzIiB5Mj0iMTUiPjwvbGluZT4KPC9zdmc+Cg==';
19
19
 
20
- const phirepassSftpClientCss = () => `:host{--radius:0.375rem;--card:220 18% 10%;--border:220 15% 18%;--primary:160 60% 45%;--radius:0.375rem;--destructive:0 70% 50%;--muted:220 15% 13%;--muted-foreground:220 10% 50%;--primary-foreground:220 20% 7%;--scroll-track:220 16% 12%;--scroll-thumb:220 12% 34%;--scroll-thumb-hover:160 45% 44%;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;height:100%;width:100%;border:1px solid hsl(var(--border));background-color:hsl(var(--card));border-radius:var(--radius);overflow:hidden;display:flex;flex-direction:column;position:relative;container-type:inline-size;.listing{height:100%;display:flex;flex-direction:column;justify-content:space-between;min-height:0;header{height:30px;background:rgba(28, 31, 38, 0.6);border-bottom:1px solid hsl(var(--border));display:flex;align-items:center;justify-content:space-between;.actions{display:flex;align-items:center;.action{cursor:pointer;padding:4px;display:flex;align-items:center;z-index:1;img{height:14px;padding:4px;border-radius:4px}&:hover{background-color:hsl(var(--border) / 0.6)}}}.title{color:hsl(var(--primary));height:14px;padding:0 12px;display:flex;align-items:center;font-size:0.75rem;line-height:1rem;img{height:14px;margin-right:5px}.text{display:flex;flex-direction:row;justify-content:center;margin-top:2px;.name{margin-right:10px}.description{color:hsl(var(--muted-foreground))}}}}main{flex:1;display:flex;flex-direction:column;position:relative;min-height:0;overflow:hidden;.loader{color:hsl(var(--muted-foreground));font-size:13px;animation:pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;text-align:center;display:flex;align-items:center;justify-content:center;position:absolute;height:100%;width:100%;background:rgba(28, 31, 38, 0);backdrop-filter:blur(4px)}.error{font-size:13px;text-align:center;color:hsl(var(--destructive));height:100%;display:flex;align-items:center;justify-content:center}.navigation{height:25px;padding:10px;font-size:0.75rem;line-height:1rem;background-color:hsl(var(--card));display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid hsl(var(--border));position:sticky;top:0;z-index:3;.breadcrumbs{display:flex;align-items:center;margin-right:10px;.breadcrumb{color:hsl(var(--primary));margin-right:4px;cursor:pointer;&:after{margin-left:4px}&:hover{color:rgb(189, 219, 209)}&:last-child{margin-right:0;color:rgb(189, 219, 209);cursor:default}}.arrow{height:12px;width:12px;opacity:0.6;top:2px;margin-right:4px;position:relative}}.actions{display:flex;align-items:center;gap:8px}.action{border:none;background:transparent;color:rgb(189, 219, 209);font-size:1.1rem;line-height:1;padding:2px 4px;border-radius:4px;cursor:pointer;&:hover{background-color:hsl(var(--border) / 0.6)}img{height:14px;width:14px;display:block}}.action.disconnect{color:#ff4d5f;font-size:0.65rem;letter-spacing:0.08em;padding:4px 8px;&:hover{color:#ff6b7a;background-color:hsl(var(--destructive) / 0.12)}}}.content{flex:1;min-height:0;overflow:auto;font-size:0.75rem;line-height:1rem;scrollbar-width:thin;scrollbar-color:hsl(var(--scroll-thumb)) hsl(var(--scroll-track));&::-webkit-scrollbar{width:10px;height:10px}&::-webkit-scrollbar-track{background:hsl(var(--scroll-track))}&::-webkit-scrollbar-thumb{background:hsl(var(--scroll-thumb));border-radius:999px;border:2px solid hsl(var(--scroll-track))}&::-webkit-scrollbar-thumb:hover{background:hsl(var(--scroll-thumb-hover))}table{width:100%;border-collapse:separate;border-spacing:0;table-layout:auto;thead{background-color:hsl(var(--muted));border-bottom:1px solid hsl(var(--border));th{padding:8px 10px;text-align:left;color:hsl(var(--muted-foreground));position:sticky;top:0;z-index:2;background-color:hsl(var(--muted));border-bottom:1px solid hsl(var(--border));line-height:0.95rem;&.action-col{width:58px;min-width:58px;padding:0 10px}&:first-child{width:30%;min-width:180px;max-width:195px}&:nth-child(2),&:nth-child(3),&:nth-child(4),&:nth-child(5){white-space:nowrap;width:1%}}}tbody{padding:10px 10px;tr{border-bottom:1px solid hsl(var(--border) / 0.4);td{padding:10px 10px 9px;color:hsl(var(--muted-foreground));&:first-child{min-width:180px;max-width:195px;white-space:nowrap;.name{display:inline-block;max-width:calc(100% - 26px);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}}&:nth-child(2),&:nth-child(3),&:nth-child(4),&:nth-child(5){white-space:nowrap}&.action-col{width:58px;min-width:58px;text-align:center;padding-left:1px;padding-right:1px;.file-actions{display:flex;align-items:center;justify-content:center;gap:8px}.file-action{border:none;background:transparent;color:hsl(var(--muted-foreground));width:16px;height:16px;border-radius:3px;cursor:pointer;opacity:0;visibility:hidden;pointer-events:none;transition:opacity 120ms ease;padding:0;svg{width:12px;height:12px;display:block;margin:0 auto}&:hover{color:hsl(var(--primary))}&.delete:hover{color:hsl(var(--destructive))}}}.name{&.file{color:rgb(189, 219, 209)}&.folder{color:hsl(var(--primary))}}.kind{height:14px;width:14px;margin-right:5px;top:3px;position:relative}}&:hover{cursor:pointer;background-color:hsl(var(--muted) / 0.4);td.action-col .file-action{opacity:1;visibility:visible;pointer-events:auto;color:hsl(var(--primary))}}&.selected{background-color:hsl(var(--primary) / 0.3);td.action-col .file-action{opacity:1;visibility:visible;pointer-events:auto}&:hover{background-color:hsl(var(--primary) / 0.4)}}}}}}}footer{height:25px;background:rgba(28, 31, 38, 0.6);border-top:1px solid hsl(var(--border));font-size:0.75rem;line-height:1rem;display:flex;align-items:center;justify-content:space-between;padding:0 10px;.status{font-size:0.65rem;color:hsl(var(--muted-foreground));.selected-item{margin-left:10px;color:hsl(var(--primary))}}.version{font-size:0.65rem;color:hsl(var(--muted-foreground))}}}.creds{position:absolute;top:0;left:0;height:100%;width:100%;display:flex;justify-content:center;align-items:center;;&.blurred{background:rgba(28, 31, 38, 0);backdrop-filter:blur(4px)}.auth{display:flex;flex-direction:column;background:hsl(var(--card));position:relative;background-color:rgba(21, 24, 30, 0.95);border:1px solid hsl(var(--border));padding:30px;box-shadow:rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.5) 0px 25px 50px -12px;border-radius:var(--radius);.title{margin-bottom:12px;color:hsl(var(--primary))}label{font-size:0.75rem;line-height:1rem;margin-bottom:1rem;color:hsl(var(--muted-foreground))}input{font-size:0.875rem;line-height:1.25rem;padding-top:0.5rem;padding-bottom:0.5rem;padding-left:0.75rem;padding-right:0.75rem;background-color:rgb(28, 31, 38);border-color:rgb(39, 44, 53);border-width:1px;border-radius:calc(var(--radius) - 2px);width:100%;margin-bottom:12px;color:rgb(189, 219, 209);box-sizing:border-box;&:focus{outline:none;border-color:hsl(var(--primary));box-shadow:0 0 0 1px hsl(var(--primary))}}button[type='submit']{margin-top:12px;width:100%;background-color:hsl(var(--primary));color:hsl(var(--primary-foreground));letter-spacing:0.05em;font-size:13px;font-weight:500;padding:0.5rem 1rem;border-radius:calc(var(--radius) - 2px);height:2rem;cursor:pointer;border:none;&:hover{background-color:hsl(var(--primary) / 0.9)}}}}.upload-modal,.download-modal,.delete-modal{position:absolute;inset:0;display:none;align-items:center;justify-content:center;background:rgba(28, 31, 38, 0);backdrop-filter:blur(4px);z-index:6;&.visible{display:flex}.upload-dialog,.download-dialog,.delete-dialog{width:min(360px, calc(100% - 24px));background-color:rgba(21, 24, 30, 0.96);border:1px solid hsl(var(--border));border-radius:var(--radius);padding:16px;box-shadow:rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.5) 0px 25px 50px -12px;.title{color:hsl(var(--primary));font-size:0.8rem;margin-bottom:8px}.file-name{color:rgb(189, 219, 209);font-size:0.72rem;line-height:1rem;margin-bottom:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.progress-track{width:100%;height:10px;border-radius:999px;background-color:hsl(var(--muted));overflow:hidden;border:1px solid hsl(var(--border));.progress-fill{height:100%;width:0;background:linear-gradient(90deg, hsl(var(--primary) / 0.7), hsl(var(--primary)));transition:width 140ms ease}}.progress-value{margin-top:8px;color:hsl(var(--muted-foreground));font-size:0.7rem;text-align:right}.cancel{margin-top:14px;width:100%;height:2rem;border:1px solid hsl(var(--border));border-radius:calc(var(--radius) - 2px);background:hsl(var(--muted));color:rgb(189, 219, 209);font-size:0.75rem;letter-spacing:0.03em;cursor:pointer;&:hover{border-color:hsl(var(--primary));color:hsl(var(--primary))}&.finished{background-color:hsl(var(--primary));border-color:hsl(var(--primary));color:hsl(var(--primary-foreground));&:hover{background-color:hsl(var(--primary) / 0.9);border-color:hsl(var(--primary) / 0.9);color:hsl(var(--primary-foreground))}}}.message{color:rgb(189, 219, 209);font-size:0.74rem;line-height:1rem;margin-bottom:8px}.modal-actions{margin-top:14px;display:grid;grid-template-columns:1fr 1fr;gap:8px;.btn{height:2rem;border:1px solid hsl(var(--border));border-radius:calc(var(--radius) - 2px);font-size:0.75rem;letter-spacing:0.03em;cursor:pointer;&:disabled{opacity:0.65;cursor:not-allowed}}.btn.secondary{background:hsl(var(--muted));color:rgb(189, 219, 209);&:hover{border-color:hsl(var(--primary));color:hsl(var(--primary))}}.btn.destructive{background:hsl(var(--destructive));border-color:hsl(var(--destructive));color:white;&:hover{background:hsl(var(--destructive) / 0.9);border-color:hsl(var(--destructive) / 0.9)}}}.delete-loading-bar{margin-top:2px;width:100%;height:8px;border-radius:999px;border:1px solid hsl(var(--border));background:linear-gradient(90deg, hsl(var(--muted)) 0%, hsl(var(--muted)) 100%), linear-gradient(90deg, hsl(var(--primary) / 0.3), hsl(var(--primary)), hsl(var(--primary) / 0.3));background-repeat:no-repeat;background-size:100% 100%, 40% 100%;animation:delete-loading 1s linear infinite}}}}@keyframes delete-loading{from{background-position:0 0, -45% 0}to{background-position:0 0, 145% 0}}:host(.max){height:100vh;width:100vw;position:fixed;top:0;left:0;z-index:9999}@container (max-width: 699px){:host .listing main .content table thead th:nth-child(4),:host .listing main .content table tbody td:nth-child(4){display:none}}@container (max-width: 635px){:host .listing main .content table thead th:nth-child(3),:host .listing main .content table tbody td:nth-child(3){display:none}}@container (max-width: 530px){:host .listing main .content table thead th:nth-child(5),:host .listing main .content table tbody td:nth-child(5){display:none}:host .listing footer .status{display:none}}@container (max-width: 370px){:host .listing main .content table thead th:nth-child(2),:host .listing main .content table tbody td:nth-child(2){display:none}:host .listing main .content table thead th:first-child,:host .listing main .content table tbody td:first-child{width:100%;min-width:0;max-width:none}:host .listing main .content table tbody td:first-child .name{max-width:100%}}@container (max-width: 295px){:host .listing main .content table tbody td:first-child .name{max-width:120px}}`;
20
+ const phirepassSftpClientCss = () => `:host{--radius:0.375rem;--card:220 18% 10%;--border:220 15% 18%;--primary:160 60% 45%;--radius:0.375rem;--destructive:0 70% 50%;--muted:220 15% 13%;--muted-foreground:220 10% 50%;--primary-foreground:220 20% 7%;--scroll-track:220 16% 12%;--scroll-thumb:220 12% 34%;--scroll-thumb-hover:160 45% 44%;font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;height:100%;width:100%;border:1px solid hsl(var(--border));background-color:hsl(var(--card));border-radius:var(--radius);overflow:hidden;display:flex;flex-direction:column;position:relative;container-type:inline-size;.listing{height:100%;display:flex;flex-direction:column;justify-content:space-between;min-height:0;header{height:30px;background:rgba(28, 31, 38, 0.6);border-bottom:1px solid hsl(var(--border));display:flex;align-items:center;justify-content:space-between;.actions{display:flex;align-items:center;.action{cursor:pointer;padding:4px;display:flex;align-items:center;z-index:1;img{height:14px;padding:4px;border-radius:4px}&:hover{background-color:hsl(var(--border) / 0.6)}}}.title{color:hsl(var(--primary));height:14px;padding:0 12px;display:flex;align-items:center;font-size:0.75rem;line-height:1rem;img{height:14px;margin-right:5px}.text{display:flex;flex-direction:row;justify-content:center;margin-top:2px;.name{margin-right:10px}.description{color:hsl(var(--muted-foreground))}}}}main{flex:1;display:flex;flex-direction:column;position:relative;min-height:0;overflow:hidden;.loader{color:hsl(var(--muted-foreground));font-size:13px;animation:pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;text-align:center;display:flex;align-items:center;justify-content:center;position:absolute;height:100%;width:100%;background:rgba(28, 31, 38, 0);backdrop-filter:blur(4px)}.error{font-size:13px;text-align:center;color:hsl(var(--destructive));height:100%;display:flex;align-items:center;justify-content:center}.navigation{height:25px;padding:10px;font-size:0.75rem;line-height:1rem;background-color:hsl(var(--card));display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid hsl(var(--border));position:sticky;top:0;z-index:3;.breadcrumbs{display:flex;align-items:center;margin-right:10px;.breadcrumb-container{white-space:nowrap;.breadcrumb{color:hsl(var(--primary));margin-right:4px;cursor:pointer;&:after{margin-left:4px}&:hover{color:rgb(189, 219, 209)}&:last-child{margin-right:0;color:rgb(189, 219, 209);cursor:default}}}.arrow{height:12px;width:12px;opacity:0.6;top:2px;margin-right:4px;position:relative}}.actions{display:flex;align-items:center;gap:8px}.action{border:none;background:transparent;color:rgb(189, 219, 209);font-size:1.1rem;line-height:1;padding:2px 4px;border-radius:4px;cursor:pointer;&:hover{background-color:hsl(var(--border) / 0.6)}img{height:14px;width:14px;display:block}}.action.disconnect{color:#ff4d5f;font-size:0.65rem;letter-spacing:0.08em;padding:4px 8px;&:hover{color:#ff6b7a;background-color:hsl(var(--destructive) / 0.12)}}}.content{flex:1;min-height:0;overflow:auto;font-size:0.75rem;line-height:1rem;scrollbar-width:thin;scrollbar-color:hsl(var(--scroll-thumb)) hsl(var(--scroll-track));&::-webkit-scrollbar{width:10px;height:10px}&::-webkit-scrollbar-track{background:hsl(var(--scroll-track))}&::-webkit-scrollbar-thumb{background:hsl(var(--scroll-thumb));border-radius:999px;border:2px solid hsl(var(--scroll-track))}&::-webkit-scrollbar-thumb:hover{background:hsl(var(--scroll-thumb-hover))}table{width:100%;border-collapse:separate;border-spacing:0;table-layout:auto;thead{background-color:hsl(var(--muted));border-bottom:1px solid hsl(var(--border));th{padding:8px 10px;text-align:left;color:hsl(var(--muted-foreground));position:sticky;top:0;z-index:2;background-color:hsl(var(--muted));border-bottom:1px solid hsl(var(--border));line-height:0.95rem;&.action-col{width:58px;min-width:58px;padding:0 10px}&:first-child{width:30%;min-width:180px;max-width:195px}&:nth-child(2),&:nth-child(3),&:nth-child(4),&:nth-child(5){white-space:nowrap;width:1%}}}tbody{padding:10px 10px;tr{border-bottom:1px solid hsl(var(--border) / 0.4);td{padding:10px 10px 9px;color:hsl(var(--muted-foreground));&:first-child{min-width:180px;max-width:195px;white-space:nowrap;.name{display:inline-block;max-width:calc(100% - 26px);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}}&:nth-child(2),&:nth-child(3),&:nth-child(4),&:nth-child(5){white-space:nowrap}&.action-col{width:58px;min-width:58px;text-align:center;padding-left:1px;padding-right:1px;.file-actions{display:flex;align-items:center;justify-content:center;gap:8px}.file-action{border:none;background:transparent;color:hsl(var(--muted-foreground));width:16px;height:16px;border-radius:3px;cursor:pointer;opacity:0;visibility:hidden;pointer-events:none;transition:opacity 120ms ease;padding:0;svg{width:12px;height:12px;display:block;margin:0 auto}&:hover{color:hsl(var(--primary))}&.delete:hover{color:hsl(var(--destructive))}}}.name{&.file{color:rgb(189, 219, 209)}&.folder{color:hsl(var(--primary))}}.kind{height:14px;width:14px;margin-right:5px;top:3px;position:relative}}&:hover{cursor:pointer;background-color:hsl(var(--muted) / 0.4);td.action-col .file-action{opacity:1;visibility:visible;pointer-events:auto;color:hsl(var(--primary))}}&.selected{background-color:hsl(var(--primary) / 0.3);td.action-col .file-action{opacity:1;visibility:visible;pointer-events:auto}&:hover{background-color:hsl(var(--primary) / 0.4)}}}}}}}footer{height:25px;background:rgba(28, 31, 38, 0.6);border-top:1px solid hsl(var(--border));font-size:0.75rem;line-height:1rem;display:flex;align-items:center;justify-content:space-between;padding:0 10px;.status{font-size:0.65rem;color:hsl(var(--muted-foreground));.selected-item{margin-left:10px;color:hsl(var(--primary))}}.version{font-size:0.65rem;color:hsl(var(--muted-foreground))}}}.creds{position:absolute;top:0;left:0;height:100%;width:100%;display:flex;justify-content:center;align-items:center;;&.blurred{background:rgba(28, 31, 38, 0);backdrop-filter:blur(4px)}.auth{display:flex;flex-direction:column;background:hsl(var(--card));position:relative;background-color:rgba(21, 24, 30, 0.95);border:1px solid hsl(var(--border));padding:30px;box-shadow:rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.5) 0px 25px 50px -12px;border-radius:var(--radius);.title{margin-bottom:12px;color:hsl(var(--primary))}label{font-size:0.75rem;line-height:1rem;margin-bottom:1rem;color:hsl(var(--muted-foreground))}input{font-size:0.875rem;line-height:1.25rem;padding-top:0.5rem;padding-bottom:0.5rem;padding-left:0.75rem;padding-right:0.75rem;background-color:rgb(28, 31, 38);border-color:rgb(39, 44, 53);border-width:1px;border-radius:calc(var(--radius) - 2px);width:100%;margin-bottom:12px;color:rgb(189, 219, 209);box-sizing:border-box;&:focus{outline:none;border-color:hsl(var(--primary));box-shadow:0 0 0 1px hsl(var(--primary))}}button[type='submit']{margin-top:12px;width:100%;background-color:hsl(var(--primary));color:hsl(var(--primary-foreground));letter-spacing:0.05em;font-size:13px;font-weight:500;padding:0.5rem 1rem;border-radius:calc(var(--radius) - 2px);height:2rem;cursor:pointer;border:none;&:hover{background-color:hsl(var(--primary) / 0.9)}}}}.upload-modal,.download-modal,.delete-modal{position:absolute;inset:0;display:none;align-items:center;justify-content:center;background:rgba(28, 31, 38, 0);backdrop-filter:blur(4px);z-index:6;&.visible{display:flex}.upload-dialog,.download-dialog,.delete-dialog{width:min(360px, calc(100% - 24px));background-color:rgba(21, 24, 30, 0.96);border:1px solid hsl(var(--border));border-radius:var(--radius);padding:16px;box-shadow:rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.5) 0px 25px 50px -12px;.title{color:hsl(var(--primary));font-size:0.8rem;margin-bottom:8px}.file-name{color:rgb(189, 219, 209);font-size:0.72rem;line-height:1rem;margin-bottom:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.progress-track{width:100%;height:10px;border-radius:999px;background-color:hsl(var(--muted));overflow:hidden;border:1px solid hsl(var(--border));.progress-fill{height:100%;width:0;background:linear-gradient(90deg, hsl(var(--primary) / 0.7), hsl(var(--primary)));transition:width 140ms ease}}.progress-meta{margin-top:8px;margin-bottom:12px;display:flex;align-items:center;justify-content:space-between;gap:10px}.progress-speed{color:hsl(var(--muted-foreground));font-size:0.75rem;font-variant-numeric:tabular-nums;line-height:1.4;text-align:left}.progress-value{color:hsl(var(--muted-foreground));font-size:0.75rem;font-variant-numeric:tabular-nums;line-height:1.4;text-align:right}.cancel{margin-top:14px;width:100%;height:2rem;border:1px solid hsl(var(--border));border-radius:calc(var(--radius) - 2px);background:hsl(var(--muted));color:rgb(189, 219, 209);font-size:0.75rem;letter-spacing:0.03em;cursor:pointer;&:hover{border-color:hsl(var(--primary));color:hsl(var(--primary))}&.finished{background-color:hsl(var(--primary));border-color:hsl(var(--primary));color:hsl(var(--primary-foreground));&:hover{background-color:hsl(var(--primary) / 0.9);border-color:hsl(var(--primary) / 0.9);color:hsl(var(--primary-foreground))}}}.message{color:rgb(189, 219, 209);font-size:0.74rem;line-height:1rem;margin-bottom:8px}.modal-actions{margin-top:14px;display:grid;grid-template-columns:1fr 1fr;gap:8px;.btn{height:2rem;border:1px solid hsl(var(--border));border-radius:calc(var(--radius) - 2px);font-size:0.75rem;letter-spacing:0.03em;cursor:pointer;&:disabled{opacity:0.65;cursor:not-allowed}}.btn.secondary{background:hsl(var(--muted));color:rgb(189, 219, 209);&:hover{border-color:hsl(var(--primary));color:hsl(var(--primary))}}.btn.destructive{background:hsl(var(--destructive));border-color:hsl(var(--destructive));color:white;&:hover{background:hsl(var(--destructive) / 0.9);border-color:hsl(var(--destructive) / 0.9)}}}.delete-loader{margin-top:4px;display:flex;justify-content:center;.spinner{width:16px;height:16px;border:2px solid hsl(var(--muted-foreground) / 0.35);border-top-color:hsl(var(--primary));border-radius:50%;animation:spin 0.7s linear infinite}}}}}@keyframes spin{to{transform:rotate(360deg)}}:host(.max){height:100vh;width:100vw;position:fixed;top:0;left:0;z-index:9999}@container (max-width: 699px){:host .listing main .content table thead th:nth-child(4),:host .listing main .content table tbody td:nth-child(4){display:none}}@container (max-width: 635px){:host .listing main .content table thead th:nth-child(3),:host .listing main .content table tbody td:nth-child(3){display:none}}@container (max-width: 530px){:host .listing main .content table thead th:nth-child(5),:host .listing main .content table tbody td:nth-child(5){display:none}:host .listing footer .status{display:none}}@container (max-width: 370px){:host .listing main .content table thead th:nth-child(2),:host .listing main .content table tbody td:nth-child(2){display:none}:host .listing main .content table thead th:first-child,:host .listing main .content table tbody td:first-child{width:100%;min-width:0;max-width:none}:host .listing main .content table tbody td:first-child .name{max-width:100%}}@container (max-width: 295px){:host .listing main .content table tbody td:first-child .name{max-width:120px}}`;
21
21
 
22
22
  const PhirepassSftpClient = class {
23
23
  constructor(hostRef) {
@@ -30,9 +30,15 @@ const PhirepassSftpClient = class {
30
30
  runtimeReady = false;
31
31
  connected = false;
32
32
  uploadInputEl;
33
- uploadProgressHandle;
34
- downloadProgressHandle;
35
33
  deleteLoadingTimeout;
34
+ msgId = 1;
35
+ activeUploadToken = 0;
36
+ pendingUploadStarts = new Map();
37
+ pendingUploadAcks = new Map();
38
+ pendingDownloadStarts = new Map();
39
+ activeDownloads = new Map();
40
+ activeDownloadMsgId;
41
+ pendingDelete;
36
42
  // private inputMode: InputMode = InputMode.Default;
37
43
  session_id;
38
44
  // private usernameBuffer = "";
@@ -93,10 +99,12 @@ const PhirepassSftpClient = class {
93
99
  show_upload_modal = false;
94
100
  upload_progress = 0;
95
101
  upload_file_name = '';
102
+ upload_speed = '--';
96
103
  upload_finished = false;
97
104
  show_download_modal = false;
98
105
  download_progress = 0;
99
106
  download_file_name = '';
107
+ download_speed = '--';
100
108
  download_finished = false;
101
109
  show_delete_modal = false;
102
110
  delete_file_name = '';
@@ -131,30 +139,120 @@ const PhirepassSftpClient = class {
131
139
  this.connected = false;
132
140
  this.domReady = false;
133
141
  this.runtimeReady = false;
134
- this.clear_upload_progress();
135
- this.clear_download_progress();
142
+ this.cancel_active_upload();
143
+ this.cancel_active_download();
144
+ this.clear_pending_operations();
136
145
  this.clear_delete_loading_timeout();
137
146
  this.close_comms();
138
147
  // this.destroy_terminal();
139
148
  }
140
- clear_upload_progress() {
141
- if (this.uploadProgressHandle !== undefined) {
142
- window.clearInterval(this.uploadProgressHandle);
143
- this.uploadProgressHandle = undefined;
144
- }
145
- }
146
- clear_download_progress() {
147
- if (this.downloadProgressHandle !== undefined) {
148
- window.clearInterval(this.downloadProgressHandle);
149
- this.downloadProgressHandle = undefined;
150
- }
151
- }
152
149
  clear_delete_loading_timeout() {
153
150
  if (this.deleteLoadingTimeout !== undefined) {
154
151
  window.clearTimeout(this.deleteLoadingTimeout);
155
152
  this.deleteLoadingTimeout = undefined;
156
153
  }
157
154
  }
155
+ next_msg_id() {
156
+ const id = this.msgId;
157
+ this.msgId += 1;
158
+ return id;
159
+ }
160
+ clear_pending_operations() {
161
+ this.pendingUploadStarts.forEach((pending) => {
162
+ window.clearTimeout(pending.timeout);
163
+ pending.reject(new Error('Upload start aborted'));
164
+ });
165
+ this.pendingUploadStarts.clear();
166
+ this.pendingUploadAcks.forEach((pending) => {
167
+ window.clearTimeout(pending.timeout);
168
+ pending.reject(new Error('Upload chunk aborted'));
169
+ });
170
+ this.pendingUploadAcks.clear();
171
+ this.pendingDownloadStarts.forEach((pending) => {
172
+ window.clearTimeout(pending.timeout);
173
+ pending.reject(new Error('Download start aborted'));
174
+ });
175
+ this.pendingDownloadStarts.clear();
176
+ this.stop_delete_polling();
177
+ this.activeDownloads.clear();
178
+ }
179
+ stop_delete_polling() {
180
+ if (this.pendingDelete?.interval !== undefined) {
181
+ window.clearInterval(this.pendingDelete.interval);
182
+ }
183
+ this.pendingDelete = undefined;
184
+ }
185
+ cancel_active_upload() {
186
+ this.activeUploadToken += 1;
187
+ this.upload_progress = 0;
188
+ this.upload_finished = false;
189
+ this.upload_speed = '--';
190
+ }
191
+ cancel_active_download() {
192
+ if (this.activeDownloadMsgId !== undefined) {
193
+ this.activeDownloads.delete(this.activeDownloadMsgId);
194
+ }
195
+ this.activeDownloadMsgId = undefined;
196
+ this.download_progress = 0;
197
+ this.download_finished = false;
198
+ this.download_speed = '--';
199
+ }
200
+ format_duration(seconds) {
201
+ if (!Number.isFinite(seconds) || seconds < 0) {
202
+ return '--';
203
+ }
204
+ if (seconds < 60) {
205
+ return `${seconds.toFixed(0)}s`;
206
+ }
207
+ const minutes = Math.floor(seconds / 60);
208
+ const remainderSeconds = Math.floor(seconds % 60);
209
+ if (minutes < 60) {
210
+ return `${minutes}m ${remainderSeconds}s`;
211
+ }
212
+ const hours = Math.floor(minutes / 60);
213
+ const remainderMinutes = minutes % 60;
214
+ return `${hours}h ${remainderMinutes}m`;
215
+ }
216
+ format_percent(value) {
217
+ const safe = Number.isFinite(value) ? value : 0;
218
+ return `${safe.toFixed(2)}%`;
219
+ }
220
+ format_transfer_rate(bytesPerSecond) {
221
+ if (!Number.isFinite(bytesPerSecond) || bytesPerSecond <= 0) {
222
+ return '--';
223
+ }
224
+ return `${this.format_size(bytesPerSecond)}/s`;
225
+ }
226
+ update_upload_progress(uploadedBytes, totalBytes, startTime) {
227
+ const progress = totalBytes > 0 ? (uploadedBytes / totalBytes) * 100 : 0;
228
+ this.upload_progress = Math.max(0, Math.min(100, progress));
229
+ if (uploadedBytes >= totalBytes) {
230
+ this.upload_finished = true;
231
+ this.upload_speed = '--';
232
+ return;
233
+ }
234
+ const elapsedSeconds = (performance.now() - startTime) / 1000;
235
+ const speed = elapsedSeconds > 0 ? uploadedBytes / elapsedSeconds : 0;
236
+ this.upload_speed = this.format_transfer_rate(speed);
237
+ const remaining = totalBytes - uploadedBytes;
238
+ const eta = speed > 0 ? remaining / speed : NaN;
239
+ this.status = `Uploading ${this.format_size(uploadedBytes)} / ${this.format_size(totalBytes)} (ETA ${this.format_duration(eta)})`;
240
+ }
241
+ update_download_progress(receivedBytes, totalBytes, startTime) {
242
+ const progress = totalBytes > 0 ? (receivedBytes / totalBytes) * 100 : 0;
243
+ this.download_progress = Math.max(0, Math.min(100, progress));
244
+ if (receivedBytes >= totalBytes) {
245
+ this.download_finished = true;
246
+ this.download_speed = '--';
247
+ return;
248
+ }
249
+ const elapsedSeconds = (Date.now() - startTime) / 1000;
250
+ const speed = elapsedSeconds > 0 ? receivedBytes / elapsedSeconds : 0;
251
+ this.download_speed = this.format_transfer_rate(speed);
252
+ const remaining = totalBytes - receivedBytes;
253
+ const eta = speed > 0 ? remaining / speed : NaN;
254
+ this.status = `Downloading ${this.format_size(receivedBytes)} / ${this.format_size(totalBytes)} (ETA ${this.format_duration(eta)})`;
255
+ }
158
256
  connect() {
159
257
  this.connected = true;
160
258
  this.channel.connect();
@@ -193,10 +291,38 @@ const PhirepassSftpClient = class {
193
291
  return `${protocol}://${this.serverHost}:${this.serverPort}`;
194
292
  }
195
293
  handle_error(error) {
294
+ if (error.msg_id !== undefined) {
295
+ const pendingUploadStart = this.pendingUploadStarts.get(error.msg_id);
296
+ if (pendingUploadStart) {
297
+ window.clearTimeout(pendingUploadStart.timeout);
298
+ pendingUploadStart.reject(new Error(error.message || 'Upload start failed'));
299
+ this.pendingUploadStarts.delete(error.msg_id);
300
+ }
301
+ const pendingDownloadStart = this.pendingDownloadStarts.get(error.msg_id);
302
+ if (pendingDownloadStart) {
303
+ window.clearTimeout(pendingDownloadStart.timeout);
304
+ pendingDownloadStart.reject(new Error(error.message || 'Download start failed'));
305
+ this.pendingDownloadStarts.delete(error.msg_id);
306
+ }
307
+ if (this.activeDownloads.has(error.msg_id)) {
308
+ this.activeDownloads.delete(error.msg_id);
309
+ if (this.activeDownloadMsgId === error.msg_id) {
310
+ this.activeDownloadMsgId = undefined;
311
+ }
312
+ this.download_finished = false;
313
+ }
314
+ if (this.pendingDelete?.msgId === error.msg_id) {
315
+ this.stop_delete_polling();
316
+ this.delete_loading = false;
317
+ this.show_delete_modal = false;
318
+ this.status = 'Connected';
319
+ }
320
+ }
196
321
  switch (error.kind) {
197
322
  case ErrorType.Generic:
198
323
  case ErrorType.Authentication:
199
324
  this.error_message = error.message || 'An unknown error occurred.';
325
+ this.show_error = true;
200
326
  break;
201
327
  case ErrorType.RequiresUsername:
202
328
  this.show_login_screen_username = true;
@@ -246,8 +372,233 @@ const PhirepassSftpClient = class {
246
372
  });
247
373
  this.show_content = true;
248
374
  this.show_navigation = true;
375
+ if (this.pendingDelete && web.path === this.current_dir) {
376
+ const fileStillExists = web.dir.items.some((item) => item.kind === 'File' && item.name === this.pendingDelete?.filename);
377
+ if (!fileStillExists) {
378
+ this.stop_delete_polling();
379
+ this.delete_loading = false;
380
+ this.show_delete_modal = false;
381
+ this.delete_file_name = '';
382
+ this.status = 'Connected';
383
+ }
384
+ }
249
385
  console.log('Received SFTP list items:', web);
250
386
  }
387
+ handle_upload_start_response(web) {
388
+ if (web.msg_id === undefined) {
389
+ return;
390
+ }
391
+ const pending = this.pendingUploadStarts.get(web.msg_id);
392
+ if (!pending) {
393
+ return;
394
+ }
395
+ window.clearTimeout(pending.timeout);
396
+ pending.resolve(web.response.upload_id);
397
+ this.pendingUploadStarts.delete(web.msg_id);
398
+ }
399
+ handle_upload_chunk_ack(web) {
400
+ const key = `${web.upload_id}_${web.chunk_index}`;
401
+ const pending = this.pendingUploadAcks.get(key);
402
+ if (!pending) {
403
+ return;
404
+ }
405
+ window.clearTimeout(pending.timeout);
406
+ pending.resolve();
407
+ this.pendingUploadAcks.delete(key);
408
+ }
409
+ handle_download_start_response(web) {
410
+ if (web.msg_id === undefined) {
411
+ return;
412
+ }
413
+ const pending = this.pendingDownloadStarts.get(web.msg_id);
414
+ if (!pending) {
415
+ return;
416
+ }
417
+ window.clearTimeout(pending.timeout);
418
+ pending.resolve({
419
+ download_id: web.response.download_id,
420
+ total_size: web.response.total_size,
421
+ total_chunks: web.response.total_chunks,
422
+ });
423
+ this.pendingDownloadStarts.delete(web.msg_id);
424
+ }
425
+ request_next_download_chunk(msgId) {
426
+ const download = this.activeDownloads.get(msgId);
427
+ if (!download || !this.session_id) {
428
+ return;
429
+ }
430
+ this.channel.send_sftp_download_chunk(this.nodeId, this.session_id, download.download_id, download.nextChunkToRequest, msgId);
431
+ download.nextChunkToRequest += 1;
432
+ }
433
+ finalize_download(msgId) {
434
+ const download = this.activeDownloads.get(msgId);
435
+ if (!download) {
436
+ return;
437
+ }
438
+ const sortedChunks = Array.from(download.chunks.entries())
439
+ .sort((a, b) => a[0] - b[0])
440
+ .map(([, data]) => data);
441
+ // Normalize to fresh ArrayBuffer-backed views for BlobPart compatibility.
442
+ const blobParts = sortedChunks.map((chunk) => new Uint8Array(chunk));
443
+ const blob = new Blob(blobParts, { type: 'application/octet-stream' });
444
+ const objectUrl = URL.createObjectURL(blob);
445
+ const anchor = document.createElement('a');
446
+ anchor.href = objectUrl;
447
+ anchor.download = download.filename;
448
+ document.body.appendChild(anchor);
449
+ anchor.click();
450
+ document.body.removeChild(anchor);
451
+ URL.revokeObjectURL(objectUrl);
452
+ this.activeDownloads.delete(msgId);
453
+ if (this.activeDownloadMsgId === msgId) {
454
+ this.activeDownloadMsgId = undefined;
455
+ }
456
+ this.download_finished = true;
457
+ this.status = 'Connected';
458
+ }
459
+ handle_download_chunk(web) {
460
+ if (web.msg_id === undefined) {
461
+ return;
462
+ }
463
+ const download = this.activeDownloads.get(web.msg_id);
464
+ if (!download) {
465
+ return;
466
+ }
467
+ const chunkData = new Uint8Array(web.chunk.data);
468
+ download.chunks.set(web.chunk.chunk_index, chunkData);
469
+ const receivedBytes = Array.from(download.chunks.values()).reduce((sum, data) => sum + data.length, 0);
470
+ this.update_download_progress(receivedBytes, download.total_size, download.startTime);
471
+ if (download.chunks.size >= download.total_chunks) {
472
+ this.finalize_download(web.msg_id);
473
+ return;
474
+ }
475
+ this.request_next_download_chunk(web.msg_id);
476
+ }
477
+ async start_download(item) {
478
+ if (!this.session_id) {
479
+ return;
480
+ }
481
+ this.selected_item = item;
482
+ this.download_file_name = item.name;
483
+ this.download_progress = 0;
484
+ this.download_finished = false;
485
+ this.download_speed = '--';
486
+ this.show_download_modal = true;
487
+ this.show_error = false;
488
+ const msgId = this.next_msg_id();
489
+ this.activeDownloadMsgId = msgId;
490
+ this.activeDownloads.set(msgId, {
491
+ filename: item.name,
492
+ chunks: new Map(),
493
+ total_chunks: 0,
494
+ total_size: 0,
495
+ download_id: 0,
496
+ nextChunkToRequest: 0,
497
+ startTime: Date.now(),
498
+ });
499
+ const downloadStart = new Promise((resolve, reject) => {
500
+ const timeout = window.setTimeout(() => {
501
+ this.pendingDownloadStarts.delete(msgId);
502
+ reject(new Error('Download start timeout'));
503
+ }, 10_000);
504
+ this.pendingDownloadStarts.set(msgId, {
505
+ timeout,
506
+ resolve,
507
+ reject,
508
+ });
509
+ });
510
+ try {
511
+ this.channel.send_sftp_download_start(this.nodeId, this.session_id, item.path, item.name, msgId);
512
+ const { download_id, total_chunks, total_size } = await downloadStart;
513
+ const download = this.activeDownloads.get(msgId);
514
+ if (!download) {
515
+ return;
516
+ }
517
+ download.download_id = download_id;
518
+ download.total_chunks = total_chunks;
519
+ download.total_size = total_size;
520
+ download.nextChunkToRequest = 0;
521
+ this.request_next_download_chunk(msgId);
522
+ }
523
+ catch (err) {
524
+ this.activeDownloads.delete(msgId);
525
+ if (this.activeDownloadMsgId === msgId) {
526
+ this.activeDownloadMsgId = undefined;
527
+ }
528
+ this.show_error = true;
529
+ this.error_message = err instanceof Error ? err.message : 'Failed to start download';
530
+ this.cancel_download();
531
+ }
532
+ }
533
+ async upload_file(fileToUpload) {
534
+ if (!this.session_id) {
535
+ return;
536
+ }
537
+ const uploadToken = this.activeUploadToken + 1;
538
+ this.activeUploadToken = uploadToken;
539
+ this.upload_file_name = fileToUpload.name;
540
+ this.upload_progress = 0;
541
+ this.upload_finished = false;
542
+ this.upload_speed = '--';
543
+ this.show_upload_modal = true;
544
+ this.show_error = false;
545
+ this.status = 'Uploading...';
546
+ const chunkSize = 64 * 1024;
547
+ const totalChunks = Math.max(1, Math.ceil(fileToUpload.size / chunkSize));
548
+ const msgId = this.next_msg_id();
549
+ const uploadStart = new Promise((resolve, reject) => {
550
+ const timeout = window.setTimeout(() => {
551
+ this.pendingUploadStarts.delete(msgId);
552
+ reject(new Error('Upload start timeout'));
553
+ }, 10_000);
554
+ this.pendingUploadStarts.set(msgId, {
555
+ timeout,
556
+ resolve,
557
+ reject,
558
+ });
559
+ });
560
+ try {
561
+ this.channel.send_sftp_upload_start(this.nodeId, this.session_id, fileToUpload.name, this.current_dir, totalChunks, BigInt(fileToUpload.size), msgId);
562
+ const uploadId = await uploadStart;
563
+ let uploadedBytes = 0;
564
+ const startedAt = performance.now();
565
+ for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex += 1) {
566
+ if (uploadToken !== this.activeUploadToken) {
567
+ throw new Error('Upload cancelled');
568
+ }
569
+ const start = chunkIndex * chunkSize;
570
+ const end = Math.min(start + chunkSize, fileToUpload.size);
571
+ const chunkBuffer = new Uint8Array(await fileToUpload.slice(start, end).arrayBuffer());
572
+ await new Promise((resolve, reject) => {
573
+ const key = `${uploadId}_${chunkIndex}`;
574
+ const timeout = window.setTimeout(() => {
575
+ this.pendingUploadAcks.delete(key);
576
+ reject(new Error(`Upload chunk ${chunkIndex + 1} timed out`));
577
+ }, 30_000);
578
+ this.pendingUploadAcks.set(key, {
579
+ timeout,
580
+ resolve,
581
+ reject,
582
+ });
583
+ this.channel.send_sftp_upload_chunk(this.nodeId, this.session_id, uploadId, chunkIndex, chunkBuffer.length, chunkBuffer, null);
584
+ });
585
+ uploadedBytes += chunkBuffer.length;
586
+ this.update_upload_progress(uploadedBytes, fileToUpload.size, startedAt);
587
+ }
588
+ this.upload_progress = 100;
589
+ this.upload_finished = true;
590
+ this.status = 'Connected';
591
+ this.refresh_directory();
592
+ }
593
+ catch (err) {
594
+ if (err.message !== 'Upload cancelled') {
595
+ this.show_error = true;
596
+ this.error_message = err instanceof Error ? err.message : 'Upload failed';
597
+ }
598
+ this.upload_finished = false;
599
+ this.status = 'Connected';
600
+ }
601
+ }
251
602
  handle_tunnel_data(web) {
252
603
  console.log('received tunnel data:', web);
253
604
  }
@@ -303,12 +654,30 @@ const PhirepassSftpClient = class {
303
654
  case ProtocolMessageType.SFTPListItems:
304
655
  this.handle_sftp_list_items(web);
305
656
  break;
657
+ case ProtocolMessageType.SFTPUploadStartResponse:
658
+ this.handle_upload_start_response(web);
659
+ break;
660
+ case ProtocolMessageType.SFTPUploadChunkAck:
661
+ this.handle_upload_chunk_ack(web);
662
+ break;
663
+ case ProtocolMessageType.SFTPDownloadStartResponse:
664
+ this.handle_download_start_response(web);
665
+ break;
666
+ case ProtocolMessageType.SFTPDownloadChunk:
667
+ this.handle_download_chunk(web);
668
+ break;
306
669
  default:
307
670
  console.warn('Unhandled protocol message type:', web);
308
671
  }
309
672
  });
310
673
  }
311
674
  close_comms() {
675
+ this.cancel_active_upload();
676
+ this.cancel_active_download();
677
+ this.clear_pending_operations();
678
+ if (!this.channel) {
679
+ return;
680
+ }
312
681
  this.channel.stop_heartbeat();
313
682
  this.channel.disconnect();
314
683
  }
@@ -354,26 +723,25 @@ const PhirepassSftpClient = class {
354
723
  this.show_login_screen_username = false;
355
724
  this.show_login_screen_password = false;
356
725
  this.show_login_screen = false;
726
+ this.show_upload_modal = false;
727
+ this.show_download_modal = false;
728
+ this.show_delete_modal = false;
729
+ this.upload_progress = 0;
730
+ this.download_progress = 0;
731
+ this.upload_finished = false;
732
+ this.download_finished = false;
733
+ this.delete_loading = false;
734
+ this.delete_file_name = '';
357
735
  this.version = '';
358
736
  this.status = 'Disconnected';
359
737
  }
360
738
  on_file_row_action(item, event) {
361
739
  event.preventDefault();
362
740
  event.stopPropagation();
363
- this.selected_item = item;
364
- this.download_file_name = item.name;
365
- this.download_progress = 0;
366
- this.download_finished = false;
367
- this.show_download_modal = true;
368
- this.clear_download_progress();
369
- this.downloadProgressHandle = window.setInterval(() => {
370
- if (this.download_progress >= 100) {
371
- this.clear_download_progress();
372
- this.download_finished = true;
373
- return;
374
- }
375
- this.download_progress = Math.min(100, this.download_progress + 5);
376
- }, 180);
741
+ if (item.kind !== 'File') {
742
+ return;
743
+ }
744
+ void this.start_download(item);
377
745
  }
378
746
  on_file_delete_action(item, event) {
379
747
  event.preventDefault();
@@ -390,25 +758,48 @@ const PhirepassSftpClient = class {
390
758
  this.show_delete_modal = false;
391
759
  this.delete_file_name = '';
392
760
  this.delete_loading = false;
761
+ this.refresh_directory();
393
762
  }
394
763
  confirm_delete() {
395
764
  if (this.delete_loading) {
396
765
  return;
397
766
  }
398
- this.delete_loading = true;
399
- const deletingFileName = this.delete_file_name;
400
- this.clear_delete_loading_timeout();
401
- this.deleteLoadingTimeout = window.setTimeout(() => {
767
+ if (!this.session_id || !this.selected_item) {
402
768
  this.show_delete_modal = false;
403
- this.delete_loading = false;
404
- this.show_error = true;
405
- this.error_message = `Delete for "${deletingFileName}" is not available yet.`;
406
- window.setTimeout(() => {
407
- this.show_error = false;
408
- }, 2_000);
409
- this.delete_file_name = '';
410
- this.deleteLoadingTimeout = undefined;
411
- }, 1_100);
769
+ return;
770
+ }
771
+ const fileToDelete = this.selected_item.name;
772
+ this.delete_loading = true;
773
+ this.status = 'Deleting...';
774
+ this.show_error = false;
775
+ this.stop_delete_polling();
776
+ const msgId = this.next_msg_id();
777
+ this.pendingDelete = {
778
+ filename: fileToDelete,
779
+ msgId,
780
+ startedAt: Date.now(),
781
+ };
782
+ const pollOnce = () => {
783
+ if (!this.pendingDelete) {
784
+ return;
785
+ }
786
+ const elapsed = Date.now() - this.pendingDelete.startedAt;
787
+ if (elapsed >= 30_000) {
788
+ this.stop_delete_polling();
789
+ this.delete_loading = false;
790
+ this.show_delete_modal = false;
791
+ this.show_error = true;
792
+ this.error_message = `Delete timed out for "${fileToDelete}".`;
793
+ this.status = 'Connected';
794
+ return;
795
+ }
796
+ if (this.session_id) {
797
+ this.channel.send_sftp_list_data(this.nodeId, this.session_id, this.current_dir);
798
+ }
799
+ };
800
+ pollOnce();
801
+ this.pendingDelete.interval = window.setInterval(pollOnce, 2_500);
802
+ this.channel.send_sftp_delete(this.nodeId, this.session_id, this.current_dir, fileToDelete, msgId);
412
803
  }
413
804
  open_upload_picker() {
414
805
  this.uploadInputEl?.click();
@@ -419,34 +810,24 @@ const PhirepassSftpClient = class {
419
810
  if (!selectedFile) {
420
811
  return;
421
812
  }
422
- this.upload_file_name = selectedFile.name;
423
- this.upload_progress = 0;
424
- this.upload_finished = false;
425
- this.show_upload_modal = true;
426
- this.clear_upload_progress();
427
- this.uploadProgressHandle = window.setInterval(() => {
428
- if (this.upload_progress >= 100) {
429
- this.clear_upload_progress();
430
- this.upload_finished = true;
431
- return;
432
- }
433
- this.upload_progress = Math.min(100, this.upload_progress + 5);
434
- }, 180);
813
+ void this.upload_file(selectedFile);
435
814
  input.value = '';
436
815
  }
437
816
  cancel_upload() {
438
- this.clear_upload_progress();
817
+ this.cancel_active_upload();
439
818
  this.show_upload_modal = false;
440
- this.upload_progress = 0;
441
819
  this.upload_file_name = '';
442
- this.upload_finished = false;
820
+ this.upload_speed = '--';
821
+ this.status = 'Connected';
822
+ this.refresh_directory();
443
823
  }
444
824
  cancel_download() {
445
- this.clear_download_progress();
825
+ this.cancel_active_download();
446
826
  this.show_download_modal = false;
447
- this.download_progress = 0;
448
827
  this.download_file_name = '';
449
- this.download_finished = false;
828
+ this.download_speed = '--';
829
+ this.status = 'Connected';
830
+ this.refresh_directory();
450
831
  }
451
832
  is_selected(item) {
452
833
  if (!this.selected_item) {
@@ -474,9 +855,6 @@ const PhirepassSftpClient = class {
474
855
  this.selected_item = null;
475
856
  this.channel.send_sftp_list_data(this.nodeId, this.session_id, path);
476
857
  }
477
- get_full_path(item) {
478
- return [item.path, item.name].join('/');
479
- }
480
858
  format_size(size) {
481
859
  if (size === undefined || Number.isNaN(size)) {
482
860
  return '-';
@@ -553,18 +931,18 @@ const PhirepassSftpClient = class {
553
931
  return `${typeChar}${chars.join('')}`;
554
932
  }
555
933
  render() {
556
- return (h(Host, { key: 'd6835d8f10772d163d135f7c03a8bfd6ea9dc9e5', class: {
934
+ return (h(Host, { key: '4a0c122426a92a92e3a7121d8adecbefe5eaf852', class: {
557
935
  'default': !this.max,
558
936
  'max': this.max,
559
- } }, h("section", { key: '1b8c7c297fe0c13fb6374179960d220bfa264ce1', class: "listing" }, !this.hideHeader &&
560
- h("header", { key: '2aca7b108ed314344a9adab45c41b155ad243006' }, h("section", { key: 'e74cf72a21a03f706b40badcc453a6f00f00b54f', class: "title" }, h("img", { key: 'f3f9799352fd0f24a30c32fbf776fac55297d115', src: phirepassSftpClientLogoSvg, alt: "SFTP Client" }), h("div", { key: '6094df7cf6cd9e00d02f88aec504f1f1f8aa0117', class: "text" }, h("div", { key: '661f83eedde6b10eb779cf5ba51eda8de86a6235', class: "name" }, this.name), h("div", { key: '43f1e5268dcef0ce029e0037865444337da720db', class: "description" }, this.description))), h("section", { key: '1f39c200d7e429c1fe2ba00f271524cbf4694c1b', class: "actions" }, h("div", { key: 'c09d3bafff294a24c84cb98041ccc0914024aebf', class: "action", onClick: () => this.toggle_max() }, h("img", { key: '15700c04d1aac6c5552f2cbbd13909bdac28ebc4', src: phirepassSftpClientMaxSvg, alt: "Maximize" })))), h("main", { key: '43d58b425080731024cb0987f99750b4d106d929' }, this.show_navigation && h("nav", { key: 'fe3020afb24408ae00d8feb03f71911736a4e8fd', class: "navigation" }, h("div", { key: '92f394c1b1f867e365c713e587ee3bf03677ebdd', class: "breadcrumbs" }, this.breadcrumbs.map((crumb, index, breadcrumbs) => (h(h.Fragment, null, h("span", { key: index, onClick: () => this.list_breadcrumb(crumb.path), class: "breadcrumb" }, crumb.label), index < breadcrumbs.length - 1 && h("img", { class: "arrow", src: phirepassSftpClientChevronSvg }))))), h("section", { key: '0a33173ce03dbef85a09c0e6bddea20e8defd4cc', class: "actions", "aria-label": "SFTP actions" }, h("button", { key: '08f27eacad2be8c3b26ab911ab7c8a467d050783', type: "button", class: "action", onClick: () => this.go_to_parent_directory(), title: "Go to parent directory", "aria-label": "Go to parent directory" }, h("img", { key: '20f41d4e2d4ed6bfa0c7cd45140eeebc7d151b29', src: phirepassSftpClientGoUpSvg, alt: "Go up" })), h("button", { key: 'cdc64bf9c863337f1d88923a791aa734e2c6ecfb', type: "button", class: "action", onClick: () => this.refresh_directory(), title: "Refresh", "aria-label": "Refresh" }, h("img", { key: 'c7b8503b466a3f319bc63ddbfc1893addb52d731', src: phirepassSftpClientRefreshSvg, alt: "Refresh" })), h("button", { key: 'a27273c0860ebea231217f49639345185414cd6a', type: "button", class: "action", onClick: () => this.open_upload_picker(), title: "Upload", "aria-label": "Upload" }, h("img", { key: '56c4feb6be73b663df107c342c974689a1922427', src: phirepassSftpClientUploadSvg, alt: "Upload" })), h("button", { key: 'e052aea68588e6711b6fe9ac39b057e8a1ca8f59', type: "button", class: "action disconnect", onClick: () => this.disconnect_session(), title: "Disconnect", "aria-label": "Disconnect" }, "DISCONNECT"))), h("input", { key: 'bac3a9f443a3175dcf9e436ea2754aa46c237e38', type: "file", ref: (el) => this.uploadInputEl = el, onChange: (event) => this.on_upload_selected(event), style: { display: 'none' } }), this.show_content && h("div", { key: 'f8b5a1b307b290bc4ac1c5dbfafea13d942981ea', class: "content" }, h("table", { key: 'acd4c91ff1fad061b847c6c10a6bd5228540bbdd' }, h("thead", { key: 'a416b35d7ac3e1809514f90b20cd52180a98fd78' }, h("tr", { key: '1e42ebd055d9821455205981cd6b86c176d818c6' }, h("th", { key: '785f06a6ff02eca8de9fef36cbb085c2a03b16e9' }, "Name"), h("th", { key: 'f860e66146bd0a5a85516a7c98d901ae4ccf672e' }, "Size"), h("th", { key: '21e2d9c1b923af76afc9aff707219d8fb570c661' }, "Permissions"), h("th", { key: '4d8f3d7909fa2ad3cb52e0c62426d86c399015d8' }, "Owner"), h("th", { key: '5a628872d532a62c49923139d762bb1500163d2f' }, "Modified"), h("th", { key: 'bd635bbd123d003a87460b8958dafdeed887d6f2', class: "action-col", "aria-label": "Actions" }))), h("tbody", { key: '762ab21361490e0455942ea42e5b9feccb9ea6d7' }, this.listing.map((item, index) => (h("tr", { key: index, class: {
937
+ } }, h("section", { key: 'f408645cf18f728c09e7af174f5eb30b5d37ca3b', class: "listing" }, !this.hideHeader &&
938
+ h("header", { key: '42fbffd05631ab758d4a9647b4bda41cb5b77b0a' }, h("section", { key: '9b67a0e72219f287d8458bb8ce271789ec653dc7', class: "title" }, h("img", { key: '0eb4b3588b0631d4e93827f74111650d3bed26c4', src: phirepassSftpClientLogoSvg, alt: "SFTP Client" }), h("div", { key: '30945973ee86494b0b2c90ead1c178a1f48086fa', class: "text" }, h("div", { key: '716418d9af825dfd974ef96f7c9687f8e08cc4e7', class: "name" }, this.name), h("div", { key: 'eec1114d46f86c0f777b75a98dc21af1fe473f96', class: "description" }, this.description))), h("section", { key: '05aa545ba36f40adabe6d920514a00b50219744e', class: "actions" }, h("div", { key: '036d227279849911bd353ba879600d46d4cd1ab2', class: "action", onClick: () => this.toggle_max() }, h("img", { key: '3087b9252229f3dc401ea984c7e4576dc0bb74cb', src: phirepassSftpClientMaxSvg, alt: "Maximize" })))), h("main", { key: '5f2a69fb252b3df05742f8b74a15a0c9028f372f' }, this.show_navigation && h("nav", { key: '10612928faf505db3a3a2a00df51425540ea97ec', class: "navigation" }, h("div", { key: 'fdaa4662f45fad1b2fa31059f67df9344f7e7428', class: "breadcrumbs" }, this.breadcrumbs.map((crumb, index, breadcrumbs) => (h("span", { key: index, class: "breadcrumb-container" }, h("span", { key: index, onClick: () => this.list_breadcrumb(crumb.path), class: "breadcrumb" }, crumb.label), index < breadcrumbs.length - 1 && h("img", { class: "arrow", src: phirepassSftpClientChevronSvg }))))), h("section", { key: '71356c63017f5c74eadeabec428a3b7b3809ade2', class: "actions", "aria-label": "SFTP actions" }, h("button", { key: 'eaf88ec4362509efd594f29a38531a8b158ece9f', type: "button", class: "action", onClick: () => this.go_to_parent_directory(), title: "Go to parent directory", "aria-label": "Go to parent directory" }, h("img", { key: 'b1d5c6a632e22d64f829dbbd7139b859006dbd7a', src: phirepassSftpClientGoUpSvg, alt: "Go up" })), h("button", { key: '94abac9e1a6984872c4c85e66aa448d11621e980', type: "button", class: "action", onClick: () => this.refresh_directory(), title: "Refresh", "aria-label": "Refresh" }, h("img", { key: 'd953e97de3411cd1a526c6e1fe042db0ddc673e5', src: phirepassSftpClientRefreshSvg, alt: "Refresh" })), h("button", { key: '03598d60ae17c54493b1572f53c267b765008766', type: "button", class: "action", onClick: () => this.open_upload_picker(), title: "Upload", "aria-label": "Upload" }, h("img", { key: 'c39ee38d8e584c35155035aeb37403d4a89372ba', src: phirepassSftpClientUploadSvg, alt: "Upload" })), h("button", { key: '7e017137f2588bb7a231ef76e874b85e3c1c112d', type: "button", class: "action disconnect", onClick: () => this.disconnect_session(), title: "Disconnect", "aria-label": "Disconnect" }, "DISCONNECT"))), h("input", { key: '2956f9ad2124f813d848ace2206312ee81a4e145', type: "file", ref: (el) => this.uploadInputEl = el, onChange: (event) => this.on_upload_selected(event), style: { display: 'none' } }), this.show_content && h("div", { key: '451d0758c8b71ac9c720f4ad07c5fa3a7011b43e', class: "content" }, h("table", { key: '27a87bfdc1e357a15ff578cae12f41fb768be576' }, h("thead", { key: 'c8161cd9ff7e2bdf0579b3aa9797bd2366b106e8' }, h("tr", { key: '23dc88a5b43a77bb1ab031f72e01996c0e16d4de' }, h("th", { key: '460827f1703d2c7165df2e07b2d873d71a842c6f' }, "Name"), h("th", { key: '6960f731ba9b30012d1772911899714ad6ea5e10' }, "Size"), h("th", { key: '71ae2e8bd6c7ba2110470b651aed9cda0ef2b88f' }, "Permissions"), h("th", { key: '6e8e87a11812570c5bbfebadf4793eafe15e6237' }, "Owner"), h("th", { key: 'b0001ae77eb5c4958434558c715aa5b23e336da2' }, "Modified"), h("th", { key: '3eb862c25e9734c1a2c99fe07ea804761d9578e9', class: "action-col", "aria-label": "Actions" }))), h("tbody", { key: 'b80916d2917e97c9e4058195c5d5d20e98702d60' }, this.listing.map((item, index) => (h("tr", { key: index, class: {
561
939
  'selected': this.is_selected(item),
562
940
  }, onClick: () => this.list_directory(item) }, h("td", null, item.kind === 'Folder' ? h("img", { class: "kind", src: phirepassSftpClientFolderSvg, alt: "Folder" }) : h("img", { class: "kind", src: phirepassSftpClientFileSvg, alt: "File" }), h("span", { class: `name ${item.kind.toLowerCase()}` }, item.name)), h("td", null, this.format_size(item.attributes.size)), h("td", null, this.format_permissions(item.attributes.permissions, item.kind)), h("td", null, item.attributes.user ?? '-'), h("td", null, new Date(item.attributes.modified * 1000).toLocaleString()), h("td", { class: "action-col" }, item.kind === 'File' &&
563
- h("div", { class: "file-actions" }, h("button", { type: "button", class: "file-action", onClick: (event) => this.on_file_row_action(item, event), title: "Download", "aria-label": "Download" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), h("polyline", { points: "7 10 12 15 17 10" }), h("line", { x1: "12", x2: "12", y1: "15", y2: "3" }))), h("button", { type: "button", class: "file-action delete", onClick: (event) => this.on_file_delete_action(item, event), title: "Delete", "aria-label": "Delete" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("polyline", { points: "3 6 5 6 21 6" }), h("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), h("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), h("line", { x1: "10", x2: "10", y1: "11", y2: "17" }), h("line", { x1: "14", x2: "14", y1: "11", y2: "17" }))))))))))), this.show_loader && h("div", { key: '8889681c30251969a4b0c7bdf9dee9716bae3a7e', class: "loader" }, "Loading..."), this.show_error && h("div", { key: 'e64a52b759c799db6e3b1fe50a6bf37a5c98054c', class: "error" }, this.error_message)), h("footer", { key: '5a839546c86673fefb234bdaef9bd365779411df' }, h("section", { key: 'cbff2897ce0c934cd65afee0ca26214792b8e2dd', class: "status" }, h("span", { key: 'd948c7ffd13a54551f3ef2b4994b6d4c332d7621' }, this.status), this.selected_item && h("span", { key: '9f42bdd345c3fbf7e81fb74e8ddf1950d5d29a46', class: "selected-item" }, this.get_full_path(this.selected_item))), h("section", { key: 'c4dc849a8fd5c3a81977e4bdca9bf2b4f525f8d9', class: "version" }, this.version ? `Version: ${this.version}` : ''))), this.show_login_screen &&
564
- h("section", { key: '98180dd1473469824fcc7b2e88cbf62012c026d3', class: {
941
+ h("div", { class: "file-actions" }, h("button", { type: "button", class: "file-action", onClick: (event) => this.on_file_row_action(item, event), title: "Download", "aria-label": "Download" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }), h("polyline", { points: "7 10 12 15 17 10" }), h("line", { x1: "12", x2: "12", y1: "15", y2: "3" }))), h("button", { type: "button", class: "file-action delete", onClick: (event) => this.on_file_delete_action(item, event), title: "Delete", "aria-label": "Delete" }, h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true" }, h("polyline", { points: "3 6 5 6 21 6" }), h("path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), h("path", { d: "M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" }), h("line", { x1: "10", x2: "10", y1: "11", y2: "17" }), h("line", { x1: "14", x2: "14", y1: "11", y2: "17" }))))))))))), this.show_loader && h("div", { key: '6698d4f3a2f60efa264ac5d4a3e35da14c1b47d5', class: "loader" }, "Loading..."), this.show_error && h("div", { key: '411d74aa5574e444eb4f08d7ecec37fbe9c54a37', class: "error" }, this.error_message)), h("footer", { key: 'a58fb0f412a403f930cbdca15269678cf92037f9' }, h("section", { key: '8a989e00a03d5d3290599131989ddef872444e9b', class: "version" }, this.version ? `Version: ${this.version}` : ''))), this.show_login_screen &&
942
+ h("section", { key: '8f070e03986f073de9ca90ea2f46cd0d485a0a8c', class: {
565
943
  'creds': true,
566
944
  'blurred': this.show_login_screen,
567
- } }, h("form", { key: '8ee6af5523225fd1f1ab93bc3fb268e73ec8d7e6', class: "auth", onSubmit: (event) => {
945
+ } }, h("form", { key: 'f8d6b2455ecf15e6ef19f1058c86100d7fe36357', class: "auth", onSubmit: (event) => {
568
946
  const formData = new FormData(event.target);
569
947
  let username = undefined;
570
948
  if (this.show_login_screen_username) {
@@ -581,27 +959,28 @@ const PhirepassSftpClient = class {
581
959
  this.show_loader = true;
582
960
  event.stopPropagation();
583
961
  event.preventDefault();
584
- } }, h("div", { key: '50fd8c259b5df82b304f2ed08b16050d3cb9bba0', class: "title" }, "SFTP Connection"), this.show_login_screen_username &&
585
- h("div", { key: '9bcbc10707682d879c14419a0bd02f982af985e8' }, h("label", { key: 'c60920335472e50331db739e63cd3615c5cb24b4', htmlFor: "username" }, "Username"), h("input", { key: '9a56e8f648049f2f9216f5886da962cdda273781', autocorrect: "off", autocapitalize: "none", autoComplete: "off", id: "username", name: "username", type: "text", placeholder: "" })), this.show_login_screen_password &&
586
- h("div", { key: '1118e66371c80e7da7100469bc7820e315ffdc7e' }, h("label", { key: 'ff1a7e258f720f380ebe90f8d878713552be1eb8', htmlFor: "password" }, "Password"), h("input", { key: '14265511ce70214639d6c86d2dbec827cf35e3d0', autocorrect: "off", autocapitalize: "none", autoComplete: "off", id: "password", name: "password", type: "password", placeholder: "" })), h("div", { key: 'b850f2be07d80f4d151878c73545e644f05ecd34' }, h("button", { key: '9291d47362ed567b910276636176aa52d106c388', type: "submit" }, "Connect")))), this.show_upload_modal &&
587
- h("section", { key: 'b7f9bd6374bfb8bcf04d8563e4ef48f8a077d582', class: {
962
+ } }, h("div", { key: '870343a9f67b01ce620c88ab3af2d823e9c109da', class: "title" }, "SFTP Connection"), this.show_login_screen_username &&
963
+ h("div", { key: 'd32b19a3d0e89196247358ca846fd6108fe15128' }, h("label", { key: 'c60053d805db2357780bb986c71f6b839390ca20', htmlFor: "username" }, "Username"), h("input", { key: '73c368508cc63db7ff5d7c7ca1d3f12a6e409926', autocorrect: "off", autocapitalize: "none", autoComplete: "off", id: "username", name: "username", type: "text", placeholder: "" })), this.show_login_screen_password &&
964
+ h("div", { key: 'c5a91b121c0309e577ca63a5392dce7b982e6429' }, h("label", { key: 'b3adfc6963d418f9a7748092a661f87a77949f1d', htmlFor: "password" }, "Password"), h("input", { key: '0e6855eb8e7ef22e6981e5c7df429d4bc81e8d67', autocorrect: "off", autocapitalize: "none", autoComplete: "off", id: "password", name: "password", type: "password", placeholder: "" })), h("div", { key: '05377a2061e222afada603838feaac68b913be1b' }, h("button", { key: '4d28615b22f083ad8b7430a3babe2a5dbc9c4f90', type: "submit" }, "Connect")))), this.show_upload_modal &&
965
+ h("section", { key: '7979af0ec1f92bf78a94d5e1be2a7b7a79b780be', class: {
588
966
  'upload-modal': true,
589
967
  'visible': this.show_upload_modal,
590
- } }, h("div", { key: '44f4f5f989376be19de17ef9ceee57d421f74a87', class: "upload-dialog", role: "dialog", "aria-modal": "true", "aria-label": "Upload progress" }, h("div", { key: '04337b2bdb2248c357d75479c16a9b7dee480150', class: "title" }, "Uploading File"), h("div", { key: '2bada0f7123a8111ace072757857fc5e9d1e45df', class: "file-name", title: this.upload_file_name }, this.upload_file_name), h("div", { key: '7e5c8115e49d339421af4c481bc1381b45b14906', class: "progress-track", role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": this.upload_progress }, h("div", { key: 'fe2d2659b4e09cfc07604761800f0155f6f4da7c', class: "progress-fill", style: { width: `${this.upload_progress}%` } })), h("div", { key: 'a50903b50a4d57fc7aa9c62f2b08eee94e90c6c6', class: "progress-value" }, this.upload_progress, "%"), h("button", { key: 'a3a0f3b6bee2348d77affcef6a35faba7bdf7b0a', type: "button", class: {
968
+ } }, h("div", { key: '55132c16758312e55fd7bb5bb32dfcd557500838', class: "upload-dialog", role: "dialog", "aria-modal": "true", "aria-label": "Upload progress" }, h("div", { key: '7b808945f2123b5c1e8ed300cba85f3325be643e', class: "title" }, "Uploading File"), h("div", { key: '0c7065ccff128f524eee7da248eee97f78819bc0', class: "file-name", title: this.upload_file_name }, this.upload_file_name), h("div", { key: '848d3526b2cff55c6cc6eab0a4cb536264f14d80', class: "progress-track", role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": this.upload_progress }, h("div", { key: 'a3f8d7c47971866243a5138ae1e5b84fe50fa008', class: "progress-fill", style: { width: `${this.upload_progress}%` } })), h("div", { key: '6675b28ce14fa0f3d84cbfcc602409f6ba650a13', class: "progress-meta" }, h("div", { key: '5205d72ab81c7bfc906fcfe827b05933440161b8', class: "progress-speed" }, this.upload_speed), h("div", { key: 'c3f59de705696ac1355629ac0397e1a9baf56a0a', class: "progress-value" }, this.format_percent(this.upload_progress))), h("button", { key: '06d9bc2f61d7f83361ad97b7bb23f2f45b11ec27', type: "button", class: {
591
969
  'cancel': true,
592
970
  'finished': this.upload_finished,
593
971
  }, onClick: () => this.cancel_upload() }, this.upload_finished ? 'Close' : 'Cancel'))), this.show_download_modal &&
594
- h("section", { key: '268e3fc9a4bd26e0b167ac2f7ec98d85755e06d1', class: {
972
+ h("section", { key: '7217722972f463d2893bd44ac5a4899c8fe545a7', class: {
595
973
  'download-modal': true,
596
974
  'visible': this.show_download_modal,
597
- } }, h("div", { key: '94c7cee66d0d49f1efe1489e93a84b2f66d2566f', class: "download-dialog", role: "dialog", "aria-modal": "true", "aria-label": "Download progress" }, h("div", { key: '392c81df57b514dd146c24aaf47fc7232949e8e1', class: "title" }, "Downloading File"), h("div", { key: 'ebfe8992e27741c18e3d2539fd621db660fb1552', class: "file-name", title: this.download_file_name }, this.download_file_name), h("div", { key: '1424a4bde99d5ee57946210e5089123efbaa5812', class: "progress-track", role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": this.download_progress }, h("div", { key: '6011f979cf8a865a3e8116f16c8e04b3c12b2ebc', class: "progress-fill", style: { width: `${this.download_progress}%` } })), h("div", { key: '8f38212d4d5b55ec24868e14db0d3fa76e3c0a4d', class: "progress-value" }, this.download_progress, "%"), h("button", { key: '2d6090c87206ca4dbbc0d6f0e88f772153f19260', type: "button", class: {
975
+ } }, h("div", { key: '493dddfad5d25411a3421641ef930eab561347b4', class: "download-dialog", role: "dialog", "aria-modal": "true", "aria-label": "Download progress" }, h("div", { key: '2115492e8360a19edf260c7c603bc44e736cccec', class: "title" }, "Downloading File"), h("div", { key: '5582b3ea56c9a184ff1b6de4ca89b93f07461847', class: "file-name", title: this.download_file_name }, this.download_file_name), h("div", { key: '90df12daa47066e7a212edeec5760cef2abc52c6', class: "progress-track", role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": this.download_progress }, h("div", { key: '2c3c6ef5b7091ea010c4fc9037d05db5845f4e23', class: "progress-fill", style: { width: `${this.download_progress}%` } })), h("div", { key: '9d963e08afe1e073f19fc9195cd66f67a874204f', class: "progress-meta" }, h("div", { key: '96508c5a2a95ce9889d947bc4786403785b15c75', class: "progress-speed" }, this.download_speed), h("div", { key: '3f0cab67e511efda1cf79111705525b9838eb410', class: "progress-value" }, this.format_percent(this.download_progress))), h("button", { key: 'cac13e01231ba4c1713b85e7b7ac661b1ec6f6e5', type: "button", class: {
598
976
  'cancel': true,
599
977
  'finished': this.download_finished,
600
978
  }, onClick: () => this.cancel_download() }, this.download_finished ? 'Close' : 'Cancel'))), this.show_delete_modal &&
601
- h("section", { key: '8bfc94b6a829c3997aebcec8368d4e99a3321375', class: {
979
+ h("section", { key: 'e66cc06cb588d7842a4557041a5fa617b2672b0b', class: {
602
980
  'delete-modal': true,
603
981
  'visible': this.show_delete_modal,
604
- } }, h("div", { key: '9fb7a902510330c9366370fd66b48de54339b154', class: "delete-dialog", role: "dialog", "aria-modal": "true", "aria-label": "Delete confirmation" }, h("div", { key: '0835d56456b5a5de31f44528d4e4ece436361280', class: "title" }, "Delete File"), h("div", { key: '8fa20e7ec0ece30993cf07415d6288d855fa9afe', class: "message" }, this.delete_loading ? 'Deleting file...' : 'Are you sure you want to delete this file?'), h("div", { key: '47e29802f717c5c1613cbbd86de7c493c3f4267f', class: "file-name", title: this.delete_file_name }, this.delete_file_name), this.delete_loading && h("div", { key: 'd63f8e662d7a44ab2ab3dba7988996ac8b80bb9e', class: "delete-loading-bar", "aria-hidden": "true" }), h("div", { key: '1b498931d6fed515130589a837a9a0a017718c9a', class: "modal-actions" }, h("button", { key: '641f8ce95c205b170da0a498213c263bc7c9a410', type: "button", class: "btn secondary", onClick: () => this.cancel_delete(), disabled: this.delete_loading }, "Cancel"), h("button", { key: '54685d2b101a8af75912edb72109e3c4c23b0789', type: "button", class: "btn destructive", onClick: () => this.confirm_delete(), disabled: this.delete_loading }, this.delete_loading ? 'Deleting...' : 'Delete'))))));
982
+ } }, h("div", { key: 'ac2298da9dde4e4043f29a8b2b137fe7f2e0f5dc', class: "delete-dialog", role: "dialog", "aria-modal": "true", "aria-label": "Delete confirmation" }, h("div", { key: 'ac53826a41c03e3cb94296c30e622f453bca0f40', class: "title" }, "Delete File"), h("div", { key: '9724627c77b3242f25e7d73b18bae820833cdb9f', class: "message" }, this.delete_loading ? 'Deleting file...' : 'Are you sure you want to delete this file?'), h("div", { key: '408ece6999a858d60baf7bd34b3133d07aba8806', class: "file-name", title: this.delete_file_name }, this.delete_file_name), this.delete_loading &&
983
+ h("div", { key: '6f157f39e1097a355c139af9ea0e35ee76a04117', class: "delete-loader", "aria-hidden": "true" }, h("span", { key: 'bd85fe1e6dfc09febebcd1c31fc99629d1f4429d', class: "spinner" })), h("div", { key: 'ad4f19824730b61e82e8ad205d5ea0cc2e715a7f', class: "modal-actions" }, h("button", { key: '9d95213a54aefc8064769796f235b4533fc5aa08', type: "button", class: "btn secondary", onClick: () => this.cancel_delete(), disabled: this.delete_loading }, "Cancel"), h("button", { key: 'd423c0537eb372ed491387c45e6a5c5f5a975259', type: "button", class: "btn destructive", onClick: () => this.confirm_delete(), disabled: this.delete_loading }, this.delete_loading ? 'Deleting...' : 'Delete'))))));
605
984
  }
606
985
  static get watchers() { return {
607
986
  "nodeId": [{