phirepass-widgets 0.0.54 → 0.0.56

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