Merge branch 'main' into cache_magic_section

This commit is contained in:
ashilkn
2024-06-24 17:31:58 +05:30
186 changed files with 5170 additions and 2630 deletions

View File

@@ -145,7 +145,7 @@ jobs:
- name: Install dependencies for desktop build
run: |
sudo apt-get update -y
sudo apt-get install -y libsecret-1-dev libsodium-dev libwebkit2gtk-4.0-dev libfuse2 ninja-build libgtk-3-dev dpkg-dev pkg-config rpm patchelf libsqlite3-dev locate libayatana-appindicator3-dev libffi-dev libtiff5
sudo apt-get install -y libsecret-1-dev libsodium-dev libwebkit2gtk-4.0-dev libfuse2 ninja-build libgtk-3-dev dpkg-dev pkg-config rpm patchelf libsqlite3-dev locate libayatana-appindicator3-dev libffi-dev libtiff5 xz-utils libarchive-tools
sudo updatedb --localpaths='/usr/lib/x86_64-linux-gnu'
- name: Install appimagetool
@@ -157,10 +157,16 @@ jobs:
- name: Build desktop app
run: |
flutter config --enable-linux-desktop
dart pub global activate flutter_distributor
# dart pub global activate flutter_distributor
dart pub global activate --source git https://github.com/prateekmedia/flutter_distributor --git-ref pacman --git-path packages/flutter_distributor
# Run below command if it is a beta or nightly
if [[ ${{ github.ref }} =~ beta|nightly ]]; then
flutter_distributor package --platform=linux --targets=pacman --skip-clean
mv dist/**/*-*-linux.pacman artifacts/ente-${{ github.ref_name }}-x86_64.pacman
fi
flutter_distributor package --platform=linux --targets=rpm --skip-clean
flutter_distributor package --platform=linux --targets=appimage --skip-clean
mv dist/**/*-*-linux.rpm artifacts/ente-${{ github.ref_name }}-x86_64.rpm
flutter_distributor package --platform=linux --targets=appimage --skip-clean
mv dist/**/*-*-linux.AppImage artifacts/ente-${{ github.ref_name }}-x86_64.AppImage
- name: Generate checksums

View File

@@ -1,5 +1,7 @@
name: "Deploy staging (web)"
# Builds the "staging/web" branch if it exists, "main" otherwise.
on:
schedule:
# Run everyday at ~3:00 PM IST
@@ -18,9 +20,20 @@ jobs:
working-directory: web
steps:
- name: Checkout code
- name: Determine branch to build
id: select-branch
working-directory: ${{ github.workspace }}
run: |
if git ls-remote --exit-code --heads https://github.com/ente-io/ente refs/heads/staging/web; then
echo "branch=staging/web" >> $GITHUB_OUTPUT
else
echo "branch=main" >> $GITHUB_OUTPUT
fi
- name: Checkout ${{ steps.select-branch.outputs.branch }}
uses: actions/checkout@v4
with:
ref: ${{ steps.select-branch.outputs.branch }}
submodules: recursive
- name: Setup node and enable yarn caching

View File

@@ -39,11 +39,15 @@
{
"title": "Bloom Host",
"slug": "bloom_host",
"altNames": ["Bloom Host Billing"]
"altNames": [
"Bloom Host Billing"
]
},
{
"title": "BorgBase",
"altNames": ["borg"],
"altNames": [
"borg"
],
"slug": "BorgBase"
},
{
@@ -67,6 +71,13 @@
{
"title": "Cloudflare"
},
{
"title": "CloudAMQP"
},
{
"title": "ConfigCat",
"slug": "configcat"
},
{
"title": "CoinDCX"
},
@@ -83,7 +94,9 @@
},
{
"title": "DCS",
"altNames": ["Digital Combat Simulator"],
"altNames": [
"Digital Combat Simulator"
],
"slug": "dcs"
},
{
@@ -143,7 +156,9 @@
},
{
"title": "Gosuslugi",
"altNames": ["Госуслуги"],
"altNames": [
"Госуслуги"
],
"slug": "Gosuslugi"
},
{
@@ -219,7 +234,11 @@
{
"title": "Local",
"slug": "local_wp",
"altNames": ["LocalWP", "Local WP", "Local Wordpress"]
"altNames": [
"LocalWP",
"Local WP",
"Local Wordpress"
]
},
{
"title": "Marketplace.tf",
@@ -227,14 +246,23 @@
},
{
"title": "Mastodon",
"altNames": ["mstdn", "fediscience", "mathstodon", "fosstodon"],
"altNames": [
"mstdn",
"fediscience",
"mathstodon",
"fosstodon"
],
"slug": "mastodon",
"hex": "6364FF"
},
{
"title": "Mercado Livre",
"slug": "mercado_livre",
"altNames": ["Mercado Libre", "MercadoLibre", "MercadoLivre"]
"altNames": [
"Mercado Libre",
"MercadoLibre",
"MercadoLivre"
]
},
{
"title": "Microsoft"
@@ -250,7 +278,9 @@
},
{
"title": "Murena",
"altNames": ["eCloud"],
"altNames": [
"eCloud"
],
"slug": "ecloud"
},
{
@@ -277,6 +307,10 @@
{
"title": "Notion"
},
{
"title": "NuCommunity",
"slug": "nucommunity"
},
{
"title": "NVIDIA"
},
@@ -335,8 +369,16 @@
"slug": "real_debrid"
},
{
"title": "Registro.br",
"slug": "registro_br"
"title": "Registro br",
"slug": "registro_br",
"altNames": [
"Registro br",
"registrobr",
"Registro.br"
]
},
{
"title": "Render"
},
{
"title": "Revolt",
@@ -355,6 +397,9 @@
"slug": "rust_language_forum",
"hex": "000000"
},
{
"title": "Samsung"
},
{
"title": "Sendgrid"
},
@@ -396,7 +441,10 @@
},
{
"title": "Techlore",
"altNames": ["Techlore Courses", "Techlore Forums"]
"altNames": [
"Techlore Courses",
"Techlore Forums"
]
},
{
"title": "Termius",
@@ -426,6 +474,13 @@
"title": "Twingate",
"hex": "858585"
},
{
"title": "Twitch",
"altNames": [
"Twitch.tv",
"Twitch tv"
]
},
{
"title": "Ubisoft",
"hex": "4285f4"
@@ -460,23 +515,32 @@
{
"title": "WorkOS",
"slug": "workos",
"altNames": ["Work OS"]
"altNames": [
"Work OS"
]
},
{
"title": "X",
"altNames": ["twitter"],
"altNames": [
"twitter"
],
"slug": "x"
},
{
"title": "Yandex",
"altNames": ["Ya", "Яндекс"],
"altNames": [
"Ya",
"Яндекс"
],
"slug": "Yandex"
},
{
"title": "YNAB",
"altNames": ["You Need A Budget"],
"altNames": [
"You Need A Budget"
],
"slug": "ynab",
"hex": "3B5EDA"
}
]
}
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="512px" height="512px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
<g><path style="opacity:1" fill="#0f0f0f" d="M 511.5,272.5 C 511.5,285.5 511.5,298.5 511.5,311.5C 508.543,328.958 502.376,345.291 493,360.5C 489.783,363.38 486.95,366.547 484.5,370C 491.258,380.639 489.591,389.639 479.5,397C 464.044,407.934 447.377,416.601 429.5,423C 412.83,426.168 399.163,421.335 388.5,408.5C 367.197,419.324 344.531,424.491 320.5,424C 318.692,436.612 312.359,446.279 301.5,453C 283.703,460.911 265.036,464.411 245.5,463.5C 242.9,471.276 237.9,477.109 230.5,481C 217.623,486.044 204.289,487.711 190.5,486C 185.821,485.662 181.488,484.328 177.5,482C 156.539,481.714 144.039,471.214 140,450.5C 127.176,458.148 113.343,460.648 98.5,458C 90.6339,455.515 82.6339,453.515 74.5,452C 54.9132,442.997 49.0799,428.497 57,408.5C 66.2342,395.627 78.7342,387.961 94.5,385.5C 92.6275,381.588 90.6275,377.755 88.5,374C 70.6568,365.82 58.8235,352.32 53,333.5C 40.7936,289.193 46.2936,247.193 69.5,207.5C 59.4487,191.064 51.2821,173.73 45,155.5C 46.0538,140.201 46.3871,124.867 46,109.5C 35.4808,94.9732 23.4808,81.6398 10,69.5C 6.25674,65.2678 2.75674,60.9345 -0.5,56.5C -0.5,52.1667 -0.5,47.8333 -0.5,43.5C 9.76623,24.2659 25.0996,18.7659 45.5,27C 67.9457,36.2887 85.1124,51.4554 97,72.5C 110.456,95.0753 121.456,118.742 130,143.5C 131.478,149.551 132.812,155.551 134,161.5C 150.985,156.607 167.819,150.94 184.5,144.5C 189.063,124.296 197.563,105.963 210,89.5C 221.355,76.4675 234.189,65.3008 248.5,56C 281.602,35.3661 304.768,43.1994 318,79.5C 320.953,90.3093 322.453,101.309 322.5,112.5C 360.236,109.787 395.903,116.953 429.5,134C 465.163,161.014 489.997,195.848 504,238.5C 507.153,249.807 509.653,261.14 511.5,272.5 Z"/></g>
<g><path style="opacity:1" fill="#f9f9f9" d="M 24.5,29.5 C 29.5518,29.4502 34.5518,29.9502 39.5,31C 64.2651,40.4294 82.7651,56.9294 95,80.5C 105.37,98.9048 114.37,117.905 122,137.5C 124.445,145.715 126.278,154.048 127.5,162.5C 112.806,166.18 99.806,173.013 88.5,183C 87.6683,183.688 87.0016,183.521 86.5,182.5C 81.5074,171.354 77.0074,160.021 73,148.5C 71.949,132.503 70.949,116.503 70,100.5C 69.8323,89.9943 66.4989,80.661 60,72.5C 50.2229,59.4865 39.3896,47.3198 27.5,36C 24.3562,34.3084 21.0229,33.1418 17.5,32.5C 19.7639,31.1308 22.0972,30.1308 24.5,29.5 Z"/></g>
<g><path style="opacity:1" fill="#f8a38f" d="M 12.5,38.5 C 17.3236,37.9711 21.6569,39.1378 25.5,42C 39.5654,55.7226 51.7321,70.8893 62,87.5C 64.8374,107.385 66.5041,127.385 67,147.5C 70.9051,161.478 76.0717,174.978 82.5,188C 79.7313,192.44 76.5646,196.606 73,200.5C 64.0573,185.948 56.724,170.614 51,154.5C 51.9952,139.197 52.3286,123.864 52,108.5C 48.7377,102.307 44.7377,96.6405 40,91.5C 29,79.8333 18,68.1667 7,56.5C 3.70863,48.8182 5.54196,42.8182 12.5,38.5 Z"/></g>
<g><path style="opacity:1" fill="#fafafa" d="M 75.5,358.5 C 75.5,358.167 75.5,357.833 75.5,357.5C 89.9869,361.531 96.4869,355.865 95,340.5C 88.9149,339.688 82.7482,339.188 76.5,339C 72.7424,337.077 69.4091,334.577 66.5,331.5C 65.914,331.709 65.414,332.043 65,332.5C 64.3219,336.221 64.4886,339.888 65.5,343.5C 65.5,344.167 65.5,344.833 65.5,345.5C 56.2828,328.814 51.9494,310.814 52.5,291.5C 52.6554,251.963 65.6554,217.463 91.5,188C 109.872,171.873 131.372,164.04 156,164.5C 163.871,164.941 171.705,165.774 179.5,167C 180.059,167.725 180.392,168.558 180.5,169.5C 177.315,184.684 175.315,200.018 174.5,215.5C 176.5,215.5 178.5,215.5 180.5,215.5C 182.202,180.727 189.035,147.061 201,114.5C 217.196,84.2957 241.363,63.4624 273.5,52C 285.541,49.4426 295.374,52.9426 303,62.5C 310.113,73.413 314.447,85.413 316,98.5C 321.979,137.67 310.146,170.17 280.5,196C 263.081,211.714 243.415,223.881 221.5,232.5C 221.08,234.326 221.08,236.326 221.5,238.5C 234.851,234.241 247.351,228.241 259,220.5C 259.772,220.645 260.439,220.978 261,221.5C 275.359,247.499 277.359,274.499 267,302.5C 255.866,325.636 239.699,344.469 218.5,359C 205.461,365.355 191.794,369.689 177.5,372C 152.14,376.37 126.806,376.37 101.5,372C 91.2074,370.356 82.5408,365.856 75.5,358.5 Z"/></g>
<g><path style="opacity:1" fill="#0f0c0c" d="M 193.5,223.5 C 192.507,215.35 192.174,207.017 192.5,198.5C 193.5,169.804 200.666,142.804 214,117.5C 225.84,98.1554 243.007,87.1554 265.5,84.5C 286.335,85.1601 299.835,95.4934 306,115.5C 309.914,142.091 302.081,164.591 282.5,183C 256.19,203.482 226.523,216.982 193.5,223.5 Z"/></g>
<g><path style="opacity:1" fill="#fca592" d="M 257.5,90.5 C 284.894,88.5662 299.56,101.233 301.5,128.5C 300.608,150.45 291.608,168.284 274.5,182C 251.674,198.494 226.507,209.994 199,216.5C 197.361,188.998 201.361,162.331 211,136.5C 219.834,114.165 235.334,98.8314 257.5,90.5 Z"/></g>
<g><path style="opacity:1" fill="#fafafa" d="M 60.5,425.5 C 59.5386,423.735 59.2053,421.735 59.5,419.5C 63.1115,407.716 70.7781,399.549 82.5,395C 91.0632,391.633 99.5632,391.799 108,395.5C 108.667,394.833 108.667,394.167 108,393.5C 102.81,388.767 99.4764,383.1 98,376.5C 102.705,378.033 107.538,379.2 112.5,380C 140.837,382.162 168.837,380.162 196.5,374C 217.812,367.925 235.645,356.425 250,339.5C 264.443,322.614 274.11,303.281 279,281.5C 281.871,258.038 277.038,236.371 264.5,216.5C 281.854,203.979 296.687,188.979 309,171.5C 318.099,155.03 322.599,137.363 322.5,118.5C 360.451,115.776 396.117,123.276 429.5,141C 473.317,176.458 498.484,222.292 505,278.5C 507.615,302.611 503.949,325.611 494,347.5C 489.686,356.123 483.52,363.123 475.5,368.5C 480.461,372.751 482.961,378.085 483,384.5C 480.5,388.333 477.333,391.5 473.5,394C 459.716,403.227 445.049,410.893 429.5,417C 425.514,417.499 421.514,417.666 417.5,417.5C 417.193,411.907 417.527,406.407 418.5,401C 417.167,400.333 415.833,399.667 414.5,399C 430.794,394.523 446.461,388.356 461.5,380.5C 461.014,378.503 459.847,377.169 458,376.5C 440.722,385.148 422.555,390.982 403.5,394C 380.37,396.219 367.203,385.719 364,362.5C 362.937,347.817 366.437,334.317 374.5,322C 373.465,320.726 372.298,319.56 371,318.5C 354.722,340.239 353.389,362.905 367,386.5C 371.262,392.27 376.762,396.27 383.5,398.5C 384.736,400.034 385.236,401.7 385,403.5C 364.91,414.289 343.41,418.956 320.5,417.5C 319.84,404.55 317.673,391.883 314,379.5C 311.816,377.129 309.65,377.296 307.5,380C 314.177,397.067 315.677,414.567 312,432.5C 305.593,444.224 295.76,451.39 282.5,454C 268.581,456.057 254.581,457.224 240.5,457.5C 239.833,466.67 235.166,472.837 226.5,476C 215.527,480.056 204.193,481.39 192.5,480C 187.997,479.932 183.83,478.765 180,476.5C 179.18,467.46 181.68,459.46 187.5,452.5C 186.167,451.5 184.833,450.5 183.5,449.5C 176.525,456.706 173.192,465.372 173.5,475.5C 155.566,474.56 151.066,466.227 160,450.5C 165.03,445.927 164.364,443.594 158,443.5C 153.995,448.511 151.328,454.178 150,460.5C 149.667,460.167 149.333,459.833 149,459.5C 144.897,446.475 148.397,435.975 159.5,428C 163.945,425.443 168.611,423.443 173.5,422C 182.977,422.438 192.477,422.938 202,423.5C 220.978,425.676 230.811,417.343 231.5,398.5C 229.5,398.5 227.5,398.5 225.5,398.5C 226.791,409.364 222.125,415.864 211.5,418C 200.619,418.627 189.786,418.127 179,416.5C 166.002,416.349 155.502,421.349 147.5,431.5C 146.029,427.759 144.363,424.092 142.5,420.5C 141.998,419.479 141.332,419.312 140.5,420C 139.272,420.779 138.272,421.779 137.5,423C 139.652,428.271 141.652,433.604 143.5,439C 129.108,453.41 112.441,456.91 93.5,449.5C 89.7245,439.648 91.3911,430.815 98.5,423C 97.3147,421.647 95.9814,420.48 94.5,419.5C 87.1734,427.469 84.5067,436.803 86.5,447.5C 75.3584,448.43 68.025,443.597 64.5,433C 65.9688,424.073 69.6355,416.239 75.5,409.5C 74.5,407.833 73.1667,406.5 71.5,405.5C 66.2677,411.297 62.601,417.964 60.5,425.5 Z"/></g>
<g><path style="opacity:1" fill="#e5e5e5" d="M 180.5,151.5 C 181.675,151.281 182.675,151.614 183.5,152.5C 182.878,155.37 182.211,158.204 181.5,161C 175.174,160.8 168.84,160.134 162.5,159C 168.652,156.569 174.652,154.069 180.5,151.5 Z"/></g>
<g><path style="opacity:1" fill="#9b9b9b" d="M 192.5,198.5 C 192.174,207.017 192.507,215.35 193.5,223.5C 193.44,224.043 193.107,224.376 192.5,224.5C 191.179,215.675 191.179,207.009 192.5,198.5 Z"/></g>
<g><path style="opacity:1" fill="#090909" d="M 190.5,275.5 C 203.491,273.992 208.658,279.659 206,292.5C 201.745,299.54 195.578,302.04 187.5,300C 181.092,296.677 178.925,291.511 181,284.5C 183.679,280.924 186.846,277.924 190.5,275.5 Z"/></g>
<g><path style="opacity:1" fill="#dddddd" d="M 192.5,279.5 C 196.302,278.88 199.635,279.714 202.5,282C 201.646,283.022 200.646,283.855 199.5,284.5C 197.382,283.054 195.049,282.387 192.5,282.5C 192.5,281.5 192.5,280.5 192.5,279.5 Z"/></g>
<g><path style="opacity:1" fill="#070707" d="M 75.5,357.5 C 71.1612,353.465 67.8279,348.798 65.5,343.5C 64.4886,339.888 64.3219,336.221 65,332.5C 65.414,332.043 65.914,331.709 66.5,331.5C 69.4091,334.577 72.7424,337.077 76.5,339C 82.7482,339.188 88.9149,339.688 95,340.5C 96.4869,355.865 89.9869,361.531 75.5,357.5 Z"/></g>
<g><path style="opacity:1" fill="#afafaf" d="M 65.5,343.5 C 67.8279,348.798 71.1612,353.465 75.5,357.5C 75.5,357.833 75.5,358.167 75.5,358.5C 70.6417,355.312 67.3083,350.979 65.5,345.5C 65.5,344.833 65.5,344.167 65.5,343.5 Z"/></g>
<g><path style="opacity:1" fill="#ededed" d="M 407.5,398.5 C 409.167,398.5 410.833,398.5 412.5,398.5C 411.966,404.499 411.299,410.499 410.5,416.5C 402.406,414.736 396.739,410.069 393.5,402.5C 393.608,401.558 393.941,400.725 394.5,400C 399.019,399.825 403.353,399.325 407.5,398.5 Z"/></g>
<g><path style="opacity:1" fill="#8e8e8e" d="M 59.5,419.5 C 59.2053,421.735 59.5386,423.735 60.5,425.5C 60.6068,427.379 60.1068,427.712 59,426.5C 58.2042,423.961 58.3709,421.628 59.5,419.5 Z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@@ -1 +1 @@
<svg id="logosandtypes_com" data-name="logosandtypes com" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150"><defs><style>.cls-1{fill:none;}.cls-2{fill:#e31937;}</style></defs><g id="Layer_2" data-name="Layer 2"><path id="Layer_3" data-name="Layer 3" class="cls-1" d="M0,0H150V150H0Z" transform="translate(0 0)"/></g><rect class="cls-2" x="13.34" y="14.37" width="15.01" height="123.08"/><rect class="cls-2" x="122.92" y="14.37" width="15.01" height="123.08"/><rect class="cls-2" x="43.36" y="54.9" width="64.54" height="15.01"/><rect class="cls-2" x="43.36" y="83.42" width="64.54" height="15.01"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150" fill="#e31937" xmlns:v="https://vecta.io/nano"><path d="M13.34 14.37h15.01v123.08H13.34zm109.58 0h15.01v123.08h-15.01zM43.36 54.9h64.54v15.01H43.36zm0 28.52h64.54v15.01H43.36z"/></svg>

