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,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-DPi8rcp9.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": [{