Before

Width:  |  Height:  |  Size: 611 B

After

Width:  |  Height:  |  Size: 247 B

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 386 KiB

After

Width:  |  Height:  |  Size: 316 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 959 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 523 KiB

After

Width:  |  Height:  |  Size: 735 B

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="900px" height="900px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
<g><path style="opacity:1" fill="#fefefe" d="M -0.5,-0.5 C 299.5,-0.5 599.5,-0.5 899.5,-0.5C 899.5,299.5 899.5,599.5 899.5,899.5C 599.5,899.5 299.5,899.5 -0.5,899.5C -0.5,599.5 -0.5,299.5 -0.5,-0.5 Z"/></g>
<g><path style="opacity:1" fill="#e0a5fc" d="M 297.5,264.5 C 309.66,263.34 321.993,263.173 334.5,264C 337.457,264.279 340.123,265.113 342.5,266.5C 327.57,264.717 312.57,264.051 297.5,264.5 Z"/></g>
<g><path style="opacity:1" fill="#8f02d8" d="M 297.5,264.5 C 312.57,264.051 327.57,264.717 342.5,266.5C 369.173,272.584 390.673,286.584 407,308.5C 421.104,329.299 429.604,352.299 432.5,377.5C 432.334,383.509 432.501,389.509 433,395.5C 433.21,397.058 433.71,398.391 434.5,399.5C 434.5,406.5 434.5,413.5 434.5,420.5C 434.5,421.5 434.5,422.5 434.5,423.5C 433.71,422.391 433.21,421.058 433,419.5C 432.5,487.833 432.333,556.166 432.5,624.5C 404.167,624.5 375.833,624.5 347.5,624.5C 347.832,575.997 347.499,527.664 346.5,479.5C 346.829,464.99 346.496,450.657 345.5,436.5C 347.595,406.902 342.095,378.902 329,352.5C 307.252,317.035 275.419,299.368 233.5,299.5C 233.5,299.167 233.5,298.833 233.5,298.5C 250.906,279.797 272.24,268.463 297.5,264.5 Z"/></g>
<g><path style="opacity:1" fill="#e2aefc" d="M 464.5,272.5 C 494.329,271.502 524.329,271.169 554.5,271.5C 554.5,330.167 554.5,388.833 554.5,447.5C 554.5,452.833 554.5,458.167 554.5,463.5C 553.501,400.002 553.168,336.336 553.5,272.5C 523.833,272.5 494.167,272.5 464.5,272.5 Z"/></g>
<g><path style="opacity:1" fill="#c47ceb" d="M 789.5,272.5 C 759.662,272.169 729.995,272.502 700.5,273.5C 700.667,355.501 700.5,437.501 700,519.5C 699.819,522.695 699.319,525.695 698.5,528.5C 699.467,442.842 699.801,357.175 699.5,271.5C 729.671,271.169 759.671,271.502 789.5,272.5 Z"/></g>
<g><path style="opacity:1" fill="#f9fff3" d="M 790.5,489.5 C 790.5,417.167 790.5,344.833 790.5,272.5C 791.341,271.991 791.841,272.657 792,274.5C 792.667,345.167 792.667,415.833 792,486.5C 791.667,489.5 791.333,492.5 791,495.5C 790.505,493.527 790.338,491.527 790.5,489.5 Z"/></g>
<g><path style="opacity:1" fill="#fedffe" d="M 789.5,272.5 C 789.833,272.5 790.167,272.5 790.5,272.5C 790.5,344.833 790.5,417.167 790.5,489.5C 789.833,492.167 789.167,494.833 788.5,497.5C 789.469,422.51 789.802,347.51 789.5,272.5 Z"/></g>
<g><path style="opacity:1" fill="#eb99fb" d="M 464.5,272.5 C 464.168,339.002 464.501,405.335 465.5,471.5C 465.5,480.5 465.5,489.5 465.5,498.5C 464.672,492.347 464.172,486.013 464,479.5C 463.168,410.332 463.335,341.332 464.5,272.5 Z"/></g>
<g><path style="opacity:1" fill="#8113b9" d="M 464.5,272.5 C 494.167,272.5 523.833,272.5 553.5,272.5C 553.168,336.336 553.501,400.002 554.5,463.5C 554.334,472.173 554.5,480.84 555,489.5C 555.183,492.365 555.683,495.031 556.5,497.5C 557.067,504.237 558.067,510.904 559.5,517.5C 558.069,517.119 557.236,516.119 557,514.5C 555.425,506.905 554.259,499.238 553.5,491.5C 552.5,418.836 552.167,346.17 552.5,273.5C 523.5,273.5 494.5,273.5 465.5,273.5C 465.5,339.5 465.5,405.5 465.5,471.5C 464.501,405.335 464.168,339.002 464.5,272.5 Z"/></g>
<g><path style="opacity:1" fill="#8f02d8" d="M 559.5,517.5 C 567.209,549.077 585.209,572.91 613.5,589C 621.878,592.737 630.545,595.571 639.5,597.5C 641.515,598.924 643.848,599.59 646.5,599.5C 652.509,599.701 658.509,600.034 664.5,600.5C 664.833,601.167 665.167,601.833 665.5,602.5C 652.044,616.271 636.044,625.937 617.5,631.5C 613.313,632.213 609.313,633.213 605.5,634.5C 604.167,634.5 602.833,634.5 601.5,634.5C 584.03,635.144 566.696,634.144 549.5,631.5C 522.738,623.576 502.238,607.576 488,583.5C 473.799,557.033 466.299,528.699 465.5,498.5C 465.5,489.5 465.5,480.5 465.5,471.5C 465.5,405.5 465.5,339.5 465.5,273.5C 494.5,273.5 523.5,273.5 552.5,273.5C 552.167,346.17 552.5,418.836 553.5,491.5C 554.259,499.238 555.425,506.905 557,514.5C 557.236,516.119 558.069,517.119 559.5,517.5 Z"/></g>
<g><path style="opacity:1" fill="#8f01d8" d="M 700.5,273.5 C 730.005,273.169 759.338,273.502 788.5,274.5C 787.167,309.327 786.5,344.494 786.5,380C 786.5,415.506 787.167,450.673 788.5,485.5C 787.326,491.399 786.659,497.399 786.5,503.5C 786.5,505.167 786.5,506.833 786.5,508.5C 775.375,553.295 747.708,582.629 703.5,596.5C 699.521,596.742 695.854,597.742 692.5,599.5C 684.181,600.124 675.848,600.457 667.5,600.5C 685.44,579.935 695.774,555.935 698.5,528.5C 699.319,525.695 699.819,522.695 700,519.5C 700.5,437.501 700.667,355.501 700.5,273.5 Z"/></g>
<g><path style="opacity:1" fill="#9700e9" d="M 788.5,274.5 C 788.5,344.833 788.5,415.167 788.5,485.5C 787.167,450.673 786.5,415.506 786.5,380C 786.5,344.494 787.167,309.327 788.5,274.5 Z"/></g>
<g><path style="opacity:1" fill="#7c10b7" d="M 700.5,273.5 C 729.995,272.502 759.662,272.169 789.5,272.5C 789.802,347.51 789.469,422.51 788.5,497.5C 787.833,499.5 787.167,501.5 786.5,503.5C 786.659,497.399 787.326,491.399 788.5,485.5C 788.5,415.167 788.5,344.833 788.5,274.5C 759.338,273.502 730.005,273.169 700.5,273.5 Z"/></g>
<g><path style="opacity:1" fill="#e0b2f7" d="M 214.5,299.5 C 220.645,298.51 226.978,298.177 233.5,298.5C 233.5,298.833 233.5,299.167 233.5,299.5C 232.833,299.833 232.167,300.167 231.5,300.5C 226.025,299.511 220.358,299.178 214.5,299.5 Z"/></g>
<g><path style="opacity:1" fill="#bb82dc" d="M 203.5,301.5 C 201.485,302.924 199.152,303.59 196.5,303.5C 198.515,302.076 200.848,301.41 203.5,301.5 Z"/></g>
<g><path style="opacity:1" fill="#8f01d8" d="M 214.5,299.5 C 220.358,299.178 226.025,299.511 231.5,300.5C 214.94,317.802 205.273,338.469 202.5,362.5C 201.693,366.021 201.026,369.688 200.5,373.5C 199.833,374.5 199.167,375.5 198.5,376.5C 196.503,458.827 195.836,541.493 196.5,624.5C 168.167,624.5 139.833,624.5 111.5,624.5C 111.5,552.833 111.5,481.167 111.5,409.5C 111.5,408.833 111.5,408.167 111.5,407.5C 111.646,403.481 111.979,399.481 112.5,395.5C 113.768,393.095 114.435,390.428 114.5,387.5C 121.985,358.168 138.319,335.001 163.5,318C 173.533,310.984 184.533,306.151 196.5,303.5C 199.152,303.59 201.485,302.924 203.5,301.5C 207.221,301.089 210.888,300.422 214.5,299.5 Z"/></g>
<g><path style="opacity:1" fill="#9500e4" d="M 198.5,376.5 C 198.5,459.833 198.5,543.167 198.5,626.5C 169.147,627.159 140.147,626.492 111.5,624.5C 139.833,624.5 168.167,624.5 196.5,624.5C 195.836,541.493 196.503,458.827 198.5,376.5 Z"/></g>
<g><path style="opacity:1" fill="#7d10b7" d="M 200.5,373.5 C 199.513,458.149 199.18,542.815 199.5,627.5C 169.833,627.5 140.167,627.5 110.5,627.5C 110.167,554.665 110.501,481.998 111.5,409.5C 111.5,481.167 111.5,552.833 111.5,624.5C 140.147,626.492 169.147,627.159 198.5,626.5C 198.5,543.167 198.5,459.833 198.5,376.5C 199.167,375.5 199.833,374.5 200.5,373.5 Z"/></g>
<g><path style="opacity:1" fill="#a456d2" d="M 432.5,377.5 C 434.105,384.603 434.772,391.937 434.5,399.5C 433.71,398.391 433.21,397.058 433,395.5C 432.501,389.509 432.334,383.509 432.5,377.5 Z"/></g>
<g><path style="opacity:1" fill="#d898f7" d="M 114.5,387.5 C 114.435,390.428 113.768,393.095 112.5,395.5C 112.294,392.505 112.96,389.838 114.5,387.5 Z"/></g>
<g><path style="opacity:1" fill="#fccbfe" d="M 111.5,407.5 C 111.5,408.167 111.5,408.833 111.5,409.5C 110.501,481.998 110.167,554.665 110.5,627.5C 140.167,627.5 169.833,627.5 199.5,627.5C 169.671,628.498 139.671,628.831 109.5,628.5C 109.333,555.166 109.5,481.833 110,408.5C 110.383,407.944 110.883,407.611 111.5,407.5 Z"/></g>
<g><path style="opacity:1" fill="#8313bf" d="M 434.5,420.5 C 435.499,489.331 435.833,558.331 435.5,627.5C 405.833,627.5 376.167,627.5 346.5,627.5C 346.5,578.167 346.5,528.833 346.5,479.5C 347.499,527.664 347.832,575.997 347.5,624.5C 376.147,626.492 405.147,627.159 434.5,626.5C 434.5,558.833 434.5,491.167 434.5,423.5C 434.5,422.5 434.5,421.5 434.5,420.5 Z"/></g>
<g><path style="opacity:1" fill="#e6b9fc" d="M 434.5,399.5 C 435.327,404.651 435.827,409.984 436,415.5C 436.832,486.335 436.665,557.001 435.5,627.5C 435.833,558.331 435.499,489.331 434.5,420.5C 434.5,413.5 434.5,406.5 434.5,399.5 Z"/></g>
<g><path style="opacity:1" fill="#c48ee5" d="M 202.5,362.5 C 202.271,369.515 201.771,376.515 201,383.5C 200.833,465.001 200.333,546.334 199.5,627.5C 199.18,542.815 199.513,458.149 200.5,373.5C 201.026,369.688 201.693,366.021 202.5,362.5 Z"/></g>
<g><path style="opacity:1" fill="#9800e9" d="M 434.5,423.5 C 434.5,491.167 434.5,558.833 434.5,626.5C 405.147,627.159 376.147,626.492 347.5,624.5C 375.833,624.5 404.167,624.5 432.5,624.5C 432.333,556.166 432.5,487.833 433,419.5C 433.21,421.058 433.71,422.391 434.5,423.5 Z"/></g>
<g><path style="opacity:1" fill="#fde2ff" d="M 554.5,447.5 C 555.97,463.978 556.637,480.645 556.5,497.5C 555.683,495.031 555.183,492.365 555,489.5C 554.5,480.84 554.334,472.173 554.5,463.5C 554.5,458.167 554.5,452.833 554.5,447.5 Z"/></g>
<g><path style="opacity:1" fill="#e6b4fd" d="M 788.5,497.5 C 788.749,501.458 788.082,505.124 786.5,508.5C 786.5,506.833 786.5,505.167 786.5,503.5C 787.167,501.5 787.833,499.5 788.5,497.5 Z"/></g>
<g><path style="opacity:1" fill="#e6b5fa" d="M 703.5,596.5 C 700.146,598.258 696.479,599.258 692.5,599.5C 695.854,597.742 699.521,596.742 703.5,596.5 Z"/></g>
<g><path style="opacity:1" fill="#d196ef" d="M 639.5,597.5 C 642.152,597.41 644.485,598.076 646.5,599.5C 643.848,599.59 641.515,598.924 639.5,597.5 Z"/></g>
<g><path style="opacity:1" fill="#eebef9" d="M 692.5,599.5 C 683.638,600.905 674.638,601.905 665.5,602.5C 665.167,601.833 664.833,601.167 664.5,600.5C 665.5,600.5 666.5,600.5 667.5,600.5C 675.848,600.457 684.181,600.124 692.5,599.5 Z"/></g>
<g><path style="opacity:1" fill="#e8b7fd" d="M 345.5,436.5 C 346.496,450.657 346.829,464.99 346.5,479.5C 346.5,528.833 346.5,578.167 346.5,627.5C 376.167,627.5 405.833,627.5 435.5,627.5C 405.671,628.498 375.671,628.831 345.5,628.5C 345.5,564.5 345.5,500.5 345.5,436.5 Z"/></g>
<g><path style="opacity:1" fill="#eeccfd" d="M 617.5,631.5 C 614.032,634.114 610.032,635.114 605.5,634.5C 609.313,633.213 613.313,632.213 617.5,631.5 Z"/></g>
<g><path style="opacity:1" fill="#902eca" d="M 549.5,631.5 C 566.696,634.144 584.03,635.144 601.5,634.5C 598.375,635.479 595.042,635.813 591.5,635.5C 581.461,635.758 571.461,635.424 561.5,634.5C 557.098,634.692 553.098,633.692 549.5,631.5 Z"/></g>
<g><path style="opacity:1" fill="#e2b3f9" d="M 561.5,634.5 C 571.461,635.424 581.461,635.758 591.5,635.5C 582.009,636.658 572.342,636.825 562.5,636C 561.944,635.617 561.611,635.117 561.5,634.5 Z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 671 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="200px" height="200px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
<g><path style="opacity:1" fill="#fefefe" d="M -0.5,-0.5 C 66.1667,-0.5 132.833,-0.5 199.5,-0.5C 199.5,66.1667 199.5,132.833 199.5,199.5C 132.833,199.5 66.1667,199.5 -0.5,199.5C -0.5,132.833 -0.5,66.1667 -0.5,-0.5 Z"/></g>
<g><path style="opacity:1" fill="#0e0e0e" d="M 119.5,47.5 C 133.743,46.0344 143.909,51.701 150,64.5C 154.009,81.9852 147.509,93.4852 130.5,99C 123.167,99.3333 115.833,99.6667 108.5,100C 104.333,101.5 101.5,104.333 100,108.5C 99.5001,122.829 99.3334,137.163 99.5,151.5C 82.1667,151.5 64.8333,151.5 47.5,151.5C 47.5,132.833 47.5,114.167 47.5,95.5C 60.0736,101.213 72.4069,100.713 84.5,94C 88.6667,91.1667 92.1667,87.6667 95,83.5C 97.7515,75.0718 100.752,66.7384 104,58.5C 108.127,53.202 113.294,49.5354 119.5,47.5 Z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="2030px" height="2048px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
<g><path style="opacity:0.999" fill="#0066ff" d="M 922.5,-0.5 C 984.167,-0.5 1045.83,-0.5 1107.5,-0.5C 1183.34,2.62698 1259.01,9.46031 1334.5,20C 1435.99,34.2851 1532.99,63.2851 1625.5,107C 1686.68,137.224 1742.68,174.891 1793.5,220C 1851.84,280.056 1898,348.556 1932,425.5C 1968.98,509.727 1994.31,597.394 2008,688.5C 2018.55,761.657 2025.72,834.99 2029.5,908.5C 2029.5,984.833 2029.5,1061.17 2029.5,1137.5C 2025.59,1213.37 2018.09,1289.04 2007,1364.5C 1992.77,1456.52 1966.44,1544.85 1928,1629.5C 1897.8,1694.64 1859.13,1753.97 1812,1807.5C 1763.29,1856.1 1708.46,1896.26 1647.5,1928C 1544.73,1980.25 1436.06,2013.59 1321.5,2028C 1239.36,2038.97 1157.03,2045.47 1074.5,2047.5C 1060.5,2047.5 1046.5,2047.5 1032.5,2047.5C 1020.83,2046.17 1009.17,2046.17 997.5,2047.5C 983.5,2047.5 969.5,2047.5 955.5,2047.5C 872.975,2045.46 790.642,2038.96 708.5,2028C 606.933,2014.94 509.599,1987.28 416.5,1945C 347.284,1912.42 284.617,1870.42 228.5,1819C 172.903,1758.37 128.403,1690.2 95,1614.5C 60.5996,1534.57 36.5996,1451.57 23,1365.5C 10.7368,1283.1 2.90342,1200.43 -0.5,1117.5C -0.5,1054.5 -0.5,991.5 -0.5,928.5C 2.77579,849.967 9.94246,771.634 21,693.5C 36.75,581.253 70.75,474.92 123,374.5C 154.057,316.905 192.557,264.739 238.5,218C 316.452,150.162 404.785,99.4952 503.5,66C 559.947,46.805 617.613,32.4717 676.5,23C 758.221,10.617 840.221,2.78365 922.5,-0.5 Z"/></g>
<g><path style="opacity:1" fill="#fefeff" d="M 626.5,1312.5 C 626.5,1276.83 626.5,1241.17 626.5,1205.5C 722.5,1205.5 818.5,1205.5 914.5,1205.5C 914.333,1244.17 914.5,1282.83 915,1321.5C 919.897,1362.39 941.73,1389.55 980.5,1403C 1004.93,1409.12 1029.59,1410.12 1054.5,1406C 1094.33,1398.51 1118.83,1375.01 1128,1335.5C 1139.64,1293.91 1132.31,1256.24 1106,1222.5C 1094.47,1209.3 1081.97,1197.13 1068.5,1186C 1051.72,1173.22 1034.38,1161.22 1016.5,1150C 961.491,1118.16 906.158,1086.83 850.5,1056C 810.408,1032.63 772.408,1006.29 736.5,977C 708.562,953.08 685.062,925.58 666,894.5C 645.646,856.764 634.646,816.431 633,773.5C 624.333,602.57 702.833,497.07 868.5,457C 927.844,444.215 987.844,439.548 1048.5,443C 1106.86,444.281 1163.52,454.614 1218.5,474C 1318.44,513.324 1371.28,586.824 1377,694.5C 1377.5,726.832 1377.67,759.165 1377.5,791.5C 1288.17,791.5 1198.83,791.5 1109.5,791.5C 1109.67,765.165 1109.5,738.831 1109,712.5C 1103.68,665.514 1077.85,637.347 1031.5,628C 1000.82,622.223 972.154,627.223 945.5,643C 926.118,658.253 914.285,678.086 910,702.5C 905.639,729.545 909.639,755.212 922,779.5C 936.918,800.419 955.085,817.919 976.5,832C 993.234,843.062 1010.23,853.729 1027.5,864C 1086.31,895.238 1144.65,927.238 1202.5,960C 1251.24,988.047 1295.4,1022.21 1335,1062.5C 1363.36,1092.86 1383.19,1128.19 1394.5,1168.5C 1403.09,1210.74 1405.93,1253.41 1403,1296.5C 1401.52,1447.37 1328.36,1543.2 1183.5,1584C 1116.22,1600.81 1047.89,1607.14 978.5,1603C 920.733,1601.37 864.733,1590.71 810.5,1571C 693.944,1524.55 632.61,1438.38 626.5,1312.5 Z"/></g>
<g><path style="opacity:1" fill="#8eb7ff" d="M 914.5,1205.5 C 818.5,1205.5 722.5,1205.5 626.5,1205.5C 626.5,1241.17 626.5,1276.83 626.5,1312.5C 625.502,1276.67 625.168,1240.67 625.5,1204.5C 722.001,1204.17 818.335,1204.5 914.5,1205.5 Z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 389 KiB

After

Width:  |  Height:  |  Size: 429 B

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="2400px" height="2800px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
<g><path style="opacity:1" fill="#9146ff" d="M 498.5,-0.5 C 1132.17,-0.5 1765.83,-0.5 2399.5,-0.5C 2399.5,466.5 2399.5,933.5 2399.5,1400.5C 2099.7,1699.8 1800.03,1999.3 1500.5,2299C 1366.83,2299.33 1233.17,2299.67 1099.5,2300C 932.965,2466.37 766.632,2632.87 600.5,2799.5C 600.167,2799.5 599.833,2799.5 599.5,2799.5C 599.5,2632.83 599.5,2466.17 599.5,2299.5C 399.5,2299.5 199.5,2299.5 -0.5,2299.5C -0.5,1699.17 -0.5,1098.83 -0.5,498.5C 166.167,332.5 332.5,166.167 498.5,-0.5 Z"/></g>
<g><path style="opacity:1" fill="#fefffe" d="M 599.5,199.5 C 1132.83,199.5 1666.17,199.5 2199.5,199.5C 2199.67,566.167 2199.5,932.833 2199,1299.5C 2065.83,1432.67 1932.67,1565.83 1799.5,1699C 1665.83,1699.33 1532.17,1699.67 1398.5,1700C 1282.33,1816.17 1166.17,1932.33 1050,2048.5C 1049.5,1932.17 1049.33,1815.83 1049.5,1699.5C 899.5,1699.5 749.5,1699.5 599.5,1699.5C 599.5,1199.5 599.5,699.5 599.5,199.5 Z"/></g>
<g><path style="opacity:1" fill="#9146ff" d="M 1149.5,549.5 C 1216.17,549.5 1282.83,549.5 1349.5,549.5C 1349.5,749.5 1349.5,949.5 1349.5,1149.5C 1282.83,1149.5 1216.17,1149.5 1149.5,1149.5C 1149.5,949.5 1149.5,749.5 1149.5,549.5 Z"/></g>
<g><path style="opacity:1" fill="#9146ff" d="M 1699.5,549.5 C 1766.17,549.5 1832.83,549.5 1899.5,549.5C 1899.5,749.5 1899.5,949.5 1899.5,1149.5C 1832.83,1149.5 1766.17,1149.5 1699.5,1149.5C 1699.5,949.5 1699.5,749.5 1699.5,549.5 Z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -7,6 +7,15 @@ If you would like to add your own custom icon, please open a pull-request with
the relevant SVG placed within `assets/custom-icons/icons` and add the
corresponding entry within `assets/custom-icons/_data/custom-icons.json`.
Please be careful to upload small and optimized icon files. If your icon file
is over 50KB, it is likely not optimized.
Note that the correspondence between the icon and the issuer is based on the name
of the issuer provided by the user, excluding spaces. Only the text before the
first dot "." or left parentheses "(" will be used for icon matching.
e.g. Issuer name provided: "github.com (Main account)" - Then "github" will be
used for matching.
This JSON file contains the following attributes:
| Attribute | Usecase | Required |

View File

@@ -1,8 +1,10 @@
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:ente_auth/core/configuration.dart';
import 'package:ente_auth/core/event_bus.dart';
import 'package:ente_auth/core/win_http_client.dart';
import 'package:ente_auth/events/endpoint_updated_event.dart';
import 'package:ente_auth/utils/package_info_util.dart';
import 'package:ente_auth/utils/platform_util.dart';
@@ -50,6 +52,19 @@ class Network {
},
),
);
if (Platform.isWindows) {
final customHttpClient = windowsHttpClient();
_enteDio.httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () {
return customHttpClient;
},
);
_dio.httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () {
return customHttpClient;
},
);
}
_setupInterceptors(endpoint);
Bus.instance.on<EndpointUpdatedEvent>().listen((event) {

View File

@@ -0,0 +1,71 @@
import 'dart:convert';
import 'dart:io';
import 'package:logging/logging.dart';
/*
Reference from
https://github.com/realm/realm-dart/blob/main/packages/realm_dart/lib/src/handles/native/default_client.dart
https://github.com/realm/realm-dart/pull/1378
*/
HttpClient windowsHttpClient() {
final logger = Logger("WindowsHttpClient");
const isrgRootX1CertPEM = // The root certificate used by lets encrypt
'''
subject=CN=ISRG Root X1,O=Internet Security Research Group,C=US
issuer=CN=DST Root CA X3,O=Digital Signature Trust Co.
-----BEGIN CERTIFICATE-----
MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC
ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL
wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D
LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK
4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5
bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y
sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ
Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4
FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc
SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql
PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND
TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1
c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx
+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB
ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu
b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E
U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu
MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC
5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW
9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG
WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O
he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC
Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5
-----END CERTIFICATE-----''';
if (Platform.isWindows) {
final context = SecurityContext(withTrustedRoots: true);
try {
logger.info('Adding certificate to trusted certificates');
context.setTrustedCertificatesBytes(
const AsciiEncoder().convert(isrgRootX1CertPEM),
);
logger.info("Certificate added to trusted certificates");
return HttpClient(context: context);
} on TlsException catch (e) {
logger.warning(
"Error adding certificate to trusted certificates: ${e.osError?.message}",
);
// certificate is already trusted. Nothing to do here
if (e.osError?.message.contains("CERT_ALREADY_IN_HASH_TABLE") != true) {
rethrow;
} else {
return HttpClient();
}
}
}
throw UnsupportedError("This platform is not supported");
}

View File

@@ -263,6 +263,8 @@
"exportLogs": "Export logs",
"enterYourRecoveryKey": "Enter your recovery key",
"tempErrorContactSupportIfPersists": "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team.",
"networkHostLookUpErr": "Unable to connect to Ente, please check your network settings and contact support if the error persists.",
"networkConnectionRefusedErr": "Unable to connect to Ente, please retry after sometime. If the error persists, please contact support.",
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "It looks like something went wrong. Please retry after some time. If the error persists, please contact our support team.",
"about": "About",
"weAreOpenSource": "We are open source!",

View File

@@ -49,7 +49,7 @@ class PasskeyService {
);
} catch (e) {
Logger('PasskeyService').severe("failed to open passkey page", e);
showGenericErrorDialog(context: context).ignore();
showGenericErrorDialog(context: context, error: e).ignore();
}
}
}

View File

@@ -101,7 +101,7 @@ class UserService {
);
return;
}
unawaited(showGenericErrorDialog(context: context));
unawaited(showGenericErrorDialog(context: context, error: null));
} on DioException catch (e) {
await dialog.hide();
_logger.info(e);
@@ -114,12 +114,12 @@ class UserService {
),
);
} else {
unawaited(showGenericErrorDialog(context: context));
unawaited(showGenericErrorDialog(context: context, error: e));
}
} catch (e) {
await dialog.hide();
_logger.severe(e);
unawaited(showGenericErrorDialog(context: context));
unawaited(showGenericErrorDialog(context: context, error: e));
}
}
@@ -227,7 +227,7 @@ class UserService {
//to close and only then to show the error dialog.
Future.delayed(
const Duration(milliseconds: 150),
() => showGenericErrorDialog(context: context),
() => showGenericErrorDialog(context: context, error: e),
);
rethrow;
}
@@ -248,7 +248,10 @@ class UserService {
}
} catch (e) {
_logger.severe(e);
await showGenericErrorDialog(context: context);
await showGenericErrorDialog(
context: context,
error: e,
);
return null;
}
}

View File

@@ -412,7 +412,10 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
_logger.severe(e, s);
await dialog.hide();
// ignore: unawaited_futures
showGenericErrorDialog(context: context);
showGenericErrorDialog(
context: context,
error: e,
);
}
}
@@ -472,7 +475,10 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
_logger.severe(e, s);
await dialog.hide();
// ignore: unawaited_futures
showGenericErrorDialog(context: context);
showGenericErrorDialog(
context: context,
error: e,
);
}
}
@@ -500,7 +506,10 @@ class _PasswordEntryPageState extends State<PasswordEntryPage> {
);
} else {
// ignore: unawaited_futures
showGenericErrorDialog(context: context);
showGenericErrorDialog(
context: context,
error: e,
);
}
}
}

View File

@@ -47,7 +47,10 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
"Please check your internet connection and try again.",
);
} else {
await showGenericErrorDialog(context: context);
await showGenericErrorDialog(
context: context,
error: e,
);
}
return;
}
@@ -107,7 +110,10 @@ class _VerifyRecoveryPageState extends State<VerifyRecoveryPage> {
);
} catch (e) {
// ignore: unawaited_futures
showGenericErrorDialog(context: context);
showGenericErrorDialog(
context: context,
error: e,
);
return;
}
}

View File

@@ -485,7 +485,10 @@ class _ButtonChildWidgetState extends State<ButtonChildWidget> {
} else if (exception != null) {
//This is to show the execution was unsuccessful if the dialog is manually
//closed before the execution completes.
showGenericErrorDialog(context: context);
showGenericErrorDialog(
context: context,
error: exception,
);
}
}

View File

@@ -56,7 +56,8 @@ class _HomePageState extends State<HomePage> {
final scaffoldKey = GlobalKey<ScaffoldState>();
final TextEditingController _textController = TextEditingController();
final FocusNode searchInputFocusNode = FocusNode();
final bool _autoFocusSearch =
PreferenceService.instance.shouldAutoFocusOnSearchBar();
bool _showSearchBox = false;
String _searchText = "";
List<Code>? _allCodes;
@@ -87,18 +88,7 @@ class _HomePageState extends State<HomePage> {
_iconsChangedEvent = Bus.instance.on<IconsChangedEvent>().listen((event) {
setState(() {});
});
_showSearchBox = PreferenceService.instance.shouldAutoFocusOnSearchBar();
if (_showSearchBox) {
WidgetsBinding.instance.addPostFrameCallback(
(_) {
// https://github.com/flutter/flutter/issues/20706#issuecomment-646328652
FocusScope.of(context).unfocus();
Timer(const Duration(milliseconds: 1), () {
FocusScope.of(context).requestFocus(searchInputFocusNode);
});
},
);
}
_showSearchBox = _autoFocusSearch;
}
void _loadCodes() {
@@ -240,8 +230,7 @@ class _HomePageState extends State<HomePage> {
: TextField(
autocorrect: false,
enableSuggestions: false,
focusNode: searchInputFocusNode,
autofocus: _searchText.isEmpty,
autofocus: _autoFocusSearch,
controller: _textController,
onChanged: (val) {
_searchText = val;
@@ -460,7 +449,10 @@ class _HomePageState extends State<HomePage> {
CodeStore.instance.addCode(newCode);
_focusNewCode(newCode);
} catch (e, s) {
showGenericErrorDialog(context: context);
showGenericErrorDialog(
context: context,
error: e,
);
_logger.severe("error while handling deeplink", e, s);
}
}

View File

@@ -69,7 +69,7 @@ class _PasskeyPageState extends State<PasskeyPage> {
return;
} catch (e, s) {
_logger.severe("failed to check status", e, s);
showGenericErrorDialog(context: context).ignore();
showGenericErrorDialog(context: context, error: e).ignore();
return;
}
await UserService.instance.onPassKeyVerified(context, response);
@@ -111,7 +111,7 @@ class _PasskeyPageState extends State<PasskeyPage> {
}
} catch (e, s) {
_logger.severe('passKey: failed to handle deeplink', e, s);
showGenericErrorDialog(context: context).ignore();
showGenericErrorDialog(context: context, error: e).ignore();
}
}
@@ -169,7 +169,7 @@ class _PasskeyPageState extends State<PasskeyPage> {
await checkStatus();
} catch (e) {
debugPrint('failed to check status %e');
showGenericErrorDialog(context: context).ignore();
showGenericErrorDialog(context: context, error: e).ignore();
}
},
shouldSurfaceExecutionStates: true,

View File

@@ -111,7 +111,10 @@ class AccountSectionWidget extends StatelessWidget {
CryptoUtil.bin2hex(Configuration.instance.getRecoveryKey());
} catch (e) {
// ignore: unawaited_futures
showGenericErrorDialog(context: context);
showGenericErrorDialog(
context: context,
error: e,
);
return;
}
// ignore: unawaited_futures

View File

@@ -182,7 +182,10 @@ class _SecuritySectionWidgetState extends State<SecuritySectionWidget> {
PasskeyService.instance.openPasskeyPage(buildContext).ignore();
} catch (e, s) {
_logger.severe("failed to open passkey page", e, s);
await showGenericErrorDialog(context: context);
await showGenericErrorDialog(
context: context,
error: e,
);
}
}

View File

@@ -13,6 +13,8 @@ import 'package:ente_auth/ui/components/components_constants.dart';
import 'package:ente_auth/ui/components/dialog_widget.dart';
import 'package:ente_auth/ui/components/models/button_result.dart';
import 'package:ente_auth/ui/components/models/button_type.dart';
import 'package:ente_auth/utils/email_util.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
typedef DialogBuilder = DialogWidget Function(BuildContext context);
@@ -69,22 +71,97 @@ Future<ButtonResult?> showErrorDialogForException({
);
}
String parseErrorForUI(
BuildContext context,
String genericError, {
Object? error,
bool surfaceError = kDebugMode,
}) {
try {
if (error == null) {
return genericError;
}
if (error is DioException) {
final DioException dioError = error;
if (dioError.type == DioExceptionType.unknown) {
if (dioError.error.toString().contains('Failed host lookup')) {
return context.l10n.networkHostLookUpErr;
} else if (dioError.error.toString().contains('SocketException')) {
return context.l10n.networkConnectionRefusedErr;
}
}
}
// return generic error if the user is not internal and the error is not in debug mode
if (!kDebugMode) {
return genericError;
}
String errorInfo = "";
if (error is DioException) {
final DioException dioError = error;
if (dioError.type == DioExceptionType.badResponse) {
if (dioError.response?.data["code"] != null) {
errorInfo = "Reason: " + dioError.response!.data["code"];
} else {
errorInfo = "Reason: " + dioError.response!.data.toString();
}
} else if (dioError.type == DioExceptionType.unknown) {
errorInfo = "Reason: " + dioError.error.toString();
} else {
errorInfo = "Reason: " + dioError.type.toString();
}
} else {
if (kDebugMode) {
errorInfo = error.toString();
} else {
errorInfo = error.toString().split('Source stack')[0];
}
}
if (errorInfo.isNotEmpty) {
return "$genericError\n\n$errorInfo";
}
return genericError;
} catch (e) {
return genericError;
}
}
///Will return null if dismissed by tapping outside
Future<ButtonResult?> showGenericErrorDialog({
required BuildContext context,
bool isDismissible = true,
required Object? error,
}) async {
final errorBody = parseErrorForUI(
context,
context.l10n.itLooksLikeSomethingWentWrongPleaseRetryAfterSome,
error: error,
);
return showDialogWidget(
context: context,
title: context.l10n.error,
icon: Icons.error_outline_outlined,
body: context.l10n.itLooksLikeSomethingWentWrongPleaseRetryAfterSome,
body: errorBody,
isDismissible: isDismissible,
buttons: const [
buttons: [
ButtonWidget(
buttonType: ButtonType.primary,
labelText: context.l10n.ok,
buttonAction: ButtonAction.first,
isInAlert: true,
),
ButtonWidget(
buttonType: ButtonType.secondary,
labelText: "OK",
isInAlert: true,
labelText: context.l10n.contactSupport,
buttonAction: ButtonAction.second,
onTap: () async {
await sendLogs(
context,
context.l10n.contactSupport,
"support@ente.io",
postShare: () {},
);
},
),
],
);

View File

@@ -1,6 +1,8 @@
display_name: Auth
license: GPLv3
metainfo: linux/packaging/ente_auth.appdata.xml
icon: assets/icons/auth-icon.png
keywords:

View File

@@ -10,6 +10,8 @@ license: GPLv3
icon: assets/icons/auth-icon.png
installed_size: 36000
metainfo: linux/packaging/ente_auth.appdata.xml
dependencies:
- libwebkit2gtk-4.0-37
- libsqlite3-0

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
<id>ente_auth</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>AGPL-3.0</project_license>
<name>Ente Auth</name>
<summary>Open source 2FA authenticator, with end-to-end encrypted backups</summary>
<description>
<p>Auth provides end-to-end encrypted cloud backups so you don't have to worry about losing your tokens. Our cryptography has been externally audited.</p>
<p>Auth has an app for every platform. Mobile, desktop and web. Your codes sync across all your devices, end-to-end encrypted.</p>
<p>Auth also comes with Offline mode, tags, icons, pins, import/export and more</p>
</description>
<launchable type="desktop-id">ente_auth.desktop</launchable>
<url type="homepage">https://ente.io/auth</url>
<screenshots>
<screenshot type="default">
<image>https://raw.githubusercontent.com/ente-io/ente/main/.github/assets/auth.png</image>
</screenshot>
</screenshots>
<releases>
<release version="3.0.12" date="2024-06-17"/>
</releases>
<provides>
<id>ente_auth.desktop</id>
</provides>
<content_rating type="oars-1.0" />
<developer id="io.github.ente-io.ente">
<name>Ente.io Developers</name>
</developer>
<update_contact>human@ente.io</update_contact>
</component>

View File

@@ -0,0 +1,58 @@
display_name: Auth
package_name: auth
maintainer:
name: Ente.io Developers
email: human@ente.io
licenses:
- GPLv3
icon: assets/icons/auth-icon.png
installed_size: 36000
metainfo: linux/packaging/ente_auth.appdata.xml
dependencies:
- c-ares
- ffmpeg
- gtk3
- http-parser
- libevent
- libvpx
- libxslt
- libxss
- minizip
- nss
- re2
- snappy
- libnotify
- libappindicator-gtk3
keywords:
- Authentication
- 2FA
generic_name: Ente Authentication
categories:
- Utility
supported_mime_type:
- x-scheme-handler/enteauth
postinstall_scripts:
- gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
- update-desktop-database -q
- if [ ! -e /usr/lib/libsodium.so.23 ]; then
- " ln -s /usr/lib/libsodium.so /usr/lib/libsodium.so.23"
- fi
postupgrade_scripts:
- post_install
postremove_scripts:
- gtk-update-icon-cache -q -t -f usr/share/icons/hicolor
- update-desktop-database -q
- if [ -e /usr/lib/libsodium.so.23 ]; then
- rm /usr/lib/libsodium.so.23
- fi
startup_notify: false

View File

@@ -9,6 +9,8 @@ url: https://github.com/ente-io/ente
display_name: Auth
metainfo: linux/packaging/ente_auth.appdata.xml
requires:
- libsqlite3x
- webkit2gtk4.0

View File

@@ -1,6 +1,6 @@
name: ente_auth
description: ente two-factor authenticator
version: 3.0.13+313
version: 3.0.17+317
publish_to: none
environment:

View File

@@ -58,6 +58,27 @@ var _disable2faCmd = &cobra.Command{
},
}
var _disablePasskeyCmd = &cobra.Command{
Use: "disable-passkey",
Short: "Disable passkey for a user",
RunE: func(cmd *cobra.Command, args []string) error {
recoverWithLog()
var flags = &model.AdminActionForUser{}
cmd.Flags().VisitAll(func(f *pflag.Flag) {
if f.Name == "admin-user" {
flags.AdminEmail = f.Value.String()
}
if f.Name == "user" {
flags.UserEmail = f.Value.String()
}
})
if flags.UserEmail == "" {
return fmt.Errorf("user email is required")
}
return ctrl.DisablePasskeys(context.Background(), *flags)
},
}
var _deleteUser = &cobra.Command{
Use: "delete-user",
Short: "Delete a user",
@@ -130,11 +151,13 @@ func init() {
_listUsers.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
_disable2faCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
_disable2faCmd.Flags().StringP("user", "u", "", "The email of the user to disable 2FA for. (required)")
_disablePasskeyCmd.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
_disablePasskeyCmd.Flags().StringP("user", "u", "", "The email of the user to disable passkey for. (required)")
_deleteUser.Flags().StringP("admin-user", "a", "", "The email of the admin user. ")
_deleteUser.Flags().StringP("user", "u", "", "The email of the user to delete. (required)")
_updateFreeUserStorage.Flags().StringP("admin-user", "a", "", "The email of the admin user.")
_updateFreeUserStorage.Flags().StringP("user", "u", "", "The email of the user to update subscription for. (required)")
// add a flag with no value --no-limit
_updateFreeUserStorage.Flags().String("no-limit", "True", "When true, sets 100TB as storage limit, and expiry to current date + 100 years")
_adminCmd.AddCommand(_userDetailsCmd, _disable2faCmd, _updateFreeUserStorage, _listUsers, _deleteUser)
_adminCmd.AddCommand(_userDetailsCmd, _disable2faCmd, _disablePasskeyCmd, _updateFreeUserStorage, _listUsers, _deleteUser)
}

View File

@@ -25,4 +25,4 @@ ente [flags]
* [ente export](ente_export.md) - Starts the export process
* [ente version](ente_version.md) - Prints the current version
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -16,4 +16,4 @@ Manage account settings
* [ente account list](ente_account_list.md) - list configured accounts
* [ente account update](ente_account_update.md) - Update an existing account's export directory
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -20,4 +20,4 @@ ente account add [flags]
* [ente account](ente_account.md) - Manage account settings
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -18,4 +18,4 @@ ente account get-token [flags]
* [ente account](ente_account.md) - Manage account settings
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -16,4 +16,4 @@ ente account list [flags]
* [ente account](ente_account.md) - Manage account settings
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -19,4 +19,4 @@ ente account update [flags]
* [ente account](ente_account.md) - Manage account settings
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -17,8 +17,9 @@ Commands for admin actions like disable or enabling 2fa, bumping up the storage
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
* [ente admin delete-user](ente_admin_delete-user.md) - Delete a user
* [ente admin disable-2fa](ente_admin_disable-2fa.md) - Disable 2fa for a user
* [ente admin disable-passkey](ente_admin_disable-passkey.md) - Disable passkey for a user
* [ente admin get-user-id](ente_admin_get-user-id.md) - Get user id
* [ente admin list-users](ente_admin_list-users.md) - List all users
* [ente admin update-subscription](ente_admin_update-subscription.md) - Update subscription for user
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -18,4 +18,4 @@ ente admin delete-user [flags]
* [ente admin](ente_admin.md) - Commands for admin actions
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -18,4 +18,4 @@ ente admin disable-2fa [flags]
* [ente admin](ente_admin.md) - Commands for admin actions
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -0,0 +1,21 @@
## ente admin disable-passkey
Disable passkey for a user
```
ente admin disable-passkey [flags]
```
### Options
```
-a, --admin-user string The email of the admin user.
-h, --help help for disable-passkey
-u, --user string The email of the user to disable passkey for. (required)
```
### SEE ALSO
* [ente admin](ente_admin.md) - Commands for admin actions
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -18,4 +18,4 @@ ente admin get-user-id [flags]
* [ente admin](ente_admin.md) - Commands for admin actions
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -17,4 +17,4 @@ ente admin list-users [flags]
* [ente admin](ente_admin.md) - Commands for admin actions
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -23,4 +23,4 @@ ente admin update-subscription [flags]
* [ente admin](ente_admin.md) - Commands for admin actions
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -13,4 +13,4 @@ Authenticator commands
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
* [ente auth decrypt](ente_auth_decrypt.md) - Decrypt authenticator export
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -16,4 +16,4 @@ ente auth decrypt [input] [output] [flags]
* [ente auth](ente_auth.md) - Authenticator commands
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -16,4 +16,4 @@ ente export [flags]
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -16,4 +16,4 @@ ente version [flags]
* [ente](ente.md) - CLI tool for exporting your photos from ente.io
###### Auto generated by spf13/cobra on 6-May-2024
###### Auto generated by spf13/cobra on 22-Jun-2024

View File

@@ -88,6 +88,29 @@ func (c *Client) Disable2Fa(ctx context.Context, userID int64) error {
return nil
}
func (c *Client) DisablePassKeyMFA(ctx context.Context, userID int64) error {
var res interface{}
payload := map[string]interface{}{
"userID": userID,
}
r, err := c.restClient.R().
SetContext(ctx).
SetResult(&res).
SetBody(payload).
Post("/admin/user/disable-passkeys")
if err != nil {
return err
}
if r.IsError() {
return &ApiError{
StatusCode: r.StatusCode(),
Message: r.String(),
}
}
return nil
}
func (c *Client) UpdateFreePlanSub(ctx context.Context, userDetails *models.UserDetails, storageInBytes int64, expiryTimeInMicro int64) error {
var res interface{}
if userDetails.Subscription.ProductID != "free" {

View File

@@ -15,7 +15,7 @@ import (
"strings"
)
var AppVersion = "0.1.16"
var AppVersion = "0.1.17"
func main() {
cliDBPath, err := GetCLIConfigPath()

View File

@@ -82,6 +82,27 @@ func (c *ClICtrl) Disable2FA(ctx context.Context, params model.AdminActionForUse
return nil
}
func (c *ClICtrl) DisablePasskeys(ctx context.Context, params model.AdminActionForUser) error {
accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail)
if err != nil {
return err
}
userDetails, err := c.Client.GetUserIdFromEmail(accountCtx, params.UserEmail)
if err != nil {
return err
}
err = c.Client.DisablePassKeyMFA(accountCtx, userDetails.User.ID)
if err != nil {
if apiErr, ok := err.(*api.ApiError); ok && apiErr.StatusCode == 400 && strings.Contains(apiErr.Message, "Token is too old") {
fmt.Printf("Error: Old admin token, please re-authenticate using `ente account add` \n")
return nil
}
return err
}
fmt.Println("Successfully disabled passkey for user")
return nil
}
func (c *ClICtrl) UpdateFreeStorage(ctx context.Context, params model.AdminActionForUser, noLimit bool) error {
accountCtx, err := c.buildAdminContext(ctx, params.AdminEmail)
if err != nil {

View File

@@ -12,9 +12,9 @@ import (
)
func GetDB(path string) (*bolt.DB, error) {
db, err := bolt.Open(path, 0600, &bolt.Options{Timeout: 1 * time.Second})
db, err := bolt.Open(path, 0600, &bolt.Options{Timeout: 5 * time.Second})
if err != nil {
log.Fatal(err)
log.Fatal(fmt.Sprintf("Failed to open db %s ", path), err)
}
return db, err
}

View File

@@ -455,20 +455,51 @@ const allowExternalLinks = (webContents: WebContents) =>
/**
* Allow uploading to arbitrary S3 buckets.
*
* The files in the desktop app are served over the ente:// protocol. During
* testing or self-hosting, we might be using a S3 bucket that does not allow
* whitelisting a custom URI scheme. To avoid requiring the bucket to set an
* "Access-Control-Allow-Origin: *" or do a echo-back of `Origin`, we add a
* workaround here instead, intercepting the ACAO header and allowing `*`.
* The files in the desktop app are served over the ente:// protocol. When that
* is returned as the CORS allowed origin, "Access-Control-Allow-Origin:
* ente://app", CORS requests fail.
*
* Further, during testing or self-hosting, file uploads involve a redirection
* (This doesn't affect our production systems since we upload via a worker,
* See: [Note: Passing credentials for self-hosted file fetches]).
*
* In some cases, we might be using a S3 bucket that does not allow whitelisting
* a custom URI scheme. Echoing back the value of `Origin` (even if the bucket
* would allow us to) would also not work, since the browser sends `null` as the
* `Origin` for the redirected request (this is as per the CORS spec). So the
* only way in such cases would be to require the bucket to set an
* "Access-Control-Allow-Origin: *".
*
* To avoid these issues, we intercepting the ACAO header and set it to `*`.
*
* However, that cause problems with requests that use credentials since "*" is
* not a valid value in such cases. One such example is the HCaptcha requests
* made by Stripe when we initiate a payment within the desktop app:
*
* > Access to XMLHttpRequest at 'https://api2.hcaptcha.com/getcaptcha/xxx' from
* > origin 'https://newassets.hcaptcha.com' has been blocked by CORS policy:
* > The value of the 'Access-Control-Allow-Origin' header in the response must
* > not be the wildcard '*' when the request's credentials mode is 'include'.
* > The credentials mode of requests initiated by the XMLHttpRequest is
* > controlled by the withCredentials attribute.
*
* So we only do this workaround if there was either no ACAO specified in the
* response, or if the ACAO was "ente://app".
*/
const allowAllCORSOrigins = (webContents: WebContents) =>
webContents.session.webRequest.onHeadersReceived(
({ responseHeaders }, callback) => {
const headers: NonNullable<typeof responseHeaders> = {};
for (const [key, value] of Object.entries(responseHeaders ?? {}))
if (key.toLowerCase() != "access-control-allow-origin")
headers[key] = value;
headers["Access-Control-Allow-Origin"] = ["*"];
for (const [key, value] of Object.entries(responseHeaders ?? {}))
if (key.toLowerCase() == "access-control-allow-origin") {
headers["Access-Control-Allow-Origin"] =
value[0] == rendererURL ? ["*"] : value;
} else {
headers[key] = value;
}
callback({ responseHeaders: headers });
},
);

View File

@@ -11,12 +11,15 @@
"preview": "vite preview"
},
"dependencies": {
"date-fns": "^3.6.0",
"react": "^18",
"react-datepicker": "^7.1.0",
"react-dom": "^18",
"react-toastify": "^10.0.5",
"zod": "^3"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/react": "^18",
"@types/react-dom": "^18",
"@typescript-eslint/eslint-plugin": "^7",
@@ -29,7 +32,7 @@
"prettier": "^3",
"prettier-plugin-organize-imports": "^3.2",
"prettier-plugin-packagejson": "^2.5",
"typescript": "^5.4.5",
"typescript": "^5",
"vite": "^5.2"
},
"packageManager": "yarn@1.22.22"

View File

@@ -19,6 +19,20 @@
border-radius: 5px;
margin-top: 20px;
}
#submitbtn {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
background-color: #009879;
color: white;
border: none;
border-radius: 5px;
margin-top: 20px;
}
#submitbtn:hover {
background-color: #007c6c;
}
.fetch-button-container button:hover {
background-color: #007c6c;
@@ -122,3 +136,321 @@ button {
.dropdown-menu button:hover {
background-color: #f0f0f0;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #ffffff;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
max-width: 80%;
max-height: 80%;
overflow: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 10px;
border-bottom: 1px solid #ccc;
}
.modal-header .close-btn {
cursor: pointer;
color: #777;
font-size: 20px;
}
.modal-content {
margin-top: 10px;
}
/* Styles for draggable modal */
.modal.draggable {
cursor: move;
}
.modal.draggable .modal-header {
cursor: move;
}
.popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: lightgreen;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.popup-content {
display: flex;
flex-direction: column;
}
.popup-content div {
margin-bottom: 10px;
}
:root {
--popup-bg-color-light: #fff;
--popup-bg-color-dark: #2c2c2c;
--popup-border-color-light: #ccc;
--popup-border-color-dark: #444;
--popup-text-color-light: #000;
--popup-text-color-dark: #fff;
--popup-shadow-light: rgba(0, 0, 0, 0.1);
--popup-shadow-dark: rgba(255, 255, 255, 0.1);
}
.update-subscription-popup {
position: fixed;
top: 50%;
left: 50%;
width: 400px;
transform: translate(-50%, -50%);
background-color: var(--popup-bg-color-light);
border: 1px solid var(--popup-border-color-light);
padding: 20px;
z-index: 1000;
box-shadow: 0px 0px 10px var(--popup-shadow-light);
}
.popup-content {
display: flex;
flex-direction: column;
}
.close-button {
align-self: flex-end;
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--popup-text-color-light);
}
.popup-content h2 {
margin-top: 0;
}
.popup-content form label {
display: block;
margin-bottom: 10px;
}
.popup-content form input,
.popup-content form select {
width: 100%;
padding: 8px;
margin-top: 5px;
background-color: var(--popup-bg-color-light);
color: var(--popup-text-color-light);
border: 1px solid var(--popup-border-color-light);
}
.popup-content form button {
padding: 10px 15px;
margin-top: 10px;
cursor: pointer;
background-color: var(--popup-bg-color-light);
color: var(--popup-text-color-light);
border: 1px solid var(--popup-border-color-light);
}
.custom-select {
position: relative;
width: 100%;
}
.custom-select select {
width: 100%;
padding: 8px;
cursor: pointer;
background-color: var(--popup-bg-color-light);
color: var(--popup-text-color-light);
border: 1px solid var(--popup-border-color-light);
appearance: none;
}
.custom-select::after {
content: "\25BC";
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
pointer-events: none;
}
.message {
margin-top: 10px;
padding: 10px;
border-radius: 5px;
}
.message.error {
background-color: #f8d7da;
color: #721c24;
}
.message.success {
background-color: #d4edda;
color: #155724;
}
@media (prefers-color-scheme: dark) {
.update-subscription-popup {
background-color: var(--popup-bg-color-dark);
border-color: var(--popup-border-color-dark);
color: var(--popup-text-color-dark);
box-shadow: 0px 0px 10px var(--popup-shadow-dark);
}
.close-button {
color: var(--popup-text-color-dark);
}
.popup-content form input,
.popup-content form select {
background-color: var(--popup-bg-color-dark);
color: var(--popup-text-color-dark);
border: 1px solid var(--popup-border-color-dark);
}
.popup-content form button {
background-color: var(--popup-bg-color-dark);
color: var(--popup-text-color-dark);
border: 1px solid var(--popup-border-color-dark);
}
}
:root {
--popup-bg-color-light: #fff;
--popup-bg-color-dark: #2c2c2c;
--popup-border-color-light: #ccc;
--popup-border-color-dark: #444;
--popup-text-color-light: #000;
--popup-text-color-dark: #fff;
--popup-shadow-light: rgba(0, 0, 0, 0.1);
--popup-shadow-dark: rgba(255, 255, 255, 0.1);
}
.update-subscription-popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: var(--popup-bg-color-light);
border: 1px solid var(--popup-border-color-light);
padding: 20px;
z-index: 1000;
box-shadow: 0px 0px 10px var(--popup-shadow-light);
}
.popup-content {
display: flex;
flex-direction: column;
}
.close-button {
align-self: flex-end;
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--popup-text-color-light);
}
.popup-content h2 {
margin-top: 0;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input,
.form-group select {
width: 100%;
padding: 8px;
background-color: var(--popup-bg-color-light);
color: var(--popup-text-color-light);
border: 1px solid var(--popup-border-color-light);
border-radius: 5px;
margin-top: 5px;
}
.custom-select {
position: relative;
width: 100%;
}
.custom-select select {
width: 100%;
padding: 8px;
cursor: pointer;
background-color: var(--popup-bg-color-light);
color: var(--popup-text-color-light);
border: 1px solid var(--popup-border-color-light);
appearance: none;
}
.custom-select::after {
content: "\25BC";
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
pointer-events: none;
}
.message {
margin-top: 10px;
padding: 10px;
border-radius: 5px;
}
.message.error {
background-color: #f8d7da;
color: #721c24;
}
.message.success {
background-color: #d4edda;
color: #155724;
}
@media (prefers-color-scheme: dark) {
.update-subscription-popup {
background-color: var(--popup-bg-color-dark);
border-color: var(--popup-border-color-dark);
color: var(--popup-text-color-dark);
box-shadow: 0px 0px 10px var(--popup-shadow-dark);
}
.close-button {
color: var(--popup-text-color-dark);
}
.form-group input,
.form-group select {
background-color: var(--popup-bg-color-dark);
color: var(--popup-text-color-dark);
border: 1px solid var(--popup-border-color-dark);
}
.form-group button {
background-color: var(--popup-bg-color-dark);
color: var(--popup-text-color-dark);
border: 1px solid var(--popup-border-color-dark);
}
}

View File

@@ -15,7 +15,7 @@ export const App: React.FC = () => {
const [email, setEmail] = useState<string>("");
const [userData, setUserData] = useState<UserData | null>(null);
const [error, setError] = useState<string | null>(null);
const [isDataFetched, setIsDataFetched] = useState<boolean>(false); // Track if data has been fetched successfully
const [isDataFetched, setIsDataFetched] = useState<boolean>(false);
useEffect(() => {
const storedToken = localStorage.getItem("token");
@@ -46,11 +46,11 @@ export const App: React.FC = () => {
console.log("API Response:", userDataResponse);
setUserData(userDataResponse);
setError(null);
setIsDataFetched(true); // Set to true when data is successfully fetched
setIsDataFetched(true);
} catch (error) {
console.error("Error fetching data:", error);
setError((error as Error).message);
setIsDataFetched(false); // Set to false if there's an error fetching data
setIsDataFetched(false);
}
};
@@ -113,7 +113,7 @@ export const App: React.FC = () => {
displayValue = value;
}
} else if (typeof value === "object" && value !== null) {
displayValue = JSON.stringify(value, null, 2); // Pretty print JSON
displayValue = JSON.stringify(value, null, 2);
} else if (value === null) {
displayValue = "null";
} else if (
@@ -124,7 +124,7 @@ export const App: React.FC = () => {
} else if (typeof value === "undefined") {
displayValue = "undefined";
} else {
displayValue = value as string; // Fallback for any other types
displayValue = value as string;
}
return (
@@ -157,7 +157,7 @@ export const App: React.FC = () => {
const handleKeyPress = (event: React.KeyboardEvent<HTMLFormElement>) => {
if (event.key === "Enter") {
event.preventDefault(); // Prevent form submission
event.preventDefault();
fetchData().catch((error: unknown) =>
console.error("Fetch data error:", error),
);

View File

@@ -1,6 +1,7 @@
import React, { useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import "../App.css";
import { apiOrigin } from "../services/support";
import UpdateSubscription from "./UpdateSubscription"; // Import the UpdateSubscription component
interface SidebarProps {
token: string;
@@ -12,18 +13,36 @@ interface UserData {
ID: string;
};
}
interface ActionResponse {
success?: boolean;
message?: string;
}
export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
const [, /*userId*/ setUserId] = useState<string | null>(null);
const [userId, setUserId] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [message, setMessage] = useState<string | null>(null);
const [dropdownVisible, setDropdownVisible] = useState<boolean>(false);
const [showUpdateSubscription, setShowUpdateSubscription] =
useState<boolean>(false); // State to control UpdateSubscription popup
interface ApiResponse {
data: {
userId: string;
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}
}, []);
const handleClickOutside = (event: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(event.target as Node)
) {
setDropdownVisible(false);
}
};
const fetchData = async (): Promise<string | null> => {
if (!email || !token) {
@@ -32,9 +51,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
}
try {
const url = `${apiOrigin}/admin/user?email=${encodeURIComponent(
email,
)}&token=${encodeURIComponent(token)}`;
const url = `${apiOrigin}/admin/user?email=${encodeURIComponent(email)}&token=${encodeURIComponent(token)}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error("Network response was not ok");
@@ -70,9 +87,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
Closefamily: "/admin/user/close-family",
};
const url = `${apiOrigin}${actionUrls[action]}?id=${encodeURIComponent(
userId,
)}&token=${encodeURIComponent(token)}`;
const url = `${apiOrigin}${actionUrls[action]}?id=${encodeURIComponent(userId)}&token=${encodeURIComponent(token)}`;
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
@@ -85,7 +100,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
);
}
const result = (await response.json()) as ApiResponse;
const result = (await response.json()) as ActionResponse;
console.log("API Response:", result);
setMessage(`${action} completed successfully`);
@@ -109,8 +124,55 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
}
};
const deleteUser = async () => {
try {
const url = `${apiOrigin}/admin/user/delete?email=${encodeURIComponent(email)}&token=${encodeURIComponent(token)}`;
const response = await fetch(url, {
method: "DELETE",
});
if (!response.ok) {
throw new Error(
`Network response was not ok: ${response.status}`,
);
}
setMessage("Delete Account completed successfully");
setError(null);
setTimeout(() => {
setMessage(null);
}, 1000);
setDropdownVisible(false);
} catch (error) {
console.error(`Error deleting account:`, error);
setError(
error instanceof Error && typeof error.message === "string"
? error.message
: "An unexpected error occurred",
);
setTimeout(() => {
setError(null);
}, 1000);
setMessage(null);
}
};
const handleActionClick = async (action: string) => {
try {
if (action === "UpdateSubscription") {
const fetchedUserId = await fetchData();
if (fetchedUserId) {
setShowUpdateSubscription(true);
}
return;
}
if (action === "DeleteAccount") {
await deleteUser();
return;
}
const fetchedUserId = await fetchData();
if (!fetchedUserId) {
throw new Error("Incorrect email id or token");
@@ -140,6 +202,8 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
{ value: "Disable2FA", label: "Disable 2FA" },
{ value: "Closefamily", label: "Close Family" },
{ value: "DisablePasskeys", label: "Disable Passkeys" },
{ value: "DeleteAccount", label: "Delete Account" },
{ value: "UpdateSubscription", label: "Update Subscription" }, // New option added here
];
return (
@@ -149,7 +213,7 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
MORE
</button>
{dropdownVisible && (
<div className="dropdown-menu">
<div className="dropdown-menu" ref={dropdownRef}>
<ul>
{dropdownOptions.map((option) => (
<li key={option.value}>
@@ -178,6 +242,13 @@ export const Sidebar: React.FC<SidebarProps> = ({ token, email }) => {
{error ? `Error: ${error}` : `Success: ${message}`}
</div>
)}
{showUpdateSubscription && userId && (
<UpdateSubscription
token={token}
userId={userId}
onClose={() => setShowUpdateSubscription(false)}
/>
)}
</div>
);
};

View File

@@ -0,0 +1,178 @@
import React, { useEffect, useState } from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import "../App.css";
interface UpdateSubscriptionProps {
token: string;
userId: string;
onClose: () => void;
}
export const UpdateSubscription: React.FC<UpdateSubscriptionProps> = ({
token,
userId,
onClose,
}) => {
const [expiryTime, setExpiryTime] = useState<Date | null>(null);
const [productId, setProductId] = useState<string>("50gb_monthly");
const [paymentProvider, setPaymentProvider] = useState<string>("bitpay");
const [transactionId, setTransactionId] = useState<string>("");
const [message, setMessage] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [storage, setStorage] = useState<number | "">("");
useEffect(() => {
if (productId === "50gb_yearly" || productId === "50gb_monthly") {
setStorage(50 * 1024 * 1024 * 1024);
} else if (
productId === "200gb_yearly" ||
productId === "200gb_monthly"
) {
setStorage(200 * 1024 * 1024 * 1024);
} else if (
productId === "500gb_yearly" ||
productId === "500gb_monthly"
) {
setStorage(500 * 1024 * 1024 * 1024);
} else if (
productId === "2000gb_yearly" ||
productId === "2000gb_monthly"
) {
setStorage(2000 * 1024 * 1024 * 1024);
} else {
setStorage("");
}
}, [productId]);
const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
const expiryTimeTimestamp = expiryTime
? expiryTime.getTime() * 1000
: "";
const url = `http://localhost:8080/admin/user/subscription`;
const body = {
userId,
storage,
expiryTime: expiryTimeTimestamp,
productId,
paymentProvider,
transactionId,
};
try {
const response = await fetch(url, {
method: "PUT",
headers: {
"Content-Type": "application/json",
"X-AUTH-TOKEN": token,
},
body: JSON.stringify(body),
});
if (!response.ok) {
throw new Error(
`Network response was not ok: ${response.status}`,
);
}
setMessage("Subscription updated successfully");
setError(null);
setTimeout(() => {
setMessage(null);
onClose();
}, 1000);
} catch (error) {
console.error("Error updating subscription:", error);
setError(
error instanceof Error && typeof error.message === "string"
? error.message
: "An unexpected error occurred",
);
setTimeout(() => {
setError(null);
}, 1000);
}
};
const handleSubmitWrapper = (event: React.FormEvent) => {
handleSubmit(event).catch((error: unknown) => {
console.error("Error in handleSubmit:", error);
});
};
return (
<div className="update-subscription-popup">
<div className="popup-content">
<button className="close-button" onClick={onClose}>
X
</button>
<h2>Update Subscription</h2>
<form onSubmit={handleSubmitWrapper}>
<div className="form-group">
<label htmlFor="expiry-time">Expiry Time:</label>
<DatePicker
id="expiry-time"
selected={expiryTime}
onChange={(date) => setExpiryTime(date)}
dateFormat="dd/MM/yyyy"
showYearDropdown
scrollableYearDropdown
yearDropdownItemNumber={15}
/>
</div>
<div className="form-group">
<label htmlFor="product-id">Choose Your Plan:</label>
<select
id="product-id"
value={productId}
onChange={(e) => setProductId(e.target.value)}
>
<option value="50gb_monthly">50GB/Month</option>
<option value="50gb_yearly">50GB/Year</option>
<option value="200gb_monthly">200GB/Month</option>
<option value="200gb_yearly">200GB/Year</option>
<option value="500gb_monthly">500GB/Month</option>
<option value="500gb_yearly">500GB/Year</option>
<option value="2000gb_monthly">2000GB/Month</option>
<option value="2000gb_yearly">2000GB/Year</option>
</select>
</div>
<div className="form-group">
<label htmlFor="payment-provider">
Payment Provider:
</label>
<select
id="payment-provider"
value={paymentProvider}
onChange={(e) => setPaymentProvider(e.target.value)}
>
<option value="bitpay">BitPay</option>
<option value="paypal">PayPal</option>
</select>
</div>
<div className="form-group">
<label htmlFor="transaction-id">Transaction ID:</label>
<input
id="transaction-id"
type="text"
value={transactionId}
onChange={(e) => setTransactionId(e.target.value)}
/>
</div>
<button type="submit" id="submitbtn">
Update
</button>
</form>
{(error ?? message) && (
<div className={`message ${error ? "error" : "success"}`}>
{error ? `Error: ${error}` : `Success: ${message}`}
</div>
)}
</div>
</div>
);
};
export default UpdateSubscription;

View File

@@ -23,7 +23,7 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz"
integrity sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.24.5":
"@babel/core@^7.24.5":
version "7.24.6"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.6.tgz"
integrity sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==
@@ -208,11 +208,121 @@
"@babel/helper-validator-identifier" "^7.24.6"
to-fast-properties "^2.0.0"
"@esbuild/aix-ppc64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537"
integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==
"@esbuild/android-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9"
integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==
"@esbuild/android-arm@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995"
integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==
"@esbuild/android-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98"
integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==
"@esbuild/darwin-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb"
integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==
"@esbuild/darwin-x64@0.20.2":
version "0.20.2"
resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz"
integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==
"@esbuild/freebsd-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911"
integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==
"@esbuild/freebsd-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c"
integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==
"@esbuild/linux-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5"
integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==
"@esbuild/linux-arm@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c"
integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==
"@esbuild/linux-ia32@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa"
integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==
"@esbuild/linux-loong64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5"
integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==
"@esbuild/linux-mips64el@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa"
integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==
"@esbuild/linux-ppc64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20"
integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==
"@esbuild/linux-riscv64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300"
integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==
"@esbuild/linux-s390x@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685"
integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==
"@esbuild/linux-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff"
integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==
"@esbuild/netbsd-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6"
integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==
"@esbuild/openbsd-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf"
integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==
"@esbuild/sunos-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f"
integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==
"@esbuild/win32-arm64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90"
integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==
"@esbuild/win32-ia32@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23"
integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==
"@esbuild/win32-x64@0.20.2":
version "0.20.2"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc"
integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
version "4.4.0"
resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz"
@@ -245,6 +355,42 @@
resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz"
integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==
"@floating-ui/core@^1.0.0":
version "1.6.2"
resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.2.tgz"
integrity sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==
dependencies:
"@floating-ui/utils" "^0.2.0"
"@floating-ui/dom@^1.0.0":
version "1.6.5"
resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz"
integrity sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==
dependencies:
"@floating-ui/core" "^1.0.0"
"@floating-ui/utils" "^0.2.0"
"@floating-ui/react-dom@^2.1.0":
version "2.1.0"
resolved "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.0.tgz"
integrity sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==
dependencies:
"@floating-ui/dom" "^1.0.0"
"@floating-ui/react@^0.26.2":
version "0.26.17"
resolved "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.17.tgz"
integrity sha512-ESD+jYWwqwVzaIgIhExrArdsCL1rOAzryG/Sjlu8yaD3Mtqi3uVyhbE2V7jD58Mo52qbzKz2eUY/Xgh5I86FCQ==
dependencies:
"@floating-ui/react-dom" "^2.1.0"
"@floating-ui/utils" "^0.2.0"
tabbable "^6.0.0"
"@floating-ui/utils@^0.2.0":
version "0.2.2"
resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz"
integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
"@humanwhocodes/config-array@^0.11.14":
version "0.11.14"
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz"
@@ -304,7 +450,7 @@
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
version "2.0.5"
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
@@ -322,11 +468,107 @@
resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz"
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
"@rollup/plugin-node-resolve@^15.2.3":
version "15.2.3"
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz#e5e0b059bd85ca57489492f295ce88c2d4b0daf9"
integrity sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==
dependencies:
"@rollup/pluginutils" "^5.0.1"
"@types/resolve" "1.20.2"
deepmerge "^4.2.2"
is-builtin-module "^3.2.1"
is-module "^1.0.0"
resolve "^1.22.1"
"@rollup/pluginutils@^5.0.1":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0"
integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==
dependencies:
"@types/estree" "^1.0.0"
estree-walker "^2.0.2"
picomatch "^2.3.1"
"@rollup/rollup-android-arm-eabi@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz#bbd0e616b2078cd2d68afc9824d1fadb2f2ffd27"
integrity sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==
"@rollup/rollup-android-arm64@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz#97255ef6384c5f73f4800c0de91f5f6518e21203"
integrity sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==
"@rollup/rollup-darwin-arm64@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz#b6dd74e117510dfe94541646067b0545b42ff096"
integrity sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==
"@rollup/rollup-darwin-x64@4.18.0":
version "4.18.0"
resolved "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz"
integrity sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==
"@rollup/rollup-linux-arm-gnueabihf@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz#9f1a6d218b560c9d75185af4b8bb42f9f24736b8"
integrity sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==
"@rollup/rollup-linux-arm-musleabihf@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz#53618b92e6ffb642c7b620e6e528446511330549"
integrity sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==
"@rollup/rollup-linux-arm64-gnu@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz#99a7ba5e719d4f053761a698f7b52291cefba577"
integrity sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==
"@rollup/rollup-linux-arm64-musl@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz#f53db99a45d9bc00ce94db8a35efa7c3c144a58c"
integrity sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==
"@rollup/rollup-linux-powerpc64le-gnu@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz#cbb0837408fe081ce3435cf3730e090febafc9bf"
integrity sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==
"@rollup/rollup-linux-riscv64-gnu@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz#8ed09c1d1262ada4c38d791a28ae0fea28b80cc9"
integrity sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==
"@rollup/rollup-linux-s390x-gnu@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz#938138d3c8e0c96f022252a28441dcfb17afd7ec"
integrity sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==
"@rollup/rollup-linux-x64-gnu@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz#1a7481137a54740bee1ded4ae5752450f155d942"
integrity sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==
"@rollup/rollup-linux-x64-musl@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz#f1186afc601ac4f4fc25fac4ca15ecbee3a1874d"
integrity sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==
"@rollup/rollup-win32-arm64-msvc@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz#ed6603e93636a96203c6915be4117245c1bd2daf"
integrity sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==
"@rollup/rollup-win32-ia32-msvc@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz#14e0b404b1c25ebe6157a15edb9c46959ba74c54"
integrity sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==
"@rollup/rollup-win32-x64-msvc@4.18.0":
version "4.18.0"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz#5d694d345ce36b6ecf657349e03eb87297e68da4"
integrity sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==
"@types/babel__core@^7.20.5":
version "7.20.5"
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
@@ -360,7 +602,7 @@
dependencies:
"@babel/types" "^7.20.7"
"@types/estree@1.0.5":
"@types/estree@1.0.5", "@types/estree@^1.0.0":
version "1.0.5"
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz"
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
@@ -385,6 +627,11 @@
"@types/prop-types" "*"
csstype "^3.0.2"
"@types/resolve@1.20.2":
version "1.20.2"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.2.tgz#97d26e00cd4a0423b4af620abecf3e6f442b7975"
integrity sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==
"@typescript-eslint/eslint-plugin@^7":
version "7.11.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz"
@@ -400,7 +647,7 @@
natural-compare "^1.4.0"
ts-api-utils "^1.3.0"
"@typescript-eslint/parser@^7", "@typescript-eslint/parser@^7.0.0":
"@typescript-eslint/parser@^7":
version "7.11.0"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz"
integrity sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==
@@ -487,7 +734,7 @@ acorn-jsx@^5.3.2:
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0:
acorn@^8.9.0:
version "8.11.3"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz"
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
@@ -652,7 +899,7 @@ braces@^3.0.3:
dependencies:
fill-range "^7.1.1"
browserslist@^4.22.2, "browserslist@>= 4.21.0":
browserslist@^4.22.2:
version "4.23.0"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz"
integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==
@@ -662,6 +909,11 @@ browserslist@^4.22.2, "browserslist@>= 4.21.0":
node-releases "^2.0.14"
update-browserslist-db "^1.0.13"
builtin-modules@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7:
version "1.0.7"
resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz"
@@ -719,16 +971,16 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
@@ -780,6 +1032,11 @@ data-view-byte-offset@^1.0.0:
es-errors "^1.3.0"
is-data-view "^1.0.1"
date-fns@^3.3.1, date-fns@^3.6.0:
version "3.6.0"
resolved "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz"
integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==
debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
version "4.3.5"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz"
@@ -792,6 +1049,11 @@ deep-is@^0.1.3:
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
deepmerge@^4.2.2:
version "4.3.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
define-data-property@^1.0.1, define-data-property@^1.1.4:
version "1.1.4"
resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz"
@@ -1053,7 +1315,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
"eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^8, eslint@^8.56.0, eslint@>=7:
eslint@^8:
version "8.57.0"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz"
integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==
@@ -1125,6 +1387,11 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
estree-walker@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
@@ -1468,6 +1735,13 @@ is-boolean-object@^1.1.0:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
is-builtin-module@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169"
integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==
dependencies:
builtin-modules "^3.3.0"
is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
version "1.2.7"
resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz"
@@ -1525,6 +1799,11 @@ is-map@^2.0.3:
resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz"
integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==
is-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
is-negative-zero@^2.0.3:
version "2.0.3"
resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz"
@@ -1735,21 +2014,7 @@ micromatch@^4.0.4:
braces "^3.0.3"
picomatch "^2.3.1"
minimatch@^3.0.5:
version "3.1.2"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimatch@^3.1.1:
version "3.1.2"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
minimatch@^3.1.2:
minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
@@ -1952,12 +2217,12 @@ prettier-plugin-packagejson@^2.5:
sort-package-json "2.10.0"
synckit "0.9.0"
prettier@^3, "prettier@>= 1.16.0", prettier@>=2.0:
prettier@^3:
version "3.3.0"
resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz"
integrity sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==
prop-types@^15.8.1:
prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -1976,7 +2241,18 @@ queue-microtask@^1.2.2:
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
react-dom@^18, react-dom@>=18:
react-datepicker@^7.1.0:
version "7.1.0"
resolved "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.1.0.tgz"
integrity sha512-Z91n5ybhmzI+YChj1ZG7ntPPOmHR2Dh4jbIl+mNgKXKoxyzUQBh7M3eQaFOwrBCVdKy5vsj370/ocQlGu1qsGA==
dependencies:
"@floating-ui/react" "^0.26.2"
clsx "^2.1.0"
date-fns "^3.3.1"
prop-types "^15.7.2"
react-onclickoutside "^6.13.0"
react-dom@^18:
version "18.3.1"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz"
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
@@ -1989,6 +2265,11 @@ react-is@^16.13.1:
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-onclickoutside@^6.13.0:
version "6.13.1"
resolved "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.1.tgz"
integrity sha512-LdrrxK/Yh9zbBQdFbMTXPp3dTSN9B+9YJQucdDu3JNKRrbdU+H+/TVONJoWtOwy4II8Sqf1y/DTI6w/vGPYW0w==
react-refresh@^0.14.2:
version "0.14.2"
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz"
@@ -2001,7 +2282,7 @@ react-toastify@^10.0.5:
dependencies:
clsx "^2.1.0"
react@^18, react@^18.3.1, react@>=18:
react@^18:
version "18.3.1"
resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz"
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
@@ -2036,6 +2317,15 @@ resolve-from@^4.0.0:
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
resolve@^1.22.1:
version "1.22.8"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
dependencies:
is-core-module "^2.13.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
resolve@^2.0.0-next.5:
version "2.0.0-next.5"
resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz"
@@ -2288,6 +2578,11 @@ synckit@0.9.0:
"@pkgr/core" "^0.1.0"
tslib "^2.6.2"
tabbable@^6.0.0:
version "6.2.0"
resolved "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz"
integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
@@ -2371,7 +2666,7 @@ typed-array-length@^1.0.6:
is-typed-array "^1.1.13"
possible-typed-array-names "^1.0.0"
typescript@^5.4.5, typescript@>=2.9, typescript@>=4.2.0:
typescript@^5:
version "5.4.5"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz"
integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==
@@ -2401,7 +2696,7 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
"vite@^4.2.0 || ^5.0.0", vite@^5.2:
vite@^5.2:
version "5.2.12"
resolved "https://registry.npmjs.org/vite/-/vite-5.2.12.tgz"
integrity sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==

View File

@@ -3,24 +3,26 @@
Source code for our
[Cloudflare Workers](https://developers.cloudflare.com/workers/).
Each worker is a self contained directory with its each `package.json`.
Workers are organized as Yarn workspaces sharing a common `package.json` and
base `tsconfig`. They can however be deployed individually.
## Deploying
- Switch to a worker directory, e.g. `cd github-discord-notifier`.
Install dependencies with `yarn`.
- Install dependencies (if needed) with `yarn`
> If you have previously deployed, then you will have an old `yarn.lock`. In
> this case it is safe to delete and recreate using `rm yarn.lock && yarn`.
> If you have previously deployed, then you will have an old `yarn.lock`. In
> this case it is safe to delete and recreate using `rm yarn.lock && yarn`.
Then, to deploy an individual worker
- Login into wrangler (if needed) using `yarn wrangler login`
- Login into wrangler (if needed) using
`yarn workspace health-check wrangler login`
- Deploy! `yarn wrangler deploy`
- Deploy! `yarn workspace health-check wrangler deploy`
Wrangler is the CLI provided by Cloudflare to manage workers. Apart from
deploying, it also allows us to stream logs from running workers by using
`yarn wrangler tail`.
`yarn workspace <worker-name> wrangler tail`.
## Creating a new worker

View File

@@ -1,10 +1,5 @@
{
"name": "cast-albums",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
"version": "0.0.0",
"private": true
}

View File

@@ -1,10 +1,5 @@
{
"name": "files",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
"version": "0.0.0",
"private": true
}

View File

@@ -1,10 +1,5 @@
{
"name": "github-discord-notifier",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
"version": "0.0.0",
"private": true
}

View File

@@ -1,10 +1,5 @@
{
"name": "health-check",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
"version": "0.0.0",
"private": true
}

View File

@@ -0,0 +1,13 @@
{
"name": "workers",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"workspaces": [
"*"
],
"packageManager": "yarn@1.22.22"
}

View File

@@ -1,10 +1,5 @@
{
"name": "public-albums",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
"version": "0.0.0",
"private": true
}

View File

@@ -1,10 +1,5 @@
{
"name": "files",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
"name": "sentry-reporter",
"version": "0.0.0",
"private": true
}

View File

@@ -1,10 +1,5 @@
{
"name": "tail",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
"version": "0.0.0",
"private": true
}

View File

@@ -1,10 +1,5 @@
{
"name": "thumbnails",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
"version": "0.0.0",
"private": true
}

View File

@@ -1,10 +1,5 @@
{
"name": "uploader",
"private": true,
"devDependencies": {
"@cloudflare/workers-types": "^4.20240614.0",
"typescript": "^5",
"wrangler": "^3"
},
"packageManager": "yarn@1.22.22"
"version": "0.0.0",
"private": true
}

View File

@@ -35,9 +35,9 @@ PODS:
- FirebaseCoreInternal (~> 10.0)
- GoogleUtilities/Environment (~> 7.12)
- GoogleUtilities/Logger (~> 7.12)
- FirebaseCoreInternal (10.24.0):
- FirebaseCoreInternal (10.28.0):
- "GoogleUtilities/NSData+zlib (~> 7.8)"
- FirebaseInstallations (10.24.0):
- FirebaseInstallations (10.28.0):
- FirebaseCore (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
@@ -83,29 +83,29 @@ PODS:
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30911.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/AppDelegateSwizzler (7.13.0):
- GoogleUtilities/AppDelegateSwizzler (7.13.3):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Privacy
- GoogleUtilities/Environment (7.13.0):
- GoogleUtilities/Environment (7.13.3):
- GoogleUtilities/Privacy
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.13.0):
- GoogleUtilities/Logger (7.13.3):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- GoogleUtilities/Network (7.13.0):
- GoogleUtilities/Network (7.13.3):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Privacy
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.13.0)":
- "GoogleUtilities/NSData+zlib (7.13.3)":
- GoogleUtilities/Privacy
- GoogleUtilities/Privacy (7.13.0)
- GoogleUtilities/Reachability (7.13.0):
- GoogleUtilities/Privacy (7.13.3)
- GoogleUtilities/Reachability (7.13.3):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GoogleUtilities/UserDefaults (7.13.0):
- GoogleUtilities/UserDefaults (7.13.3):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- home_widget (0.0.1):
@@ -157,12 +157,12 @@ PODS:
- nanopb/encode (2.30910.0)
- onnxruntime (0.0.1):
- Flutter
- onnxruntime-objc (= 1.15.1)
- onnxruntime-c (1.15.1)
- onnxruntime-objc (1.15.1):
- onnxruntime-objc/Core (= 1.15.1)
- onnxruntime-objc/Core (1.15.1):
- onnxruntime-c (= 1.15.1)
- onnxruntime-objc (= 1.18.0)
- onnxruntime-c (1.18.0)
- onnxruntime-objc (1.18.0):
- onnxruntime-objc/Core (= 1.18.0)
- onnxruntime-objc/Core (1.18.0):
- onnxruntime-c (= 1.18.0)
- open_mail_app (0.0.1):
- Flutter
- OrderedSet (5.0.0)
@@ -181,9 +181,9 @@ PODS:
- Flutter
- screen_brightness_ios (0.1.0):
- Flutter
- SDWebImage (5.19.1):
- SDWebImage/Core (= 5.19.1)
- SDWebImage/Core (5.19.1)
- SDWebImage (5.19.2):
- SDWebImage/Core (= 5.19.2)
- SDWebImage/Core (5.19.2)
- SDWebImageWebPCoder (0.14.6):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.17)
@@ -427,8 +427,8 @@ SPEC CHECKSUMS:
firebase_core: 66b99b4fb4e5d7cc4e88d4c195fe986681f3466a
firebase_messaging: 0eb0425d28b4f4af147cdd4adcaf7c0100df28ed
FirebaseCore: 11dc8a16dfb7c5e3c3f45ba0e191a33ac4f50894
FirebaseCoreInternal: bcb5acffd4ea05e12a783ecf835f2210ce3dc6af
FirebaseInstallations: 8f581fca6478a50705d2bd2abd66d306e0f5736e
FirebaseCoreInternal: 58d07f1362fddeb0feb6a857d1d1d1c5e558e698
FirebaseInstallations: 60c1d3bc1beef809fd1ad1189a8057a040c59f2e
FirebaseMessaging: 4d52717dd820707cc4eadec5eb981b4832ec8d5d
fk_user_agent: 1f47ec39291e8372b1d692b50084b0d54103c545
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
@@ -441,7 +441,7 @@ SPEC CHECKSUMS:
flutter_sodium: c84426b4de738514b5b66cfdeb8a06634e72fe0b
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
@@ -458,9 +458,9 @@ SPEC CHECKSUMS:
motionphoto: d4a432b8c8f22fb3ad966258597c0103c9c5ff16
move_to_background: 39a5b79b26d577b0372cbe8a8c55e7aa9fcd3a2d
nanopb: 438bc412db1928dac798aa6fd75726007be04262
onnxruntime: e9346181d75b8dea8733bdae512a22c298962e00
onnxruntime-c: ebdcfd8650bcbd10121c125262f99dea681b92a3
onnxruntime-objc: ae7acec7a3d03eaf072d340afed7a35635c1c2a6
onnxruntime: e7c2ae44385191eaad5ae64c935a72debaddc997
onnxruntime-c: a909204639a1f035f575127ac406f781ac797c9c
onnxruntime-objc: b6fab0f1787aa6f7190c2013f03037df4718bd8b
open_mail_app: 794172f6a22cd16319d3ddaf45e945b2f74952b0
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
@@ -470,7 +470,7 @@ SPEC CHECKSUMS:
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
receive_sharing_intent: 6837b01768e567fe8562182397bf43d63d8c6437
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb
SDWebImage: dfe95b2466a9823cf9f0c6d01217c06550d7b29a
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
Sentry: ebc12276bd17613a114ab359074096b6b3725203
sentry_flutter: 88ebea3f595b0bc16acc5bedacafe6d60c12dcd5

View File

@@ -5,6 +5,7 @@ import 'dart:collection';
import 'dart:core';
import 'dart:io';
import "package:dio/dio.dart";
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http;
@@ -14,7 +15,9 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:photos/core/error-reporting/tunneled_transport.dart';
import "package:photos/core/errors.dart";
import 'package:photos/models/typedefs.dart';
import "package:photos/services/machine_learning/face_ml/face_ml_exceptions.dart";
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:shared_preferences/shared_preferences.dart';
@@ -230,12 +233,25 @@ class SuperLogging {
StackTrace? stack,
) async {
try {
if (error is DioError) {
return;
}
if (error is CouldNotRetrieveAnyFileData ||
error is StorageLimitExceededError ||
error is WiFiUnavailableError ||
error is InvalidFileError ||
error is NoActiveSubscriptionError) {
if (kDebugMode) {
$.info('Not sending error to sentry: $error');
}
return;
}
await Sentry.captureException(
error,
stackTrace: stack,
);
} catch (e) {
$.info('Sending report to sentry.io failed: $e');
$.info('Sending report to sentry failed: $e');
$.info('Original error: $error');
}
}

View File

@@ -123,7 +123,9 @@ class EmbeddingsDB {
List<Embedding> _convertToEmbeddings(List<Map<String, dynamic>> results) {
final List<Embedding> embeddings = [];
for (final result in results) {
embeddings.add(_getEmbeddingFromRow(result));
final embedding = _getEmbeddingFromRow(result);
if (embedding.isEmpty) continue;
embeddings.add(embedding);
}
return embeddings;
}

View File

@@ -1808,6 +1808,9 @@ class FilesDB {
}
Future<List<EnteFile>> getUploadedFiles(List<int> uploadedIDs) async {
if (uploadedIDs.isEmpty) {
return <EnteFile>[];
}
final db = await instance.sqliteAsyncDB;
String inParam = "";
for (final id in uploadedIDs) {

View File

@@ -19,4 +19,5 @@ class PeopleChangedEvent extends Event {
enum PeopleEventType {
defaultType,
removedFilesFromCluster,
syncDone,
}

View File

@@ -333,7 +333,7 @@ Future<void> _sync(String caller) async {
await SyncService.instance.sync();
} catch (e, s) {
if (!isHandledSyncError(e)) {
_logger.severe("Sync error", e, s);
_logger.warning("Sync error", e, s);
}
}
}

View File

@@ -6,6 +6,8 @@ class Embedding {
final List<double> embedding;
int? updationTime;
bool get isEmpty => embedding.isEmpty;
Embedding({
required this.fileID,
required this.model,
@@ -13,6 +15,14 @@ class Embedding {
this.updationTime,
});
factory Embedding.empty(int fileID, Model model) {
return Embedding(
fileID: fileID,
model: model,
embedding: <double>[],
);
}
static List<double> decodeEmbedding(String embedding) {
return List<double>.from(jsonDecode(embedding) as List);
}

View File

@@ -729,7 +729,7 @@ class CollectionsService {
collection.setName(newName);
sync().ignore();
} catch (e, s) {
_logger.severe("failed to rename collection", e, s);
_logger.warning("failed to rename collection", e, s);
rethrow;
}
}

View File

@@ -194,6 +194,7 @@ class FaceMlService {
void _listenOnPeopleChangedSync() {
Bus.instance.on<PeopleChangedEvent>().listen((event) {
if (event.type == PeopleEventType.syncDone) return;
_shouldSyncPeople = true;
});
}
@@ -367,7 +368,7 @@ class FaceMlService {
_isSyncing = true;
if (forceSync) {
await PersonService.instance.reconcileClusters();
Bus.instance.fire(PeopleChangedEvent());
Bus.instance.fire(PeopleChangedEvent(type: PeopleEventType.syncDone));
_shouldSyncPeople = false;
}
_isSyncing = false;
@@ -924,7 +925,7 @@ class FaceMlService {
await _getImagePathForML(enteFile, typeOfData: FileDataForML.fileData);
if (filePath == null) {
_logger.severe(
_logger.warning(
"Failed to get any data for enteFile with uploadedFileID ${enteFile.uploadedFileID} since its file path is null",
);
throw CouldNotRetrieveAnyFileData();

View File

@@ -139,6 +139,7 @@ class ClusterFeedbackService {
PersonEntity p,
) async {
try {
_logger.info('removeFilesFromPerson called');
// Get the relevant faces to be removed
final faceIDs = await FaceMLDataDB.instance
.getFaceIDsForPerson(p.remoteID)
@@ -150,6 +151,13 @@ class ClusterFeedbackService {
final embeddings =
await FaceMLDataDB.instance.getFaceEmbeddingMapForFaces(faceIDs);
if (faceIDs.isEmpty || embeddings.isEmpty) {
_logger.severe(
'No faces or embeddings found for person ${p.remoteID} that match the given files',
);
return;
}
final fileIDToCreationTime =
await FilesDB.instance.getFileIDToCreationTime();
@@ -161,7 +169,7 @@ class ClusterFeedbackService {
distanceThreshold: 0.20,
);
if (clusterResult.isEmpty) {
_logger.warning('No clusters found or something went wrong');
_logger.severe('No clusters found or something went wrong');
return;
}
final newFaceIdToClusterID = clusterResult.newFaceIdToCluster;
@@ -179,7 +187,12 @@ class ClusterFeedbackService {
await FaceMLDataDB.instance
.bulkCaptureNotPersonFeedback(notClusterIdToPersonId);
// Update remote so new sync does not undo this change
await PersonService.instance
.removeFilesFromPerson(person: p, faceIDs: faceIDs.toSet());
Bus.instance.fire(PeopleChangedEvent());
_logger.info('removeFilesFromPerson done');
return;
} catch (e, s) {
_logger.severe("Error in removeFilesFromPerson", e, s);
@@ -191,6 +204,7 @@ class ClusterFeedbackService {
List<EnteFile> files,
int clusterID,
) async {
_logger.info('removeFilesFromCluster called');
try {
// Get the relevant faces to be removed
final faceIDs = await FaceMLDataDB.instance
@@ -203,6 +217,13 @@ class ClusterFeedbackService {
final embeddings =
await FaceMLDataDB.instance.getFaceEmbeddingMapForFaces(faceIDs);
if (faceIDs.isEmpty || embeddings.isEmpty) {
_logger.severe(
'No faces or embeddings found for cluster $clusterID that match the given files',
);
return;
}
final fileIDToCreationTime =
await FilesDB.instance.getFileIDToCreationTime();
@@ -214,6 +235,7 @@ class ClusterFeedbackService {
distanceThreshold: 0.20,
);
if (clusterResult.isEmpty) {
_logger.severe('No clusters found or something went wrong');
return;
}
final newFaceIdToClusterID = clusterResult.newFaceIdToCluster;
@@ -230,13 +252,7 @@ class ClusterFeedbackService {
source: "$clusterID",
),
);
// Bus.instance.fire(
// LocalPhotosUpdatedEvent(
// files,
// type: EventType.peopleClusterChanged,
// source: "$clusterID",
// ),
// );
_logger.info('removeFilesFromCluster done');
return;
} catch (e, s) {
_logger.severe("Error in removeFilesFromCluster", e, s);
@@ -673,7 +689,7 @@ class ClusterFeedbackService {
.map((clusterID) => allClusterIdsToCountMap[clusterID] ?? 0)
.reduce((value, element) => min(value, element));
final checkSizes = [100, 20, kMinimumClusterSizeSearchResult, 10, 5, 1];
late Map<int, Vector> clusterAvgBigClusters;
Map<int, Vector> clusterAvgBigClusters = <int, Vector>{};
final List<(int, double)> suggestionsMean = [];
for (final minimumSize in checkSizes.toSet()) {
if (smallestPersonClusterSize >=

View File

@@ -201,6 +201,38 @@ class PersonService {
personData.logStats();
}
Future<void> removeFilesFromPerson({
required PersonEntity person,
required Set<String> faceIDs,
}) async {
final personData = person.data;
final List<int> emptiedClusters = [];
for (final cluster in personData.assigned!) {
cluster.faces.removeWhere((faceID) => faceIDs.contains(faceID));
if (cluster.faces.isEmpty) {
emptiedClusters.add(cluster.id);
}
}
// Safety check to make sure we haven't created an empty cluster now, if so delete it
for (final emptyClusterID in emptiedClusters) {
personData.assigned!
.removeWhere((element) => element.id != emptyClusterID);
await faceMLDataDB.removeClusterToPerson(
personID: person.remoteID,
clusterID: emptyClusterID,
);
}
await entityService.addOrUpdate(
EntityType.person,
json.encode(personData.toJson()),
id: person.remoteID,
);
personData.logStats();
}
Future<void> deletePerson(String personID, {bool onlyMapping = false}) async {
if (onlyMapping) {
final PersonEntity? entity = await getPerson(personID);

View File

@@ -3,6 +3,7 @@ import "dart:collection";
import "dart:math" show min;
import "package:computer/computer.dart";
import "package:flutter/services.dart";
import "package:logging/logging.dart";
import "package:photos/core/cache/lru_map.dart";
import "package:photos/core/configuration.dart";
@@ -204,6 +205,9 @@ class SemanticSearchService {
await _frameworkInitialization.future;
_logger.info("Attempting backfill for image embeddings");
final fileIDs = await _getFileIDsToBeIndexed();
if (fileIDs.isEmpty) {
return;
}
final files = await FilesDB.instance.getUploadedFiles(fileIDs);
_logger.info(files.length.toString() + " to be embedded");
// await _cacheThumbnails(files);
@@ -211,20 +215,6 @@ class SemanticSearchService {
unawaited(_pollQueue());
}
Future<void> _cacheThumbnails(List<EnteFile> files) async {
int counter = 0;
const batchSize = 100;
for (var i = 0; i < files.length;) {
final futures = <Future>[];
for (var j = 0; j < batchSize && i < files.length; j++, i++) {
futures.add(getThumbnail(files[i]));
}
await Future.wait(futures);
counter += futures.length;
_logger.info("$counter/${files.length} thumbnails cached");
}
}
Future<List<int>> _getFileIDsToBeIndexed() async {
final uploadedFileIDs = await getIndexableFileIDs();
final embeddedFileIDs =
@@ -387,6 +377,21 @@ class SemanticSearchService {
file,
embedding,
);
} on FormatException catch (e, _) {
_logger.severe(
"Could not get embedding for $file because FormatException occured, storing empty result locally",
e,
);
final embedding = Embedding.empty(file.uploadedFileID!, _currentModel);
await EmbeddingsDB.instance.put(embedding);
} on PlatformException catch (e, s) {
_logger.severe(
"Could not get thumbnail for $file due to PlatformException related to thumbnails, storing empty result locally",
e,
s,
);
final embedding = Embedding.empty(file.uploadedFileID!, _currentModel);
await EmbeddingsDB.instance.put(embedding);
} catch (e, s) {
_logger.severe(e, s);
}

View File

@@ -276,7 +276,7 @@ class UserService {
throw Exception("delete action failed");
}
} catch (e) {
_logger.severe(e);
_logger.warning(e);
await showGenericErrorDialog(context: context, error: e);
return null;
}
@@ -304,7 +304,7 @@ class UserService {
throw Exception("delete action failed");
}
} catch (e) {
_logger.severe(e);
_logger.warning(e);
rethrow;
}
}
@@ -329,7 +329,7 @@ class UserService {
}
rethrow;
} catch (e, s) {
_logger.severe("unexpected error", e, s);
_logger.warning("unexpected error", e, s);
rethrow;
}
}
@@ -366,7 +366,7 @@ class UserService {
Bus.instance.fire(AccountConfiguredEvent());
}
} catch (e) {
_logger.severe(e);
_logger.warning(e);
await dialog.hide();
await showGenericErrorDialog(context: context, error: e);
}
@@ -448,7 +448,7 @@ class UserService {
}
} catch (e) {
await dialog.hide();
_logger.severe(e);
_logger.warning(e);
// ignore: unawaited_futures
showErrorDialog(
context,
@@ -519,7 +519,7 @@ class UserService {
}
} catch (e) {
await dialog.hide();
_logger.severe(e);
_logger.warning(e);
// ignore: unawaited_futures
showErrorDialog(
context,

View File

@@ -13,6 +13,7 @@ import 'package:photos/services/collections_service.dart';
import "package:photos/services/filter/db_filters.dart";
import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart';
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
class HomeGalleryWidget extends StatelessWidget {
final Widget? header;
@@ -84,13 +85,15 @@ class HomeGalleryWidget extends StatelessWidget {
reloadDebounceTime: const Duration(seconds: 2),
reloadDebounceExecutionInterval: const Duration(seconds: 5),
);
return Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(GalleryType.homepage, selectedFiles),
],
return SelectionState(
selectedFiles: selectedFiles,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(GalleryType.homepage, selectedFiles),
],
),
);
// return gallery;
}
}

View File

@@ -15,6 +15,7 @@ import "package:photos/theme/ente_theme.dart";
import "package:photos/ui/common/loading_widget.dart";
import "package:photos/ui/viewer/actions/file_selection_overlay_bar.dart";
import "package:photos/ui/viewer/gallery/gallery.dart";
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
class MapPullUpGallery extends StatefulWidget {
final StreamController<List<EnteFile>> visibleImages;
@@ -48,33 +49,37 @@ class _MapPullUpGalleryState extends State<MapPullUpGallery> {
Widget? cachedScrollableContent;
return DeferredPointerHandler(
child: Stack(
alignment: Alignment.bottomCenter,
clipBehavior: Clip.none,
children: [
DraggableScrollableSheet(
expand: false,
initialChildSize: initialChildSize,
minChildSize: initialChildSize,
maxChildSize: 0.8,
snap: true,
snapSizes: const [0.5],
builder: (context, scrollController) {
//Must use cached widget here to avoid rebuilds when DraggableScrollableSheet
//is snapped to it's initialChildSize
cachedScrollableContent ??=
cacheScrollableContent(scrollController, context, logger);
return cachedScrollableContent!;
},
),
DeferPointer(
child: FileSelectionOverlayBar(
GalleryType.searchResults,
_selectedFiles,
backgroundColor: getEnteColorScheme(context).backgroundElevated2,
child: SelectionState(
selectedFiles: _selectedFiles,
child: Stack(
alignment: Alignment.bottomCenter,
clipBehavior: Clip.none,
children: [
DraggableScrollableSheet(
expand: false,
initialChildSize: initialChildSize,
minChildSize: initialChildSize,
maxChildSize: 0.8,
snap: true,
snapSizes: const [0.5],
builder: (context, scrollController) {
//Must use cached widget here to avoid rebuilds when DraggableScrollableSheet
//is snapped to it's initialChildSize
cachedScrollableContent ??=
cacheScrollableContent(scrollController, context, logger);
return cachedScrollableContent!;
},
),
),
],
DeferPointer(
child: FileSelectionOverlayBar(
GalleryType.searchResults,
_selectedFiles,
backgroundColor:
getEnteColorScheme(context).backgroundElevated2,
),
),
],
),
),
);
}

View File

@@ -695,7 +695,6 @@ class _FileSelectionActionsWidgetState
widget.person!,
);
}
Bus.instance.fire(PeopleChangedEvent());
}
widget.selectedFiles.clearAll();
if (mounted) {
@@ -738,7 +737,6 @@ class _FileSelectionActionsWidgetState
widget.clusterID!,
);
}
Bus.instance.fire(PeopleChangedEvent());
}
widget.selectedFiles.clearAll();
if (mounted) {

View File

@@ -3,8 +3,11 @@ import "package:photos/face/model/person.dart";
import 'package:photos/models/collection/collection.dart';
import 'package:photos/models/gallery_type.dart';
import 'package:photos/models/selected_files.dart';
import "package:photos/service_locator.dart";
import "package:photos/theme/effects.dart";
import "package:photos/theme/ente_theme.dart";
import 'package:photos/ui/components/bottom_action_bar/bottom_action_bar_widget.dart';
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
class FileSelectionOverlayBar extends StatefulWidget {
final GalleryType galleryType;
@@ -51,38 +54,53 @@ class _FileSelectionOverlayBarState extends State<FileSelectionOverlayBar> {
'$runtimeType building with ${widget.selectedFiles.files.length}',
);
return Container(
decoration: BoxDecoration(
boxShadow: shadowFloatFaintLight,
),
child: ValueListenableBuilder(
valueListenable: _hasSelectedFilesNotifier,
builder: (context, value, child) {
return AnimatedCrossFade(
firstCurve: Curves.easeInOutExpo,
secondCurve: Curves.easeInOutExpo,
sizeCurve: Curves.easeInOutExpo,
crossFadeState: _hasSelectedFilesNotifier.value
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 400),
firstChild: BottomActionBarWidget(
selectedFiles: widget.selectedFiles,
galleryType: widget.galleryType,
collection: widget.collection,
person: widget.person,
clusterID: widget.clusterID,
onCancel: () {
if (widget.selectedFiles.files.isNotEmpty) {
widget.selectedFiles.clearAll();
}
},
backgroundColor: widget.backgroundColor,
),
secondChild: const SizedBox(width: double.infinity),
);
},
),
return ValueListenableBuilder(
valueListenable: _hasSelectedFilesNotifier,
builder: (context, value, child) {
return AnimatedCrossFade(
firstCurve: Curves.easeInOutExpo,
secondCurve: Curves.easeInOutExpo,
sizeCurve: Curves.easeInOutExpo,
crossFadeState: _hasSelectedFilesNotifier.value
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 400),
firstChild: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
flagService.internalUser
? Padding(
padding: const EdgeInsets.only(right: 4),
child: SelectAllButton(
backgroundColor: widget.backgroundColor,
),
)
: const SizedBox.shrink(),
if (flagService.internalUser) const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
boxShadow: shadowFloatFaintLight,
),
child: BottomActionBarWidget(
selectedFiles: widget.selectedFiles,
galleryType: widget.galleryType,
collection: widget.collection,
person: widget.person,
clusterID: widget.clusterID,
onCancel: () {
if (widget.selectedFiles.files.isNotEmpty) {
widget.selectedFiles.clearAll();
}
},
backgroundColor: widget.backgroundColor,
),
),
],
),
secondChild: const SizedBox(width: double.infinity),
);
},
);
}
@@ -90,3 +108,83 @@ class _FileSelectionOverlayBarState extends State<FileSelectionOverlayBar> {
_hasSelectedFilesNotifier.value = widget.selectedFiles.files.isNotEmpty;
}
}
class SelectAllButton extends StatefulWidget {
final Color? backgroundColor;
const SelectAllButton({super.key, required this.backgroundColor});
@override
State<SelectAllButton> createState() => _SelectAllButtonState();
}
class _SelectAllButtonState extends State<SelectAllButton> {
bool _allSelected = false;
@override
Widget build(BuildContext context) {
final selectionState = SelectionState.of(context);
assert(
selectionState != null,
"SelectionState not found in context, SelectionState should be an ancestor of FileSelectionOverlayBar",
);
final colorScheme = getEnteColorScheme(context);
return GestureDetector(
onTap: () {
setState(() {
if (_allSelected) {
selectionState.selectedFiles.clearAll();
} else {
selectionState.selectedFiles
.selectAll(selectionState.allGalleryFiles!.toSet());
}
_allSelected = !_allSelected;
});
},
child: Padding(
padding: const EdgeInsets.only(top: 8),
child: Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: widget.backgroundColor ?? colorScheme.backgroundElevated2,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 4,
offset: const Offset(0, -1),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
Text(
"All",
style: getEnteTextTheme(context).miniMuted,
),
const SizedBox(width: 4),
ListenableBuilder(
listenable: selectionState!.selectedFiles,
builder: (context, _) {
if (selectionState.selectedFiles.files.length ==
selectionState.allGalleryFiles?.length) {
_allSelected = true;
} else {
_allSelected = false;
}
return Icon(
_allSelected
? Icons.check_circle
: Icons.check_circle_outline,
color: _allSelected ? null : colorScheme.strokeMuted,
size: 18,
);
},
),
],
),
),
),
);
}
}

View File

@@ -15,6 +15,7 @@ import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart';
import "package:photos/ui/viewer/gallery/empty_state.dart";
import 'package:photos/ui/viewer/gallery/gallery.dart';
import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
class ArchivePage extends StatelessWidget {
final String tagPrefix;
@@ -86,15 +87,18 @@ class ArchivePage extends StatelessWidget {
_selectedFiles,
),
),
body: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
overlayType,
_selectedFiles,
),
],
body: SelectionState(
selectedFiles: _selectedFiles,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
overlayType,
_selectedFiles,
),
],
),
),
);
}

View File

@@ -16,6 +16,7 @@ import "package:photos/ui/viewer/gallery/empty_album_state.dart";
import 'package:photos/ui/viewer/gallery/empty_state.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart';
import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
class CollectionPage extends StatelessWidget {
final CollectionWithThumbnail c;
@@ -98,16 +99,19 @@ class CollectionPage extends StatelessWidget {
collection: c.collection,
),
),
body: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
galleryType,
_selectedFiles,
collection: c.collection,
),
],
body: SelectionState(
selectedFiles: _selectedFiles,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
galleryType,
_selectedFiles,
collection: c.collection,
),
],
),
),
);
}

View File

@@ -22,6 +22,7 @@ import 'package:photos/ui/components/toggle_switch_widget.dart';
import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart';
import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
class DeviceFolderPage extends StatelessWidget {
final DeviceCollection deviceCollection;
@@ -66,15 +67,18 @@ class DeviceFolderPage extends StatelessWidget {
deviceCollection: deviceCollection,
),
),
body: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
GalleryType.localFolder,
_selectedFiles,
),
],
body: SelectionState(
selectedFiles: _selectedFiles,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
GalleryType.localFolder,
_selectedFiles,
),
],
),
),
);
}

View File

@@ -16,6 +16,7 @@ import "package:photos/ui/viewer/gallery/component/group/type.dart";
import "package:photos/ui/viewer/gallery/component/multiple_groups_gallery_view.dart";
import 'package:photos/ui/viewer/gallery/empty_state.dart';
import "package:photos/ui/viewer/gallery/state/gallery_context_state.dart";
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
import "package:photos/utils/debouncer.dart";
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
@@ -107,6 +108,7 @@ class GalleryState extends State<Gallery> {
final _forceReloadEventSubscriptions = <StreamSubscription<Event>>[];
late String _logTag;
bool _sortOrderAsc = false;
List<EnteFile> _allFiles = [];
@override
void initState() {
@@ -213,6 +215,8 @@ class GalleryState extends State<Gallery> {
// group files into multiple groups and returns `true` if it resulted in a
// gallery reload
bool _onFilesLoaded(List<EnteFile> files) {
_allFiles = files;
final updatedGroupedFiles =
widget.enableFileGrouping && widget.groupType.timeGrouping()
? _groupBasedOnTime(files)
@@ -246,6 +250,7 @@ class GalleryState extends State<Gallery> {
@override
Widget build(BuildContext context) {
_logger.finest("Building Gallery ${widget.tagPrefix}");
SelectionState.of(context)?.allGalleryFiles = _allFiles;
if (!_hasLoadedFiles) {
return widget.loadingWidget;
}

View File

@@ -179,7 +179,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
setState(() {});
}
} catch (e, s) {
_logger.severe("Failed to rename album", e, s);
_logger.warning("Failed to rename album", e, s);
rethrow;
}
},
@@ -610,7 +610,7 @@ class _GalleryAppBarWidgetState extends State<GalleryAppBarWidget> {
await dialog.hide();
Navigator.of(context).pop();
} catch (e, s) {
_logger.severe("failed to trash collection", e, s);
_logger.warning("failed to trash collection", e, s);
await dialog.hide();
await showGenericErrorDialog(context: context, error: e);
}

View File

@@ -19,6 +19,7 @@ import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart';
import 'package:photos/ui/viewer/gallery/empty_hidden_widget.dart';
import 'package:photos/ui/viewer/gallery/gallery.dart';
import 'package:photos/ui/viewer/gallery/gallery_app_bar_widget.dart';
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
class HiddenPage extends StatefulWidget {
final String tagPrefix;
@@ -139,15 +140,18 @@ class _HiddenPageState extends State<HiddenPage> {
_selectedFiles,
),
),
body: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
widget.overlayType,
_selectedFiles,
),
],
body: SelectionState(
selectedFiles: _selectedFiles,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
widget.overlayType,
_selectedFiles,
),
],
),
),
);
}

View File

@@ -13,6 +13,7 @@ import "package:photos/services/search_service.dart";
import 'package:photos/ui/viewer/actions/file_selection_overlay_bar.dart';
import "package:photos/ui/viewer/gallery/component/group/type.dart";
import 'package:photos/ui/viewer/gallery/gallery.dart';
import "package:photos/ui/viewer/gallery/state/selection_state.dart";
class LargeFilesPagePage extends StatelessWidget {
final String tagPrefix;
@@ -84,15 +85,18 @@ class LargeFilesPagePage extends StatelessWidget {
),
),
),
body: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
overlayType,
_selectedFiles,
),
],
body: SelectionState(
selectedFiles: _selectedFiles,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
gallery,
FileSelectionOverlayBar(
overlayType,
_selectedFiles,
),
],
),
),
);
}

Some files were not shown because too many files have changed in this diff Show More