diff --git a/.github/workflows/buildFrontend.yml b/.github/workflows/buildFrontend.yml new file mode 100644 index 00000000..ed06dbd5 --- /dev/null +++ b/.github/workflows/buildFrontend.yml @@ -0,0 +1,27 @@ +name: Build Angular App + +on: + push: + branches: [ "main", "devel" ] + pull_request: + branches: [ "main", "devel" ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install dependencies + run: cd corn-frontend; npm install + + - name: Build Developer + run: cd corn-frontend; npm run ng build + + - name: Build production + run: cd corn-frontend; npm run ng build --configuration=production diff --git a/.github/workflows/checkDockerDev.yml b/.github/workflows/checkDockerDev.yml new file mode 100644 index 00000000..2be5c386 --- /dev/null +++ b/.github/workflows/checkDockerDev.yml @@ -0,0 +1,70 @@ +name: Check dockercompose.dev + +on: + push: + branches: [ "main", "devel" ] + pull_request: + branches: [ "main", "devel" ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install jq + run: sudo apt-get install -y jq + + - name: Setup useful functions + run: | + rc=/tmp/rcfile + echo "lscontainers() { docker ps -qa | xargs --no-run-if-empty docker inspect; }" >> $rc + echo "asserttrue() { [ \"\$(cat)\" = \"true\" ]; }" >> $rc + echo "checkstatus() { lscontainers | jq -r '.[] | select(.Name == \"/'\"\$1\"'\").State.Status == \"'\"\$2\"'\"'; }" >> $rc + echo "ishealthy() { lscontainers | jq -r '.[] | select(.Name == \"/'\"\$1\"'\").State.Health.Status == \"healthy\"'; }" >> $rc + echo "fatal() { echo \"Check failed: \$@\" 1>&2; exit 1; }" >> $rc + + - name: Boot up containers + run: docker compose -f docker-compose.dev.yml up --build -d + + - name: Wait for transient states to disappear + run: sleep 200 + + - name: Test backend + run: | + source /tmp/rcfile + checkstatus "corn-postgres" "running" | asserttrue || fatal "BackDb" + checkstatus "corn-backend" "running" | asserttrue || fatal "BackSpring" + + - name: Test frontend + run: | + source /tmp/rcfile + checkstatus "corn-frontend" "running" | asserttrue || fatal "FrontNg" + + - name: Test nginx + run: | + source /tmp/rcfile + checkstatus "corn-nginx" "running" | asserttrue || fatal "NginxMain" + + - name: Test keycloak + run: | + source /tmp/rcfile + checkstatus "corn-keycloak" "running" | asserttrue || fatal "KcMain" + ishealthy "corn-keycloak" | asserttrue || fatal "KcMainHealth" + checkstatus "corn-keycloak-postgres" "running" | asserttrue || fatal "KcDb" + ishealthy "corn-keycloak-postgres" | asserttrue || fatal "KcDbHealth" + checkstatus "corn-keycloak-theme" "running" | asserttrue || fatal "KcTheme" + checkstatus "corn-keycloak-initializer" "exited" | asserttrue || fatal "KcInit" + + - name: Test proxies connectivity + run: | + source /tmp/rcfile + curl -qo /dev/null -w "%{http_code}" 'http://localhost:4200/api/fallible' | grep -qP '^(502|503|504).*' || exit 0 && fatal "NginxBack" + curl -qo /dev/null -w "%{http_code}" 'http://localhost:4200/' | grep -qP '^(502|503|504).*' || exit 0 && fatal "NginxFront" + curl -qo /dev/null -w "%{http_code}" 'http://localhost:8081/realms/Corn' | grep -qP '^(502|503|504).*' || exit 0 && fatal "NginxKc" + + - name: Test existence of Corn realm + run: | + source /tmp/rcfile + curl 'http://localhost:8081/realms/Corn/' | jq -r '.error == null' | asserttrue || fatal "CornRealm" diff --git a/.github/workflows/checkDockerProd.yml b/.github/workflows/checkDockerProd.yml new file mode 100644 index 00000000..133c28de --- /dev/null +++ b/.github/workflows/checkDockerProd.yml @@ -0,0 +1,69 @@ +name: Check dockercompose.prod + +on: + push: + branches: [ "main", "devel" ] + pull_request: + branches: [ "main", "devel" ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install jq + run: sudo apt-get install -y jq + + - name: Setup useful functions + run: | + rc=/tmp/rcfile + echo "lscontainers() { docker ps -qa | xargs --no-run-if-empty docker inspect; }" >> $rc + echo "asserttrue() { [ \"\$(cat)\" = \"true\" ]; }" >> $rc + echo "checkstatus() { lscontainers | jq -r '.[] | select(.Name == \"/'\"\$1\"'\").State.Status == \"'\"\$2\"'\"'; }" >> $rc + echo "ishealthy() { lscontainers | jq -r '.[] | select(.Name == \"/'\"\$1\"'\").State.Health.Status == \"healthy\"'; }" >> $rc + echo "fatal() { echo \"Check failed: \$@\" 1>&2; exit 1; }" >> $rc + + - name: Boot up containers + run: docker compose -f docker-compose.prod.yml up --build -d + + - name: Wait for transient states to disappear + run: sleep 200 + + - name: Test backend + run: | + source /tmp/rcfile + checkstatus "corn-postgres" "running" | asserttrue || fatal "BackDb" + checkstatus "corn-backend" "running" | asserttrue || fatal "BackSpring" + + - name: Test frontend + run: | + source /tmp/rcfile + checkstatus "corn-frontend" "running" | asserttrue || fatal "FrontNginx" + + - name: Test nginx + run: | + source /tmp/rcfile + checkstatus "corn-nginx" "running" | asserttrue || fatal "NginxMain" + + - name: Test keycloak + run: | + source /tmp/rcfile + checkstatus "corn-keycloak" "running" | asserttrue || fatal "KcMain" + ishealthy "corn-keycloak" | asserttrue || fatal "KcMainHealth" + checkstatus "corn-keycloak-postgres" "running" | asserttrue || fatal "KcDb" + ishealthy "corn-keycloak-postgres" | asserttrue || fatal "KcDbHealth" + checkstatus "corn-keycloak-initializer" "exited" | asserttrue || fatal "KcInit" + + - name: Test proxies connectivity + run: | + source /tmp/rcfile + curl -qo /dev/null -w "%{http_code}" 'http://localhost:4200/api/fallible' | grep -qP '^(502|503|504).*' || exit 0 && fatal "NginxBack" + curl -qo /dev/null -w "%{http_code}" 'http://localhost:4200/' | grep -qP '^(502|503|504).*' || exit 0 && fatal "NginxFront" + curl -qo /dev/null -w "%{http_code}" 'http://localhost:8081/realms/Corn' | grep -qP '^(502|503|504).*' || exit 0 && fatal "NginxKc" + + - name: Test existence of Corn realm + run: | + source /tmp/rcfile + curl 'http://localhost:8081/realms/Corn/' | jq -r '.error == null' | asserttrue || fatal "CornRealm" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 75799b24..12e33060 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,7 +2,7 @@ name: Test Application with Gradle on: push: - branches: [ "main" ] + branches: [ "main", "devel" ] pull_request: branches: [ "main", "devel" ] @@ -45,4 +45,4 @@ jobs: with: gradle-version: '8.2' arguments: build - build-root-directory: corn-backend \ No newline at end of file + build-root-directory: corn-backend diff --git a/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/ExternalConfig.java b/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/ExternalConfig.java index 7d31a88f..237266e3 100644 --- a/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/ExternalConfig.java +++ b/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/ExternalConfig.java @@ -13,6 +13,8 @@ public final class ExternalConfig { private static final String KCCFG_OVERRIDE_EXISTING = System.getenv("KCCFG_OVERRIDE_EXISTING"); + private static final String KCCFG_CREATE_PLACEHOLDER_USERS = System.getenv("KCCFG_CREATE_PLACEHOLDER_USERS"); + public static final String KCCFG_LOGIN_THEME_NAME = System.getenv("KCCFG_LOGIN_THEME_NAME"); private static final String KC_SERVER_URL = System.getenv("KC_SERVER_URL"); @@ -43,6 +45,10 @@ static boolean shouldOverrideExistingConfiguration() { return "true".equalsIgnoreCase(KCCFG_OVERRIDE_EXISTING); } + public static boolean shouldCreatePlaceholderUsers() { + return "true".equalsIgnoreCase(KCCFG_CREATE_PLACEHOLDER_USERS); + } + public static List getIdentityProviders() { List providers = new ArrayList<>(3); diff --git a/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/Main.java b/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/Main.java index 98fa2ea1..21de1e21 100644 --- a/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/Main.java +++ b/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/Main.java @@ -18,15 +18,13 @@ public static void main(String[] args) { .stream() .filter(r -> r.getRealm().equals(realm.getRealm())) .findFirst() - .ifPresentOrElse( - r -> { - if (!ExternalConfig.shouldOverrideExistingConfiguration()) { - throw new UnsupportedOperationException("Configured not to override existing configuration => Exiting"); - } - admin.realms().realm(r.getRealm()).remove(); - }, - () -> admin.realms().create(realm) - ); + .ifPresent(r -> { + if (!ExternalConfig.shouldOverrideExistingConfiguration()) { + throw new UnsupportedOperationException("Configured not to override existing configuration => Exiting"); + } + admin.realms().realm(r.getRealm()).remove(); + }); + admin.realms().create(realm); } } diff --git a/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/realm/corn/CornRealm.java b/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/realm/corn/CornRealm.java index f40607e8..9e233b71 100644 --- a/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/realm/corn/CornRealm.java +++ b/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/realm/corn/CornRealm.java @@ -7,7 +7,6 @@ public final class CornRealm extends RealmRepresentation { private static final String REALM_NAME = "Corn"; - private static final String DEFAULT_SIGNATURE_ALGORITHM = "ES512"; public CornRealm() { setRealm(REALM_NAME); @@ -18,7 +17,10 @@ public CornRealm() { setRevokeRefreshToken(true); setRememberMe(true); setBruteForceProtected(true); - setDefaultSignatureAlgorithm(DEFAULT_SIGNATURE_ALGORITHM); + + if(ExternalConfig.shouldCreatePlaceholderUsers()) { + setUsers(PlaceholderUsers.generate()); + } if(ExternalConfig.KCCFG_LOGIN_THEME_NAME != null) { setLoginTheme(ExternalConfig.KCCFG_LOGIN_THEME_NAME); diff --git a/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/realm/corn/PlaceholderUsers.java b/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/realm/corn/PlaceholderUsers.java new file mode 100644 index 00000000..8df17ef7 --- /dev/null +++ b/auth-server/keycloak-initializer/src/main/java/keycloakinitializer/realm/corn/PlaceholderUsers.java @@ -0,0 +1,46 @@ +package keycloakinitializer.realm.corn; + +import org.keycloak.representations.idm.CredentialRepresentation; +import org.keycloak.representations.idm.UserRepresentation; + +import java.util.List; +import java.util.stream.Stream; + +import static java.util.Collections.singletonList; + +public class PlaceholderUsers { + + private static final String MAIL_SUFFIX = "@mail.pl"; + private static final String DEFAULT_ROLE = "default-roles-corn"; + + public static List generate() { + return Stream.of( + new SimpleUser("Jan", "Kowalski", "jan", "123"), + new SimpleUser("Andrzej", "Switch", "andrzej", "123"), + new SimpleUser("John", "Doe", "john", "123"), + new SimpleUser("Jane", "Doe", "jane", "123"), + new SimpleUser("Alice", "Smith", "alice", "123"), + new SimpleUser("Bob", "Johnson", "bob", "123") + ).map(SimpleUser::intoUserRepresentation).toList(); + } + + private record SimpleUser(String name, String surname, String username, String password) { + + UserRepresentation intoUserRepresentation() { + return new UserRepresentation() {{ + setUsername(username()); + setFirstName(name); + setLastName(surname); + setEmail(username.toLowerCase()+MAIL_SUFFIX); + setEmailVerified(true); + setEnabled(true); + setRealmRoles(List.of(DEFAULT_ROLE)); + setCredentials(singletonList(new CredentialRepresentation() {{ + setType(CredentialRepresentation.PASSWORD); + setValue(password()); + }})); + }}; + } + + } +} \ No newline at end of file diff --git a/auth-server/keycloak-theme/Dockerfile.keycloak.prod b/auth-server/keycloak-theme/Dockerfile.keycloak.prod new file mode 100644 index 00000000..877f98b9 --- /dev/null +++ b/auth-server/keycloak-theme/Dockerfile.keycloak.prod @@ -0,0 +1,21 @@ +FROM alpine:3.19.1 AS build + +WORKDIR /keycloak-theme + +RUN apk update --no-cache && apk add --no-cache nodejs npm zip + +COPY package*.json ./ + +RUN npm install + +COPY . . + +RUN npm run build:corn:prod + +RUN mv themes theme + +RUN zip -r corn-theme.jar theme META-INF + +FROM quay.io/keycloak/keycloak:20.0.1 + +COPY --from=build /keycloak-theme/corn-theme.jar /opt/keycloak/providers/ diff --git a/auth-server/keycloak-theme/Dockerfile.prod b/auth-server/keycloak-theme/Dockerfile.prod deleted file mode 100644 index 9d6dcb72..00000000 --- a/auth-server/keycloak-theme/Dockerfile.prod +++ /dev/null @@ -1,21 +0,0 @@ -FROM alpine:3.19.1 AS build - -WORKDIR /corn - -RUN apk update --no-cache && apk add --no-cache nodejs npm - -COPY package*.json ./ - -RUN npm install - -COPY . . - -RUN npm run build:corn:prod - -FROM alpine:3.19.1 - -WORKDIR /corn-theme - -COPY --from=build /corn/styles ./styles - -COPY --from=build /corn/themes ./themes diff --git a/auth-server/keycloak-theme/META-INF/keycloak-themes.json b/auth-server/keycloak-theme/META-INF/keycloak-themes.json new file mode 100644 index 00000000..f2ce86bf --- /dev/null +++ b/auth-server/keycloak-theme/META-INF/keycloak-themes.json @@ -0,0 +1,6 @@ +{ + "themes": [{ + "name" : "corn", + "types": [ "login" ] + }] +} diff --git a/auth-server/keycloak-theme/themes/corn/login/resources/css/styles.css b/auth-server/keycloak-theme/themes/corn/login/resources/css/styles.css deleted file mode 100644 index e95c8dfe..00000000 --- a/auth-server/keycloak-theme/themes/corn/login/resources/css/styles.css +++ /dev/null @@ -1,1023 +0,0 @@ -/* -! tailwindcss v3.4.0 | MIT License | https://tailwindcss.com -*/ - -/* -1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) -2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) -*/ - -*, -::before, -::after { - box-sizing: border-box; - /* 1 */ - border-width: 0; - /* 2 */ - border-style: solid; - /* 2 */ - border-color: #e5e7eb; - /* 2 */ -} - -::before, -::after { - --tw-content: ''; -} - -/* -1. Use a consistent sensible line-height in all browsers. -2. Prevent adjustments of font size after orientation changes in iOS. -3. Use a more readable tab size. -4. Use the user's configured `sans` font-family by default. -5. Use the user's configured `sans` font-feature-settings by default. -6. Use the user's configured `sans` font-variation-settings by default. -7. Disable tap highlights on iOS -*/ - -html, -:host { - line-height: 1.5; - /* 1 */ - -webkit-text-size-adjust: 100%; - /* 2 */ - -moz-tab-size: 4; - /* 3 */ - -o-tab-size: 4; - tab-size: 4; - /* 3 */ - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - /* 4 */ - font-feature-settings: normal; - /* 5 */ - font-variation-settings: normal; - /* 6 */ - -webkit-tap-highlight-color: transparent; - /* 7 */ -} - -/* -1. Remove the margin in all browsers. -2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. -*/ - -body { - margin: 0; - /* 1 */ - line-height: inherit; - /* 2 */ -} - -/* -1. Add the correct height in Firefox. -2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) -3. Ensure horizontal rules are visible by default. -*/ - -hr { - height: 0; - /* 1 */ - color: inherit; - /* 2 */ - border-top-width: 1px; - /* 3 */ -} - -/* -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -abbr:where([title]) { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - -/* -Remove the default font size and weight for headings. -*/ - -h1, -h2, -h3, -h4, -h5, -h6 { - font-size: inherit; - font-weight: inherit; -} - -/* -Reset links to optimize for opt-in styling instead of opt-out. -*/ - -a { - color: inherit; - text-decoration: inherit; -} - -/* -Add the correct font weight in Edge and Safari. -*/ - -b, -strong { - font-weight: bolder; -} - -/* -1. Use the user's configured `mono` font-family by default. -2. Use the user's configured `mono` font-feature-settings by default. -3. Use the user's configured `mono` font-variation-settings by default. -4. Correct the odd `em` font sizing in all browsers. -*/ - -code, -kbd, -samp, -pre { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - /* 1 */ - font-feature-settings: normal; - /* 2 */ - font-variation-settings: normal; - /* 3 */ - font-size: 1em; - /* 4 */ -} - -/* -Add the correct font size in all browsers. -*/ - -small { - font-size: 80%; -} - -/* -Prevent `sub` and `sup` elements from affecting the line height in all browsers. -*/ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -3. Remove gaps between table borders by default. -*/ - -table { - text-indent: 0; - /* 1 */ - border-color: inherit; - /* 2 */ - border-collapse: collapse; - /* 3 */ -} - -/* -1. Change the font styles in all browsers. -2. Remove the margin in Firefox and Safari. -3. Remove default padding in all browsers. -*/ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - /* 1 */ - font-feature-settings: inherit; - /* 1 */ - font-variation-settings: inherit; - /* 1 */ - font-size: 100%; - /* 1 */ - font-weight: inherit; - /* 1 */ - line-height: inherit; - /* 1 */ - color: inherit; - /* 1 */ - margin: 0; - /* 2 */ - padding: 0; - /* 3 */ -} - -/* -Remove the inheritance of text transform in Edge and Firefox. -*/ - -button, -select { - text-transform: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Remove default button styles. -*/ - -button, -[type='button'], -[type='reset'], -[type='submit'] { - -webkit-appearance: button; - /* 1 */ - background-color: transparent; - /* 2 */ - background-image: none; - /* 2 */ -} - -/* -Use the modern Firefox focus style for all focusable elements. -*/ - -:-moz-focusring { - outline: auto; -} - -/* -Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) -*/ - -:-moz-ui-invalid { - box-shadow: none; -} - -/* -Add the correct vertical alignment in Chrome and Firefox. -*/ - -progress { - vertical-align: baseline; -} - -/* -Correct the cursor style of increment and decrement buttons in Safari. -*/ - -::-webkit-inner-spin-button, -::-webkit-outer-spin-button { - height: auto; -} - -/* -1. Correct the odd appearance in Chrome and Safari. -2. Correct the outline style in Safari. -*/ - -[type='search'] { - -webkit-appearance: textfield; - /* 1 */ - outline-offset: -2px; - /* 2 */ -} - -/* -Remove the inner padding in Chrome and Safari on macOS. -*/ - -::-webkit-search-decoration { - -webkit-appearance: none; -} - -/* -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to `inherit` in Safari. -*/ - -::-webkit-file-upload-button { - -webkit-appearance: button; - /* 1 */ - font: inherit; - /* 2 */ -} - -/* -Add the correct display in Chrome and Safari. -*/ - -summary { - display: list-item; -} - -/* -Removes the default spacing and border for appropriate elements. -*/ - -blockquote, -dl, -dd, -h1, -h2, -h3, -h4, -h5, -h6, -hr, -figure, -p, -pre { - margin: 0; -} - -fieldset { - margin: 0; - padding: 0; -} - -legend { - padding: 0; -} - -ol, -ul, -menu { - list-style: none; - margin: 0; - padding: 0; -} - -/* -Reset default styling for dialogs. -*/ - -dialog { - padding: 0; -} - -/* -Prevent resizing textareas horizontally by default. -*/ - -textarea { - resize: vertical; -} - -/* -1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) -2. Set the default placeholder color to the user's configured gray 400 color. -*/ - -input::-moz-placeholder, textarea::-moz-placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -input::placeholder, -textarea::placeholder { - opacity: 1; - /* 1 */ - color: #9ca3af; - /* 2 */ -} - -/* -Set the default cursor for buttons. -*/ - -button, -[role="button"] { - cursor: pointer; -} - -/* -Make sure disabled buttons don't get the pointer cursor. -*/ - -:disabled { - cursor: default; -} - -/* -1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) -2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) - This can trigger a poorly considered lint error in some tools but is included by design. -*/ - -img, -svg, -video, -canvas, -audio, -iframe, -embed, -object { - display: block; - /* 1 */ - vertical-align: middle; - /* 2 */ -} - -/* -Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) -*/ - -img, -video { - max-width: 100%; - height: auto; -} - -/* Make elements with the HTML hidden attribute stay hidden by default */ - -[hidden] { - display: none; -} - -[type='text'],[type='email'],[type='url'],[type='password'],[type='number'],[type='date'],[type='datetime-local'],[type='month'],[type='search'],[type='tel'],[type='time'],[type='week'],[multiple],textarea,select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; - border-radius: 0px; - padding-top: 0.5rem; - padding-right: 0.75rem; - padding-bottom: 0.5rem; - padding-left: 0.75rem; - font-size: 1rem; - line-height: 1.5rem; - --tw-shadow: 0 0 #0000; -} - -[type='text']:focus, [type='email']:focus, [type='url']:focus, [type='password']:focus, [type='number']:focus, [type='date']:focus, [type='datetime-local']:focus, [type='month']:focus, [type='search']:focus, [type='tel']:focus, [type='time']:focus, [type='week']:focus, [multiple]:focus, textarea:focus, select:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); - border-color: #2563eb; -} - -input::-moz-placeholder, textarea::-moz-placeholder { - color: #6b7280; - opacity: 1; -} - -input::placeholder,textarea::placeholder { - color: #6b7280; - opacity: 1; -} - -::-webkit-datetime-edit-fields-wrapper { - padding: 0; -} - -::-webkit-date-and-time-value { - min-height: 1.5em; -} - -::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field { - padding-top: 0; - padding-bottom: 0; -} - -select { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); - background-position: right 0.5rem center; - background-repeat: no-repeat; - background-size: 1.5em 1.5em; - padding-right: 2.5rem; - -webkit-print-color-adjust: exact; - color-adjust: exact; -} - -[multiple] { - background-image: initial; - background-position: initial; - background-repeat: unset; - background-size: initial; - padding-right: 0.75rem; - -webkit-print-color-adjust: unset; - color-adjust: unset; -} - -[type='checkbox'],[type='radio'] { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - padding: 0; - -webkit-print-color-adjust: exact; - color-adjust: exact; - display: inline-block; - vertical-align: middle; - background-origin: border-box; - -webkit-user-select: none; - -moz-user-select: none; - user-select: none; - flex-shrink: 0; - height: 1rem; - width: 1rem; - color: #2563eb; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; - --tw-shadow: 0 0 #0000; -} - -[type='checkbox'] { - border-radius: 0px; -} - -[type='radio'] { - border-radius: 100%; -} - -[type='checkbox']:focus,[type='radio']:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); - --tw-ring-offset-width: 2px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); -} - -[type='checkbox']:checked,[type='radio']:checked { - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type='checkbox']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); -} - -[type='radio']:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); -} - -[type='checkbox']:checked:hover,[type='checkbox']:checked:focus,[type='radio']:checked:hover,[type='radio']:checked:focus { - border-color: transparent; - background-color: currentColor; -} - -[type='checkbox']:indeterminate { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type='checkbox']:indeterminate:hover,[type='checkbox']:indeterminate:focus { - border-color: transparent; - background-color: currentColor; -} - -[type='file'] { - background: unset; - border-color: inherit; - border-width: 0; - border-radius: 0; - padding: 0; - font-size: unset; - line-height: inherit; -} - -[type='file']:focus { - outline: 1px auto -webkit-focus-ring-color; -} - -*, ::before, ::after { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgb(59 130 246 / 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} - -.relative { - position: relative; -} - -.mb-\[12px\] { - margin-bottom: 12px; -} - -.ml-\[-352px\] { - margin-left: -352px; -} - -.ml-\[2px\] { - margin-left: 2px; -} - -.ml-\[4px\] { - margin-left: 4px; -} - -.ml-auto { - margin-left: auto; -} - -.mt-\[12px\] { - margin-top: 12px; -} - -.mt-\[2px\] { - margin-top: 2px; -} - -.flex { - display: flex; -} - -.inline-flex { - display: inline-flex; -} - -.grid { - display: grid; -} - -.hidden { - display: none; -} - -.h-4 { - height: 1rem; -} - -.h-5 { - height: 1.25rem; -} - -.h-8 { - height: 2rem; -} - -.h-px { - height: 1px; -} - -.h-screen { - height: 100vh; -} - -.max-h-\[0px\] { - max-height: 0px; -} - -.min-h-\[512px\] { - min-height: 512px; -} - -.min-h-screen { - min-height: 100vh; -} - -.w-5 { - width: 1.25rem; -} - -.w-\[160px\] { - width: 160px; -} - -.w-\[50\%\] { - width: 50%; -} - -.w-full { - width: 100%; -} - -.min-w-\[512px\] { - min-width: 512px; -} - -.max-w-\[0px\] { - max-width: 0px; -} - -.flex-1 { - flex: 1 1 0%; -} - -.grid-cols-2 { - grid-template-columns: repeat(2, minmax(0, 1fr)); -} - -.flex-col { - flex-direction: column; -} - -.items-center { - align-items: center; -} - -.justify-center { - justify-content: center; -} - -.justify-between { - justify-content: space-between; -} - -.gap-\[12px\] { - gap: 12px; -} - -.rounded { - border-radius: 0.25rem; -} - -.rounded-md { - border-radius: 0.375rem; -} - -.rounded-l-\[32px\] { - border-top-left-radius: 32px; - border-bottom-left-radius: 32px; -} - -.border { - border-width: 1px; -} - -.border-gray-400 { - --tw-border-opacity: 1; - border-color: rgb(156 163 175 / var(--tw-border-opacity)); -} - -.border-gray-600 { - --tw-border-opacity: 1; - border-color: rgb(75 85 99 / var(--tw-border-opacity)); -} - -.border-yellow-600 { - --tw-border-opacity: 1; - border-color: rgb(202 138 4 / var(--tw-border-opacity)); -} - -.bg-gray-300 { - --tw-bg-opacity: 1; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)); -} - -.bg-gray-600 { - --tw-bg-opacity: 1; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)); -} - -.bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); -} - -.bg-yellow-400 { - --tw-bg-opacity: 1; - background-color: rgb(250 204 21 / var(--tw-bg-opacity)); -} - -.bg-yellow-500 { - --tw-bg-opacity: 1; - background-color: rgb(234 179 8 / var(--tw-bg-opacity)); -} - -.bg-yellowishDark { - --tw-bg-opacity: 1; - background-color: rgb(40 39 39 / var(--tw-bg-opacity)); -} - -.px-4 { - padding-left: 1rem; - padding-right: 1rem; -} - -.py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} - -.pl-\[32px\] { - padding-left: 32px; -} - -.pr-\[32px\] { - padding-right: 32px; -} - -.text-center { - text-align: center; -} - -.text-5xl { - font-size: 3rem; - line-height: 1; -} - -.text-lg { - font-size: 1.125rem; - line-height: 1.75rem; -} - -.font-bold { - font-weight: 700; -} - -.font-semibold { - font-weight: 600; -} - -.text-gray-300 { - --tw-text-opacity: 1; - color: rgb(209 213 219 / var(--tw-text-opacity)); -} - -.text-gray-700 { - --tw-text-opacity: 1; - color: rgb(55 65 81 / var(--tw-text-opacity)); -} - -.text-red-500 { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); -} - -.text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} - -.text-yellow-300 { - --tw-text-opacity: 1; - color: rgb(253 224 71 / var(--tw-text-opacity)); -} - -.placeholder-gray-200::-moz-placeholder { - --tw-placeholder-opacity: 1; - color: rgb(229 231 235 / var(--tw-placeholder-opacity)); -} - -.placeholder-gray-200::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(229 231 235 / var(--tw-placeholder-opacity)); -} - -.transition-colors { - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - transition-duration: 150ms; -} - -.duration-200 { - transition-duration: 200ms; -} - -.duration-300 { - transition-duration: 300ms; -} - -.hover\:border-yellow-700:hover { - --tw-border-opacity: 1; - border-color: rgb(161 98 7 / var(--tw-border-opacity)); -} - -.hover\:bg-gray-300:hover { - --tw-bg-opacity: 1; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)); -} - -.hover\:bg-yellow-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(202 138 4 / var(--tw-bg-opacity)); -} - -.hover\:text-gray-800:hover { - --tw-text-opacity: 1; - color: rgb(31 41 55 / var(--tw-text-opacity)); -} - -.focus\:border-blue-500:focus { - --tw-border-opacity: 1; - border-color: rgb(59 130 246 / var(--tw-border-opacity)); -} - -.focus\:outline-none:focus { - outline: 2px solid transparent; - outline-offset: 2px; -} diff --git a/corn-backend/postman/Corn.postman_collection.json b/corn-backend/postman/Corn.postman_collection.json new file mode 100644 index 00000000..99985e55 --- /dev/null +++ b/corn-backend/postman/Corn.postman_collection.json @@ -0,0 +1,1122 @@ +{ + "info": { + "_postman_id": "64fe62d4-07b6-40b7-ad59-fe040c72217f", + "name": "Corn", + "description": "Documentation for Corn project api.\n\nCheck variables tab for important variables to be set for endpoints.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "28494266" + }, + "item": [ + { + "name": "Project", + "item": [ + { + "name": "AddNewProject", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/project/addProject?name=newProjectName", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "project", + "addProject" + ], + "query": [ + { + "key": "name", + "value": "newProjectName", + "description": "Name for the new project" + } + ] + } + }, + "response": [] + }, + { + "name": "GetProjectsOnPage", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/project/getProjectsOnPage?page=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "project", + "getProjectsOnPage" + ], + "query": [ + { + "key": "page", + "value": "0", + "description": "Page for pageable to get next 20 pages" + } + ] + } + }, + "response": [] + }, + { + "name": "UpdateProject", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/project/updateProjectsName?name=updatedProjectName&projectId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "project", + "updateProjectsName" + ], + "query": [ + { + "key": "name", + "value": "updatedProjectName", + "description": "New name for an existing project" + }, + { + "key": "projectId", + "value": "0", + "description": "Id of a project to update" + } + ] + } + }, + "response": [] + }, + { + "name": "DeleteProject", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/project/deleteProject?projectId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "project", + "deleteProject" + ], + "query": [ + { + "key": "projectId", + "value": "0", + "description": "Id of a project to be deleted" + } + ] + } + }, + "response": [] + } + ], + "description": "Endpoints for project : /api/v1/project" + }, + { + "name": "ProjectMember", + "item": [ + { + "name": "AddMemberToProject", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/project/assignee/addMember?username=jacek@gmail.com&projectId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "project", + "assignee", + "addMember" + ], + "query": [ + { + "key": "username", + "value": "jacek@gmail.com", + "description": "The username of the user that you want to add to project" + }, + { + "key": "projectId", + "value": "0", + "description": "The Id of project to which you want to a user to" + } + ] + } + }, + "response": [] + }, + { + "name": "GetProjectMembers", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/project/assignee/getMembers?projectId=0&page=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "project", + "assignee", + "getMembers" + ], + "query": [ + { + "key": "projectId", + "value": "0", + "description": "Id of project which members you want to get" + }, + { + "key": "page", + "value": "0", + "description": "Page for pageable of size 20" + } + ] + } + }, + "response": [] + }, + { + "name": "RemoveMemberFromProject", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/project/assignee/removeMember?username=jacek@gmail.com&projectId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "project", + "assignee", + "removeMember" + ], + "query": [ + { + "key": "username", + "value": "jacek@gmail.com", + "description": "Username of user to be deleted from project" + }, + { + "key": "projectId", + "value": "0", + "description": "Id of project of which you can delete user from" + } + ] + } + }, + "response": [] + } + ], + "description": "Endpoints for project members api : /api/v1/project/member" + }, + { + "name": "Sprint", + "item": [ + { + "name": "AddNewSprint", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"projectId\": 0,\r\n \"name\": \"NameOfSprint\",\r\n \"startDate\": \"2000-01-01\",\r\n \"endDate\": \"2000-01-21\",\r\n \"description\": \"Example description of project\"\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ backendApiUrl }}/sprint/addSprint", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "sprint", + "addSprint" + ] + } + }, + "response": [] + }, + { + "name": "GetSprintById", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/sprint/getSprintById?sprintId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "sprint", + "getSprintById" + ], + "query": [ + { + "key": "sprintId", + "value": "0", + "description": "Id of a sprint" + } + ] + } + }, + "response": [] + }, + { + "name": "GetSprintsOnPage", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/sprint/getSprintsOnPage?page=0&projectId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "sprint", + "getSprintsOnPage" + ], + "query": [ + { + "key": "page", + "value": "0", + "description": "Page of pageable to get sprints for a project" + }, + { + "key": "projectId", + "value": "0", + "description": "Id of a project of which we want to get sprints from" + } + ] + } + }, + "response": [] + }, + { + "name": "UpdateSprintsName", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/sprint/updateSprintsName?name=newSprintsName&sprintId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "sprint", + "updateSprintsName" + ], + "query": [ + { + "key": "name", + "value": "newSprintsName", + "description": "New name for a sprint" + }, + { + "key": "sprintId", + "value": "0", + "description": "Id of a sprint to be updated" + } + ] + } + }, + "response": [] + }, + { + "name": "UpdateSprintsDescription", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/sprint/updateSprintsDescription?description=\"This is my new description for sprint\"&sprintId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "sprint", + "updateSprintsDescription" + ], + "query": [ + { + "key": "description", + "value": "\"This is my new description for sprint\"", + "description": "The new description for sprint" + }, + { + "key": "sprintId", + "value": "0", + "description": "Id of sprint to be updated" + } + ] + } + }, + "response": [] + }, + { + "name": "UpdateSprintsStartDate", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/sprint/updateSprintsStartDate?startDate=2024-01-01&sprintId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "sprint", + "updateSprintsStartDate" + ], + "query": [ + { + "key": "startDate", + "value": "2024-01-01", + "description": "New start date of sprint" + }, + { + "key": "sprintId", + "value": "0", + "description": "Id of sprint to update" + } + ] + } + }, + "response": [] + }, + { + "name": "UpdateSprintsEndDate", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/sprint/updateSprintsEndDate?endDate=2024-01-01&sprintId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "sprint", + "updateSprintsEndDate" + ], + "query": [ + { + "key": "endDate", + "value": "2024-01-01", + "description": "New end date of sprint" + }, + { + "key": "sprintId", + "value": "0", + "description": "Id of a sprint" + } + ] + } + }, + "response": [] + }, + { + "name": "DeleteSprint", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/sprint/deleteSprint?sprintId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "sprint", + "deleteSprint" + ], + "query": [ + { + "key": "sprintId", + "value": "0", + "description": "Id of a sprint to be deleted" + } + ] + } + }, + "response": [] + } + ], + "description": "Endpoints for api : /api/v1/sprint" + }, + { + "name": "BacklogItemComment", + "item": [ + { + "name": "AddNewComment", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"comment\": \"A comment for a backlog item\",\r\n \"backlogItemId\": 0\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ backendApiUrl }}/backlog/comment/add", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "comment", + "add" + ] + } + }, + "response": [] + }, + { + "name": "UpdateComment", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/backlog/comment/update?commentId=0&comment=\"New comment text\"", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "comment", + "update" + ], + "query": [ + { + "key": "commentId", + "value": "0", + "description": "id of a backlog item comment" + }, + { + "key": "comment", + "value": "\"New comment text\"", + "description": "The text for a comment" + } + ] + } + }, + "response": [] + }, + { + "name": "DeleteComment", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/backlog/comment/delete?commentId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "comment", + "delete" + ], + "query": [ + { + "key": "commentId", + "value": "0", + "description": "id of comment to be deleted" + } + ] + } + }, + "response": [] + }, + { + "name": "GetComment", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/backlog/comment/get?commentId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "comment", + "get" + ], + "query": [ + { + "key": "commentId", + "value": "0", + "description": "Id of comment we want to get" + } + ] + } + }, + "response": [] + } + ], + "description": "Endpoints for api of backlog item comments : /api/v1/backlog/comment", + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "BacklogItem", + "item": [ + { + "name": "GetById", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/backlog/item/get?id=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "item", + "get" + ], + "query": [ + { + "key": "id", + "value": "0", + "description": "id of a backlog item" + } + ] + } + }, + "response": [] + }, + { + "name": "UpdateBacklogItem", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"title\": \"The title of an backlog item\",\r\n \"description\": \"The description of a backlog item\",\r\n \"projectMemberId\": 0,\r\n \"sprintId\": 1,\r\n \"itemType\": \"TASK\", // STORY BUG TASK or EPIC\r\n \"itemStatus\": \"TODO\" // TODO IN_PROGRESS DONE\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ backendApiUrl }}/backlog/item/update?id=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "item", + "update" + ], + "query": [ + { + "key": "id", + "value": "0", + "description": "Item of a backlog item" + } + ] + } + }, + "response": [] + }, + { + "name": "DeleteById", + "request": { + "auth": { + "type": "jwt", + "jwt": [ + { + "key": "algorithm", + "value": "HS256", + "type": "string" + }, + { + "key": "isSecretBase64Encoded", + "value": false, + "type": "boolean" + }, + { + "key": "payload", + "value": "{}", + "type": "string" + }, + { + "key": "addTokenTo", + "value": "header", + "type": "string" + }, + { + "key": "headerPrefix", + "value": "Bearer", + "type": "string" + }, + { + "key": "queryParamKey", + "value": "token", + "type": "string" + }, + { + "key": "header", + "value": "{}", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/backlog/item/delete?id=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "item", + "delete" + ], + "query": [ + { + "key": "id", + "value": "0", + "description": "id of a backlog item to be deleted" + } + ] + } + }, + "response": [] + }, + { + "name": "CreateBacklogItem", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"title\": \"The title of an backlog item\",\r\n \"description\": \"The description of a backlog item\",\r\n \"projectMemberId\": 0,\r\n \"sprintId\": 1,\r\n \"itemType\": \"TASK\", // STORY BUG TASK or EPIC\r\n \"itemStatus\": \"TODO\" // TODO IN_PROGRESS DONE\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{ backendApiUrl }}/backlog/item/add", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "item", + "add" + ] + } + }, + "response": [] + }, + { + "name": "GetItemsBySprintId", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/backlog/item/getBySprint?sprintId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "item", + "getBySprint" + ], + "query": [ + { + "key": "sprintId", + "value": "0", + "description": "Id of a sprint backlog items to get" + } + ] + } + }, + "response": [] + }, + { + "name": "GetItemsByProjectId", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/backlog/item/getByProject?projectId=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "item", + "getByProject" + ], + "query": [ + { + "key": "projectId", + "value": "0", + "description": "Id of project to get backlog items of" + } + ] + } + }, + "response": [] + }, + { + "name": "GetItemDetailsById", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{jwt}}", + "type": "string" + } + ] + }, + "method": "GET", + "header": [], + "url": { + "raw": "{{ backendApiUrl }}/backlog/item/getDetails?id=0", + "host": [ + "{{ backendApiUrl }}" + ], + "path": [ + "backlog", + "item", + "getDetails" + ], + "query": [ + { + "key": "id", + "value": "0", + "description": "Get details of backlog item of this id" + } + ] + } + }, + "response": [] + } + ] + } + ], + "auth": { + "type": "bearer" + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": " backendApiUrl ", + "value": "http://localhost:8080/api/v1" + }, + { + "key": "jwt", + "value": "PlaceHereYourJwt" + } + ] +} \ No newline at end of file diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/comment/BacklogItemCommentControllerImpl.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/comment/BacklogItemCommentControllerImpl.java index 51b3c236..3dc12bd7 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/comment/BacklogItemCommentControllerImpl.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/comment/BacklogItemCommentControllerImpl.java @@ -7,7 +7,6 @@ import dev.corn.cornbackend.config.jwtprocessing.JwtAuthed; import dev.corn.cornbackend.entities.user.User; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/comment/constants/BacklogItemCommentMappings.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/comment/constants/BacklogItemCommentMappings.java index 22c2dcf3..88c12aa7 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/comment/constants/BacklogItemCommentMappings.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/comment/constants/BacklogItemCommentMappings.java @@ -2,7 +2,7 @@ public final class BacklogItemCommentMappings { - public static final String BACKLOG_ITEM_COMMENT_API_MAPPING = "/api/backlog/comment"; + public static final String BACKLOG_ITEM_COMMENT_API_MAPPING = "/api/v1/backlog/comment"; public static final String BACKLOG_ITEM_COMMENT_ADD_MAPPING = "/add"; public static final String BACKLOG_ITEM_COMMENT_UPDATE_MAPPING = "/update"; public static final String BACKLOG_ITEM_COMMENT_DELETE_MAPPING = "/delete"; diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/BacklogItemControllerImpl.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/BacklogItemControllerImpl.java index 84558f68..1f3ef620 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/BacklogItemControllerImpl.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/BacklogItemControllerImpl.java @@ -3,12 +3,12 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemDetails; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemRequest; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; +import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponseList; import dev.corn.cornbackend.api.backlog.item.interfaces.BacklogItemController; import dev.corn.cornbackend.api.backlog.item.interfaces.BacklogItemService; import dev.corn.cornbackend.config.jwtprocessing.JwtAuthed; import dev.corn.cornbackend.entities.user.User; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -74,9 +74,12 @@ public final List getBySprintId(@RequestParam long sprintId @Override @GetMapping(BACKLOG_ITEM_GET_BY_PROJECT_MAPPING) - public final List getByProjectId(@RequestParam long projectId, - @JwtAuthed User user) { - return backlogItemService.getByProjectId(projectId, user); + public final BacklogItemResponseList getByProjectId(@RequestParam long projectId, + @RequestParam int pageNumber, + @RequestParam String sortBy, + @RequestParam String order, + @JwtAuthed User user) { + return backlogItemService.getByProjectId(projectId, pageNumber, sortBy, order, user); } @Override diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/BacklogItemServiceImpl.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/BacklogItemServiceImpl.java index 36ad5752..646e8301 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/BacklogItemServiceImpl.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/BacklogItemServiceImpl.java @@ -3,10 +3,14 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemDetails; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemRequest; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; +import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponseList; +import dev.corn.cornbackend.api.backlog.item.enums.BacklogItemSortBy; import dev.corn.cornbackend.api.backlog.item.interfaces.BacklogItemService; import dev.corn.cornbackend.entities.backlog.comment.BacklogItemComment; +import dev.corn.cornbackend.entities.backlog.comment.interfaces.BacklogItemCommentRepository; import dev.corn.cornbackend.entities.backlog.item.BacklogItem; import dev.corn.cornbackend.entities.backlog.item.enums.ItemStatus; +import dev.corn.cornbackend.entities.backlog.item.enums.ItemType; import dev.corn.cornbackend.entities.backlog.item.interfaces.BacklogItemMapper; import dev.corn.cornbackend.entities.backlog.item.interfaces.BacklogItemRepository; import dev.corn.cornbackend.entities.project.Project; @@ -20,9 +24,15 @@ import dev.corn.cornbackend.utils.exceptions.project.ProjectDoesNotExistException; import dev.corn.cornbackend.utils.exceptions.project.member.ProjectMemberDoesNotExistException; import dev.corn.cornbackend.utils.exceptions.sprint.SprintNotFoundException; +import dev.corn.cornbackend.utils.exceptions.utils.WrongPageNumberException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.util.Collections; @@ -30,7 +40,9 @@ import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.BACKLOG_ITEM; import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.BACKLOG_ITEM_NOT_FOUND_MESSAGE; +import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.BACKLOG_ITEM_PAGE_SIZE; import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.GETTING_BY_ID; +import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.GETTING_BY_PROJECT; import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.PROJECT; import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.PROJECT_MEMBER; import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.PROJECT_MEMBER_NOT_FOUND_MESSAGE; @@ -40,20 +52,26 @@ import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.SAVING_AND_RETURNING_RESPONSE_OF; import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.SPRINT; import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.SPRINT_NOT_FOUND_MESSAGE; +import static dev.corn.cornbackend.entities.backlog.item.constants.BacklogItemConstants.BACKLOG_ITEM_ASSIGNEE_FIELD_NAME; +import static dev.corn.cornbackend.entities.project.member.constants.ProjectMemberConstants.PROJECT_MEMBER_USER_FIELD_NAME; +import static dev.corn.cornbackend.entities.user.constants.UserConstants.USER_NAME_FIELD_NAME; +import static dev.corn.cornbackend.entities.user.constants.UserConstants.USER_SURNAME_FIELD_NAME; + @Service -@RequiredArgsConstructor @Slf4j +@RequiredArgsConstructor public class BacklogItemServiceImpl implements BacklogItemService { private final BacklogItemRepository backlogItemRepository; + private final BacklogItemCommentRepository backlogItemCommentRepository; private final SprintRepository sprintRepository; private final ProjectRepository projectRepository; private final ProjectMemberRepository projectMemberRepository; private final BacklogItemMapper backlogItemMapper; @Override - public final BacklogItemResponse getById(long id, User user) { + public BacklogItemResponse getById(long id, User user) { log.info(GETTING_BY_ID, BACKLOG_ITEM, id); BacklogItem item = backlogItemRepository.findByIdWithProjectMember(id, user) @@ -65,7 +83,7 @@ public final BacklogItemResponse getById(long id, User user) { } @Override - public final BacklogItemResponse update(long id, BacklogItemRequest backlogItemRequest, User user) { + public BacklogItemResponse update(long id, BacklogItemRequest backlogItemRequest, User user) { log.info(GETTING_BY_ID, BACKLOG_ITEM, id); BacklogItem item = backlogItemRepository.findByIdWithProjectMember(id, user) @@ -83,12 +101,15 @@ public final BacklogItemResponse update(long id, BacklogItemRequest backlogItemR } @Override - public final BacklogItemResponse deleteById(long id, User user) { + @Transactional + public BacklogItemResponse deleteById(long id, User user) { log.info(GETTING_BY_ID, BACKLOG_ITEM, id); BacklogItem item = backlogItemRepository.findByIdWithProjectMember(id, user) .orElseThrow(() -> new BacklogItemNotFoundException(BACKLOG_ITEM_NOT_FOUND_MESSAGE)); + backlogItemCommentRepository.deleteByBacklogItem(item); + backlogItemRepository.deleteById(id); log.info(RETURNING_RESPONSE_OF, item); @@ -97,10 +118,11 @@ public final BacklogItemResponse deleteById(long id, User user) { } @Override - public final BacklogItemResponse create(BacklogItemRequest backlogItemRequest, User user) { + public BacklogItemResponse create(BacklogItemRequest backlogItemRequest, User user) { BacklogItemBuilderDto builder = prepareDataForBacklogItemCreation(backlogItemRequest, user); - BacklogItem item = buildNewBacklogItem(backlogItemRequest.title(), backlogItemRequest.description(), builder); + BacklogItem item = buildNewBacklogItem(backlogItemRequest.title(), backlogItemRequest.description(), + backlogItemRequest.itemType(), builder); log.info(SAVING_AND_RETURNING_RESPONSE_OF, item); @@ -110,7 +132,7 @@ public final BacklogItemResponse create(BacklogItemRequest backlogItemRequest, U } @Override - public final List getBySprintId(long sprintId, User user) { + public List getBySprintId(long sprintId, User user) { log.info(GETTING_BY_ID, SPRINT, sprintId); Sprint sprint = sprintRepository.findByIdWithProjectMember(sprintId, user) @@ -128,25 +150,48 @@ public final List getBySprintId(long sprintId, User user) { } @Override - public final List getByProjectId(long projectId, User user) { + public BacklogItemResponseList getByProjectId(long projectId, int pageNumber, String sortBy, + String order, User user) { + if(pageNumber < 0) { + throw new WrongPageNumberException(pageNumber); + } + + BacklogItemSortBy sort = BacklogItemSortBy.of(sortBy); + Sort.Direction direction = Sort.Direction.DESC.name().equalsIgnoreCase(order) ? + Sort.Direction.DESC : Sort.DEFAULT_DIRECTION; + + return getByProjectId(projectId, pageNumber, sort, direction, user); + } + + private BacklogItemResponseList getByProjectId(long projectId, int pageNumber, BacklogItemSortBy sortBy, + Sort.Direction order, User user) { log.info(GETTING_BY_ID, PROJECT, projectId); Project project = projectRepository.findByIdWithProjectMember(projectId, user) .orElseThrow(() -> new ProjectDoesNotExistException(PROJECT_NOT_FOUND_MESSAGE)); - log.info("Getting backlog items for project: {}", project); + Pageable pageRequest; - List items = backlogItemRepository.getByProject(project); + if(sortBy == BacklogItemSortBy.ASSIGNEE) { + pageRequest = getPageableForAssignee(pageNumber, order); + } else { + pageRequest = PageRequest.of(pageNumber, BACKLOG_ITEM_PAGE_SIZE, Sort.by(order, + sortBy.getValue())); + } - log.info(RETURNING_BACKLOG_ITEMS_OF_QUANTITY, items.size()); + log.info(GETTING_BY_PROJECT, project, sortBy.getValue(), order); + Page items = backlogItemRepository.getByProject(project, pageRequest); - return items.stream() - .map(backlogItemMapper::backlogItemToBacklogItemResponse) - .toList(); + return BacklogItemResponseList.builder() + .backlogItemResponseList(items.stream() + .map(backlogItemMapper::backlogItemToBacklogItemResponse) + .toList()) + .totalNumber(items.getTotalElements()) + .build(); } @Override - public final BacklogItemDetails getDetailsById(long id, User user) { + public BacklogItemDetails getDetailsById(long id, User user) { log.info(GETTING_BY_ID, BACKLOG_ITEM, id); BacklogItem backlogItem = backlogItemRepository.findByIdWithProjectMember(id, user) @@ -196,15 +241,33 @@ private BacklogItem buildUpdatedBacklogItem(long id, BacklogItemBuilderDto build .build(); } - private BacklogItem buildNewBacklogItem(String title, String description, BacklogItemBuilderDto builder) { + private BacklogItem buildNewBacklogItem(String title, String description, ItemType itemType, BacklogItemBuilderDto builder) { return BacklogItem.builder() .title(title) .description(description) .comments(Collections.emptyList()) .status(ItemStatus.TODO) + .itemType(itemType) .assignee(builder.assignee()) .sprint(builder.sprint()) .project(builder.project()) .build(); } + + + private Pageable getPageableForAssignee(int pageNumber, Sort.Direction direction) { + Sort sorting = Sort.by( + new Sort.Order(direction, String.format("%s.%s.%s", + BACKLOG_ITEM_ASSIGNEE_FIELD_NAME, + PROJECT_MEMBER_USER_FIELD_NAME, + USER_SURNAME_FIELD_NAME)), + new Sort.Order(direction, String.format("%s.%s.%s", + BACKLOG_ITEM_ASSIGNEE_FIELD_NAME, + PROJECT_MEMBER_USER_FIELD_NAME, + USER_NAME_FIELD_NAME)) + ); + + return PageRequest.of(pageNumber, BACKLOG_ITEM_PAGE_SIZE, sorting); + + } } diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/constants/BacklogItemMappings.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/constants/BacklogItemMappings.java index acac5db0..cd2dc175 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/constants/BacklogItemMappings.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/constants/BacklogItemMappings.java @@ -2,7 +2,7 @@ public class BacklogItemMappings { - public static final String BACKLOG_ITEM_API_MAPPING = "/api/backlog/item"; + public static final String BACKLOG_ITEM_API_MAPPING = "/api/v1/backlog/item"; public static final String BACKLOG_ITEM_ADD_MAPPING = "/add"; public static final String BACKLOG_ITEM_UPDATE_MAPPING = "/update"; public static final String BACKLOG_ITEM_DELETE_MAPPING = "/delete"; diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/constants/BacklogItemServiceConstants.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/constants/BacklogItemServiceConstants.java index 1ca9e6d4..356b2907 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/constants/BacklogItemServiceConstants.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/constants/BacklogItemServiceConstants.java @@ -14,6 +14,9 @@ public final class BacklogItemServiceConstants { public static final String PROJECT = "Project"; public static final String RETURNING_BACKLOG_ITEMS_OF_QUANTITY = "Returning backlog items of quantity: {}"; public static final String SAVING_AND_RETURNING_RESPONSE_OF = "Saving and returning response of: {}"; + public static final String GETTING_BY_PROJECT = "Getting backlog items for project: {}, sorting by: {}, order: {}"; + + public static final int BACKLOG_ITEM_PAGE_SIZE = 30; private BacklogItemServiceConstants() { diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/data/BacklogItemResponse.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/data/BacklogItemResponse.java index 72cf33d7..9a80bc7e 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/data/BacklogItemResponse.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/data/BacklogItemResponse.java @@ -4,6 +4,6 @@ import lombok.Builder; @Builder -public record BacklogItemResponse(String title, String description, String status, UserResponse assignee, - String itemType, String taskFinishDate) { +public record BacklogItemResponse(long backlogItemId, String title, String description, String status, UserResponse assignee, + String itemType, String taskFinishDate, long projectId, long sprintId) { } diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/data/BacklogItemResponseList.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/data/BacklogItemResponseList.java new file mode 100644 index 00000000..7de08df4 --- /dev/null +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/data/BacklogItemResponseList.java @@ -0,0 +1,8 @@ +package dev.corn.cornbackend.api.backlog.item.data; + +import lombok.Builder; + +import java.util.List; + +@Builder +public record BacklogItemResponseList(List backlogItemResponseList, long totalNumber) {} diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/enums/BacklogItemSortBy.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/enums/BacklogItemSortBy.java new file mode 100644 index 00000000..659297d4 --- /dev/null +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/enums/BacklogItemSortBy.java @@ -0,0 +1,31 @@ +package dev.corn.cornbackend.api.backlog.item.enums; + +import lombok.Getter; + +import static dev.corn.cornbackend.entities.backlog.item.constants.BacklogItemConstants.BACKLOG_ITEM_ASSIGNEE_FIELD_NAME; +import static dev.corn.cornbackend.entities.backlog.item.constants.BacklogItemConstants.BACKLOG_ITEM_STATUS_FIELD_NAME; +import static dev.corn.cornbackend.entities.backlog.item.constants.BacklogItemConstants.BACKLOG_ITEM_TYPE_FIELD_NAME; + +@Getter +public enum BacklogItemSortBy { + ASSIGNEE (BACKLOG_ITEM_ASSIGNEE_FIELD_NAME), + ITEM_TYPE (BACKLOG_ITEM_TYPE_FIELD_NAME), + STATUS (BACKLOG_ITEM_STATUS_FIELD_NAME); + + private final String value; + BacklogItemSortBy(String value) { + this.value = value; + } + + public static BacklogItemSortBy of(String value) { + return switch((value != null) ? value : BACKLOG_ITEM_STATUS_FIELD_NAME) { + case BACKLOG_ITEM_ASSIGNEE_FIELD_NAME -> BacklogItemSortBy.ASSIGNEE; + case BACKLOG_ITEM_TYPE_FIELD_NAME -> BacklogItemSortBy.ITEM_TYPE; + default -> defaultValue(); + }; + } + + private static BacklogItemSortBy defaultValue() { + return BacklogItemSortBy.STATUS; + } +} diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/interfaces/BacklogItemController.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/interfaces/BacklogItemController.java index a8cae46a..d151df2b 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/interfaces/BacklogItemController.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/interfaces/BacklogItemController.java @@ -3,6 +3,7 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemDetails; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemRequest; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; +import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponseList; import dev.corn.cornbackend.entities.user.User; import java.util.List; @@ -49,7 +50,7 @@ public interface BacklogItemController { BacklogItemResponse create(BacklogItemRequest backlogItemRequest, User user); /** - * Get backlog items by sprint id + * Get backlog items by sprint id on given page * * @param sprintId id of the sprint * @param user user to get the backlog items for @@ -61,10 +62,11 @@ public interface BacklogItemController { * Get backlog items by project id * * @param projectId id of the project + * @param pageNumber number of page * @param user user to get the backlog items for * @return the backlog items */ - List getByProjectId(long projectId, User user); + BacklogItemResponseList getByProjectId(long projectId, int pageNumber, String sortBy, String order, User user); /** * Get backlog item details by id diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/interfaces/BacklogItemService.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/interfaces/BacklogItemService.java index b7b7c1c0..3895f1a2 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/interfaces/BacklogItemService.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/backlog/item/interfaces/BacklogItemService.java @@ -3,6 +3,7 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemDetails; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemRequest; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; +import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponseList; import dev.corn.cornbackend.entities.user.User; import java.util.List; @@ -64,7 +65,7 @@ public interface BacklogItemService { * @param projectId id of the project * @return response with the list of backlog items */ - List getByProjectId(long projectId, User user); + BacklogItemResponseList getByProjectId(long projectId, int pageNumber, String sortBy, String order, User user); /** * Get backlog item details by id diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/project/member/constants/ProjectMemberMappings.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/project/member/constants/ProjectMemberMappings.java index 9bde22ac..94986a01 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/project/member/constants/ProjectMemberMappings.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/project/member/constants/ProjectMemberMappings.java @@ -1,7 +1,7 @@ package dev.corn.cornbackend.api.project.member.constants; public final class ProjectMemberMappings { - public static final String PROJECT_MEMBER_MAPPING = "/api/project/assignee"; + public static final String PROJECT_MEMBER_MAPPING = "/api/v1/project/assignee"; public static final String ADD_MEMBER_TO_PROJECT_MAPPING = "/addMember"; diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintServiceImpl.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintServiceImpl.java index 6e250f4d..ef198116 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintServiceImpl.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/SprintServiceImpl.java @@ -81,7 +81,7 @@ public final List getSprintsOnPage(int page, long projectId, Use Page sprints = sprintRepository.findAllByProjectId(projectId, user, pageable); - log.info("Sprints found on page : {}", sprints.getTotalElements()); + log.info("Sprints found on page : {}", sprints.getNumberOfElements()); return sprints.map(sprintMapper::toSprintResponse).toList(); } diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintController.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintController.java index 72edfecd..391736f7 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintController.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintController.java @@ -2,7 +2,6 @@ import dev.corn.cornbackend.api.sprint.data.SprintRequest; import dev.corn.cornbackend.api.sprint.data.SprintResponse; -import dev.corn.cornbackend.entities.project.Project; import dev.corn.cornbackend.entities.user.User; import java.time.LocalDate; diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintService.java b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintService.java index f5806ba3..090cf77d 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintService.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/api/sprint/interfaces/SprintService.java @@ -2,7 +2,6 @@ import dev.corn.cornbackend.api.sprint.data.SprintRequest; import dev.corn.cornbackend.api.sprint.data.SprintResponse; -import dev.corn.cornbackend.entities.project.Project; import dev.corn.cornbackend.entities.user.User; import java.time.LocalDate; diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/config/PlaceholderData.java b/corn-backend/src/main/java/dev/corn/cornbackend/config/PlaceholderData.java new file mode 100644 index 00000000..23be0264 --- /dev/null +++ b/corn-backend/src/main/java/dev/corn/cornbackend/config/PlaceholderData.java @@ -0,0 +1,217 @@ +package dev.corn.cornbackend.config; + +import dev.corn.cornbackend.api.backlog.comment.data.BacklogItemCommentRequest; +import dev.corn.cornbackend.api.backlog.comment.interfaces.BacklogItemCommentService; +import dev.corn.cornbackend.api.project.interfaces.ProjectService; +import dev.corn.cornbackend.api.project.member.interfaces.ProjectMemberService; +import dev.corn.cornbackend.api.sprint.data.SprintRequest; +import dev.corn.cornbackend.api.sprint.interfaces.SprintService; +import dev.corn.cornbackend.api.user.interfaces.UserService; +import dev.corn.cornbackend.entities.backlog.item.BacklogItem; +import dev.corn.cornbackend.entities.backlog.item.enums.ItemStatus; +import dev.corn.cornbackend.entities.backlog.item.enums.ItemType; +import dev.corn.cornbackend.entities.backlog.item.interfaces.BacklogItemRepository; +import dev.corn.cornbackend.entities.project.Project; +import dev.corn.cornbackend.entities.project.interfaces.ProjectRepository; +import dev.corn.cornbackend.entities.project.member.ProjectMember; +import dev.corn.cornbackend.entities.project.member.interfaces.ProjectMemberRepository; +import dev.corn.cornbackend.entities.sprint.Sprint; +import dev.corn.cornbackend.entities.sprint.interfaces.SprintRepository; +import dev.corn.cornbackend.entities.user.User; +import dev.corn.cornbackend.entities.user.data.UserResponse; +import dev.corn.cornbackend.entities.user.interfaces.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.CommandLineRunner; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.domain.Pageable; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Random; +import java.util.stream.Stream; + +@Configuration +@RequiredArgsConstructor +public class PlaceholderData implements CommandLineRunner { + + private final UserService userService; + private final UserRepository userRepository; + private final SprintService sprintService; + private final SprintRepository sprintRepository; + private final ProjectService projectService; + private final ProjectRepository projectRepository; + private final BacklogItemRepository backlogItemRepository; + private final BacklogItemCommentService backlogItemCommentService; + private final ProjectMemberService projectMemberService; + private final ProjectMemberRepository projectMemberRepository; + private final Random random = new Random(0); + + @Value("${CREATE_PLACEHOLDER_DATA:false}") + private String CREATE_PLACEHOLDER_DATA; + + @Override + public void run(String... args) { + if (!"true".equalsIgnoreCase(CREATE_PLACEHOLDER_DATA)) { + return; + } + List typesPool = List.of( + ItemType.TASK, ItemType.TASK, ItemType.TASK, ItemType.BUG, + ItemType.TASK, ItemType.TASK, ItemType.TASK, ItemType.BUG, + ItemType.BUG, ItemType.EPIC, ItemType.STORY + ); + List statusesPool = List.of( + ItemStatus.TODO, ItemStatus.TODO, ItemStatus.TODO, ItemStatus.TODO, + ItemStatus.IN_PROGRESS, ItemStatus.IN_PROGRESS, + ItemStatus.DONE, ItemStatus.DONE, ItemStatus.DONE + ); + List users = userRepository.findAllById(Stream.of( + userService.registerUser("Jan", "Kowalski", "jan"), + userService.registerUser("Andrzej", "Switch", "andrzej"), + userService.registerUser("John", "Doe", "john"), + userService.registerUser("Jane", "Doe", "jane"), + userService.registerUser("Alice", "Smith", "alice"), + userService.registerUser("Bob", "Johnson", "bob") + ).map(UserResponse::userId).toList()); + + User projectOwner = drawRandom(users); + projectService.addNewProject("Sample Project", projectOwner); + Project project = projectRepository.findAllByOwnerOrderByName(projectOwner, Pageable.ofSize(1)) + .stream().findFirst().get(); + + users.stream() + .filter(user -> user.getUserId() != projectOwner.getUserId()) + .forEach(user -> + projectMemberService.addMemberToProject(user.getUsername(), project.getProjectId(), projectOwner) + ); + + List members = projectMemberRepository.findAll(); + + for(int i = 0; i < 30; i++) { + sprintService.addNewSprint(new SprintRequest( + project.getProjectId(), String.format("Sprint %d", i), LocalDate.now(), LocalDate.now().plusDays(7), + String.format("Sprintd %d description", i) + ), projectOwner); + } + + List allSprints = sprintRepository.findAll(); + + List backlogItems = Arrays.stream(SAMPLE_BACKLOG_ITEMS) + .map(item -> new BacklogItem(0, + item[0], item[1], + drawRandom(statusesPool), + LocalDate.now().plusDays(random.nextInt(14)), + Collections.emptyList(), + drawRandom(members), + drawRandom(allSprints), + project, + drawRandom(typesPool) + )).map(backlogItemRepository::save).toList(); + + for (int i = 0; i < SAMPLE_BACKLOG_ITEMS.length / 4; i++) { + for (int j = 0; j < random.nextInt(4); j++) { + long backlogItemId = drawRandom(backlogItems).getBacklogItemId(); + User commenter = drawRandom(users); + backlogItemCommentService.addNewComment(new BacklogItemCommentRequest( + drawRandom(SAMPLE_COMMENTS), backlogItemId + ), commenter); + } + } + } + + private T drawRandom(List list) { + ArrayList tmp = new ArrayList<>(list); + Collections.shuffle(tmp, random); + return tmp.get(0); + } + + private final String[][] SAMPLE_BACKLOG_ITEMS = { + {"Develop Feature X", "Implement and test the new feature X to enhance user experience."}, + {"Fix Bug in Login Module", "Investigate and resolve the login module bug reported by users."}, + {"Refactor Database Access", "Optimize database access code for better performance and maintainability."}, + {"Create User Dashboard", "Design and implement a user dashboard for monitoring key metrics."}, + {"Update UI Styling", "Apply updated styling to improve the overall look and feel of the application."}, + {"Implement Notification System", "Create a system for sending notifications to users based on their preferences."}, + {"Add Multi-language Support", "Integrate multi-language support for the application."}, + {"Optimize Image Loading", "Improve the efficiency of image loading for a smoother user experience."}, + {"Integrate Payment Gateway", "Connect the application with a payment gateway for processing transactions."}, + {"Enhance Search Functionality", "Improve the search feature to provide more accurate and relevant results."}, + {"Upgrade Server Infrastructure", "Upgrade the server infrastructure to handle increased traffic and improve scalability."}, + {"Implement OAuth Authentication", "Integrate OAuth for secure and convenient user authentication."}, + {"Design and Implement Chat Feature", "Create a real-time chat feature for users to communicate within the application."}, + {"Improve Error Handling", "Enhance error handling to provide clearer messages and improve user experience."}, + {"Upgrade Third-party Libraries", "Update third-party libraries to the latest versions for security and performance benefits."}, + {"Create Mobile Responsive Design", "Optimize the application's design for a seamless experience on mobile devices."}, + {"Implement Two-Factor Authentication", "Enhance security by implementing two-factor authentication for user accounts."}, + {"Add Social Media Sharing", "Integrate social media sharing functionality to allow users to share content."}, + {"Optimize Backend API Calls", "Optimize backend API calls to reduce response times and improve overall performance."}, + {"Implement User Permissions", "Create a system for managing user permissions and roles within the application."}, + {"Improve Accessibility", "Enhance accessibility features to ensure the application is usable by people with disabilities."}, + {"Create Onboarding Tutorial", "Design and implement a tutorial to guide new users through the application."}, + {"Implement Automated Testing", "Introduce automated testing to ensure code reliability and catch bugs early."}, + {"Upgrade Data Encryption", "Enhance data encryption protocols to strengthen overall data security."}, + {"Implement Dark Mode", "Add a dark mode option for users who prefer a darker color scheme."}, + {"Integrate Analytics Tracking", "Implement analytics tracking to gather insights into user behavior and application usage."}, + {"Enhance File Upload Functionality", "Improve file upload features for a more seamless user experience."}, + {"Update Terms of Service", "Review and update the application's terms of service for legal compliance."}, + {"Implement User Profile Customization", "Allow users to customize their profiles with additional information and preferences."}, + {"Create In-App Notifications", "Develop a system for in-app notifications to keep users informed of important updates."}, + {"Improve Data Validation", "Enhance data validation to ensure the accuracy and integrity of user-inputted information."}, + {"Implement Geolocation Features", "Integrate geolocation features for location-based services within the application."}, + {"Upgrade Frontend Framework", "Update the frontend framework to leverage the latest features and improvements."}, + {"Optimize Database Indexing", "Improve database indexing to enhance query performance."}, + {"Implement Auto-Save Drafts", "Create an auto-save feature for drafts to prevent data loss."}, + {"Integrate Video Streaming", "Add video streaming capabilities for multimedia content."}, + {"Improve Email Notification System", "Enhance the email notification system for timely and reliable communications."}, + {"Implement User Surveys", "Introduce user surveys to gather feedback and improve user satisfaction."}, + {"Upgrade Password Security", "Enhance password security measures to protect user accounts."}, + {"Create Admin Dashboard", "Develop a dashboard for administrators to manage and monitor the application."}, + {"Implement Cross-Browser Compatibility", "Ensure the application functions smoothly across different web browsers."}, + {"Enhance Data Backup Mechanism", "Improve the data backup mechanism to prevent data loss in case of failures."}, + {"Create Interactive Data Visualizations", "Implement interactive data visualizations for better data understanding."}, + {"Optimize Mobile App Performance", "Optimize performance for the mobile app version of the application."}, + {"Implement Gamification Elements", "Introduce gamification elements to enhance user engagement."}, + {"Upgrade SSL/TLS Certificates", "Renew and update SSL/TLS certificates for secure data transmission."}, + {"Improve Documentation", "Enhance documentation for developers and end-users for better understanding."}, + }; + + private final List SAMPLE_COMMENTS = List.of( + "Good progress on Feature X. Keep it up!", + "Facing issues with the login bug. Need more details to proceed.", + "The database refactor looks promising. Any specific challenges?", + "User dashboard design approved. Start implementation phase.", + "The updated UI styling is a great improvement. Nice work!", + "Feature X implementation completed. Ready for testing.", + "Resolved the login module bug. Testing required for verification.", + "Database access code optimized successfully.", + "User dashboard backend logic implemented. Frontend in progress.", + "UI styling adjustments made based on user feedback.", + "Feature X testing phase started. Report any issues.", + "Login module bug fix verified. Ready for deployment.", + "Database access refactor reviewed and approved.", + "User dashboard frontend progress update: 50% complete.", + "Updated UI styling adjustments based on team feedback.", + "Feature X passed initial testing. Few minor tweaks needed.", + "Login module bug fix deployed to production successfully.", + "Database access refactor performance testing underway.", + "User dashboard frontend completed. Backend integration in progress.", + "Final UI styling changes approved. Ready for production.", + "Feature X officially released. Communicate to users.", + "Login module bug fix confirmed resolved. No reported issues.", + "Database access refactor performance results positive.", + "User dashboard integration complete. Testing phase initiated.", + "Positive user feedback on the new UI styling. Well done!", + "Feature X documentation updated. Notify documentation team.", + "Login module bug fix documentation reviewed. Ready for publishing.", + "Database access refactor documentation in progress.", + "User dashboard documentation initiated. Collaboration with tech writers.", + "UI styling documentation updated. Check for accuracy.", + "Feature X success metrics meeting scheduled. Prepare data.", + "Login module bug fix success metrics reviewed. Positive impact noted.", + "Database access refactor success metrics written." + ); + +} diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/comment/interfaces/BacklogItemCommentRepository.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/comment/interfaces/BacklogItemCommentRepository.java index 7edeac64..c2fc3307 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/comment/interfaces/BacklogItemCommentRepository.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/comment/interfaces/BacklogItemCommentRepository.java @@ -1,6 +1,7 @@ package dev.corn.cornbackend.entities.backlog.comment.interfaces; import dev.corn.cornbackend.entities.backlog.comment.BacklogItemComment; +import dev.corn.cornbackend.entities.backlog.item.BacklogItem; import dev.corn.cornbackend.entities.user.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -43,4 +44,6 @@ public interface BacklogItemCommentRepository extends JpaRepository findByIdWithProjectMember(@Param ("id") long id, @Param("user") User user); + + void deleteByBacklogItem(BacklogItem backlogItem); } diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/constants/BacklogItemConstants.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/constants/BacklogItemConstants.java index a2916976..94f473c7 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/constants/BacklogItemConstants.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/constants/BacklogItemConstants.java @@ -14,6 +14,7 @@ public final class BacklogItemConstants { public static final String BACKLOG_ITEM_STATUS_NULL_MSG = "Item status cannot be null"; public static final String BACKLOG_ITEM_TYPE_NULL_MSG = "Item type cannot be null"; + public static final String BACKLOG_ITEM_TYPE_FIELD_NAME = "itemType"; public static final String BACKLOG_ITEM_STATUS_FIELD_NAME = "status"; public static final String BACKLOG_ITEM_COMMENTS_NULL_ELEMENTS_MSG = "Comments cannot be null nor contain null elements"; diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/interfaces/BacklogItemMapper.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/interfaces/BacklogItemMapper.java index 8f409a95..37fdcde4 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/interfaces/BacklogItemMapper.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/interfaces/BacklogItemMapper.java @@ -3,7 +3,6 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemDetails; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; import dev.corn.cornbackend.entities.backlog.item.BacklogItem; -import dev.corn.cornbackend.entities.project.interfaces.ProjectMapper; import dev.corn.cornbackend.entities.project.member.ProjectMember; import dev.corn.cornbackend.entities.project.member.ProjectMemberMapperImpl; import dev.corn.cornbackend.entities.project.member.interfaces.ProjectMemberMapper; @@ -23,6 +22,8 @@ public interface BacklogItemMapper { * @param backlogItem The BacklogItem to map. * @return The mapped BacklogItemResponse. */ + @Mapping(target="projectId", expression="java(backlogItem.getProject().getProjectId())") + @Mapping(target="sprintId", expression="java(backlogItem.getSprint().getSprintId())") BacklogItemResponse backlogItemToBacklogItemResponse(BacklogItem backlogItem); /** diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/interfaces/BacklogItemRepository.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/interfaces/BacklogItemRepository.java index 16ad5e73..50d084bf 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/interfaces/BacklogItemRepository.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/backlog/item/interfaces/BacklogItemRepository.java @@ -4,6 +4,8 @@ import dev.corn.cornbackend.entities.project.Project; import dev.corn.cornbackend.entities.sprint.Sprint; import dev.corn.cornbackend.entities.user.User; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -29,12 +31,13 @@ public interface BacklogItemRepository extends JpaRepository * Finds all BacklogItems associated with a Project * * @param project Project to find BacklogItems for + * @param pageable Pageable that pages and sorts the data * @return List of BacklogItems associated with the Project */ - List getByProject(Project project); + Page getByProject(Project project, Pageable pageable); /** - * Finds a BacklogItem by id and checks if the user is a assignee or the owner of the project associated + * Finds a BacklogItem by id and checks if the user is an assignee or the owner of the project associated * with the BacklogItem * @param id id of BacklogItem * @param user user requesting access diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/project/member/ProjectMember.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/project/member/ProjectMember.java index 68f38391..c9cae9d4 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/project/member/ProjectMember.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/project/member/ProjectMember.java @@ -4,7 +4,6 @@ import dev.corn.cornbackend.entities.project.Project; import dev.corn.cornbackend.entities.project.member.constants.ProjectMemberConstants; import dev.corn.cornbackend.entities.user.User; -import dev.corn.cornbackend.entities.user.data.UserResponse; import dev.corn.cornbackend.utils.json.JsonMapper; import dev.corn.cornbackend.utils.json.interfaces.Jsonable; import dev.corn.cornbackend.utils.validators.interfaces.NoNullElements; diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/project/member/constants/ProjectMemberConstants.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/project/member/constants/ProjectMemberConstants.java index f338f595..9f888aba 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/project/member/constants/ProjectMemberConstants.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/project/member/constants/ProjectMemberConstants.java @@ -11,6 +11,7 @@ public final class ProjectMemberConstants { public static final String PROJECT_MEMBER_USER_NULL_MSG = "User cannot be null"; + private ProjectMemberConstants() { } diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/Sprint.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/Sprint.java index e0a8824f..59a03437 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/Sprint.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/sprint/Sprint.java @@ -25,7 +25,6 @@ import org.hibernate.proxy.HibernateProxy; import java.time.LocalDate; -import java.util.Objects; @Entity @Getter diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/entities/user/User.java b/corn-backend/src/main/java/dev/corn/cornbackend/entities/user/User.java index 7b83d5f0..d23fc56a 100644 --- a/corn-backend/src/main/java/dev/corn/cornbackend/entities/user/User.java +++ b/corn-backend/src/main/java/dev/corn/cornbackend/entities/user/User.java @@ -23,7 +23,6 @@ import java.util.Collection; import java.util.Collections; -import java.util.Objects; @Entity @Builder diff --git a/corn-backend/src/main/java/dev/corn/cornbackend/utils/exceptions/utils/WrongPageNumberException.java b/corn-backend/src/main/java/dev/corn/cornbackend/utils/exceptions/utils/WrongPageNumberException.java new file mode 100644 index 00000000..87148f1f --- /dev/null +++ b/corn-backend/src/main/java/dev/corn/cornbackend/utils/exceptions/utils/WrongPageNumberException.java @@ -0,0 +1,18 @@ +package dev.corn.cornbackend.utils.exceptions.utils; + +import dev.corn.cornbackend.utils.exceptions.AbstractException; +import org.springframework.http.HttpStatus; + +import java.io.Serial; + +public class WrongPageNumberException extends AbstractException { + + @Serial + private static final long serialVersionUID = 6996570131474872845L; + + private static final String DEFAULT_MESSAGE = "Incorrect page number: %d"; + + public WrongPageNumberException(int pageNumber) { + super(HttpStatus.BAD_REQUEST, String.format(DEFAULT_MESSAGE, pageNumber)); + } +} diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/comment/BacklogItemCommentServiceImplTest.java b/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/comment/BacklogItemCommentServiceImplTest.java index 4b0f4a2c..dbb3df3f 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/comment/BacklogItemCommentServiceImplTest.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/comment/BacklogItemCommentServiceImplTest.java @@ -4,12 +4,9 @@ import dev.corn.cornbackend.entities.backlog.comment.interfaces.BacklogItemCommentMapper; import dev.corn.cornbackend.entities.backlog.comment.interfaces.BacklogItemCommentRepository; import dev.corn.cornbackend.entities.backlog.item.interfaces.BacklogItemRepository; -import dev.corn.cornbackend.entities.user.User; import dev.corn.cornbackend.test.backlog.item.comment.BacklogItemCommentTestDataBuilder; import dev.corn.cornbackend.test.backlog.item.comment.data.BacklogItemCommentTestData; import dev.corn.cornbackend.test.backlog.item.comment.data.UpdateBacklogItemCommentTestData; -import dev.corn.cornbackend.test.backlog.item.data.UpdateBacklogItemTestData; -import dev.corn.cornbackend.test.user.UserTestDataBuilder; import dev.corn.cornbackend.utils.exceptions.backlog.item.BacklogItemNotFoundException; import dev.corn.cornbackend.utils.exceptions.backlog.item.comment.BacklogItemCommentNotFoundException; import org.junit.jupiter.api.Test; diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/item/BacklogItemControllerImplTest.java b/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/item/BacklogItemControllerImplTest.java index ba0725b8..7752d3d7 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/item/BacklogItemControllerImplTest.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/item/BacklogItemControllerImplTest.java @@ -2,6 +2,7 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemDetails; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; +import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponseList; import dev.corn.cornbackend.api.backlog.item.interfaces.BacklogItemService; import dev.corn.cornbackend.entities.user.User; import dev.corn.cornbackend.test.backlog.item.BacklogItemTestDataBuilder; @@ -119,15 +120,18 @@ final void test_getBySprintIdShouldReturnCorrectBacklogItemResponse() { final void test_getByProjectIdShouldReturnCorrectBacklogItemResponse() { //given long projectId = 1L; + int pageNumber = 0; + String sortBy = ""; + String orderBy = ""; //when - when(backlogItemService.getByProjectId(projectId, SAMPLE_USER)) - .thenReturn(BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponses()); + when(backlogItemService.getByProjectId(projectId, pageNumber, sortBy, orderBy, SAMPLE_USER)) + .thenReturn(BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponseList()); - List expected = BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponses(); + BacklogItemResponseList expected = BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponseList(); //then - assertEquals(expected, backlogItemController.getByProjectId(projectId, SAMPLE_USER), + assertEquals(expected, backlogItemController.getByProjectId(projectId, pageNumber, sortBy, orderBy, SAMPLE_USER), SHOULD_RETURN_CORRECT_BACKLOG_ITEM_RESPONSE); } diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/item/BacklogItemServiceImplTest.java b/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/item/BacklogItemServiceImplTest.java index d71c03e1..10b3f490 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/item/BacklogItemServiceImplTest.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/api/backlog/item/BacklogItemServiceImplTest.java @@ -3,6 +3,9 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemDetails; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemRequest; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; +import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponseList; +import dev.corn.cornbackend.api.backlog.item.enums.BacklogItemSortBy; +import dev.corn.cornbackend.entities.backlog.comment.interfaces.BacklogItemCommentRepository; import dev.corn.cornbackend.entities.backlog.item.enums.ItemStatus; import dev.corn.cornbackend.entities.backlog.item.interfaces.BacklogItemMapper; import dev.corn.cornbackend.entities.backlog.item.interfaces.BacklogItemRepository; @@ -21,15 +24,24 @@ import dev.corn.cornbackend.utils.exceptions.project.ProjectDoesNotExistException; import dev.corn.cornbackend.utils.exceptions.project.member.ProjectMemberDoesNotExistException; import dev.corn.cornbackend.utils.exceptions.sprint.SprintNotFoundException; +import dev.corn.cornbackend.utils.exceptions.utils.WrongPageNumberException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import java.util.List; import java.util.Optional; +import static dev.corn.cornbackend.api.backlog.item.constants.BacklogItemServiceConstants.BACKLOG_ITEM_PAGE_SIZE; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -53,6 +65,8 @@ class BacklogItemServiceImplTest { private ProjectMemberRepository projectMemberRepository; @Mock private BacklogItemMapper backlogItemMapper; + @Mock + private BacklogItemCommentRepository backlogItemCommentRepository; private final AddBacklogItemTestData BACKLOG_ITEM_TEST_DATA = BacklogItemTestDataBuilder.addBacklogItemTestData(); private final EntityData ENTITY_DATA = BacklogItemTestDataBuilder.entityData(); @@ -405,13 +419,17 @@ final void getBySprintId_shouldThrowSprintNotFoundExceptionOnIncorrectId() { final void getByProjectId_shouldReturnCorrectBacklogItemListResponseOnCorrectId() { //given long id = 1L; + int pageNumber = 0; + String sortBy = "status"; + String order = "ASC"; + Pageable pageable = PageRequest.of(pageNumber, 30, Sort.Direction.ASC, sortBy); //when when(projectRepository.findByIdWithProjectMember(id, SAMPLE_USER)) .thenReturn(Optional.of(ENTITY_DATA.project())); - when(backlogItemRepository.getByProject(ENTITY_DATA.project())) - .thenReturn(BACKLOG_ITEM_LIST_TEST_DATA.backlogItems()); + when(backlogItemRepository.getByProject(ENTITY_DATA.project(), pageable)) + .thenReturn(new PageImpl<>(BACKLOG_ITEM_LIST_TEST_DATA.backlogItems())); when(backlogItemMapper.backlogItemToBacklogItemResponse(BACKLOG_ITEM_LIST_TEST_DATA.backlogItems().get(0))) .thenReturn(BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponses().get(0)); @@ -419,10 +437,10 @@ final void getByProjectId_shouldReturnCorrectBacklogItemListResponseOnCorrectId( when(backlogItemMapper.backlogItemToBacklogItemResponse(BACKLOG_ITEM_LIST_TEST_DATA.backlogItems().get(1))) .thenReturn(BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponses().get(1)); - List expected = BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponses(); + BacklogItemResponseList expected = BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponseList(); //then - assertEquals(expected, backlogItemServiceImpl.getByProjectId(id, SAMPLE_USER), + assertEquals(expected, backlogItemServiceImpl.getByProjectId(id, pageNumber, sortBy, order, SAMPLE_USER), SHOULD_RETURN_CORRECT_BACKLOG_ITEM_RESPONSE_LIST); } @@ -430,16 +448,64 @@ final void getByProjectId_shouldReturnCorrectBacklogItemListResponseOnCorrectId( final void getByProjectId_shouldThrowProjectNotFoundExceptionOnIncorrectId() { //given long id = -1L; + int pageNumber = 0; + String sortBy = ""; + String order = ""; //when when(projectRepository.findByIdWithProjectMember(id, SAMPLE_USER)) .thenReturn(Optional.empty()); //then - assertThrows(ProjectDoesNotExistException.class, () -> backlogItemServiceImpl.getByProjectId(id, SAMPLE_USER), + assertThrows(ProjectDoesNotExistException.class, () -> backlogItemServiceImpl.getByProjectId(id, pageNumber, + sortBy, order, SAMPLE_USER), String.format(SHOULD_THROW, ProjectDoesNotExistException.class.getSimpleName())); } + @Test + final void getByProjectId_shouldThrowExceptionWhenGivenPageNumberIsNegative() { + //given + long id = 1L; + int pageNumber = -1; + String sortBy = ""; + String order = ""; + + //then + assertThrows(WrongPageNumberException.class, () -> backlogItemServiceImpl.getByProjectId( + id, pageNumber, sortBy, order, SAMPLE_USER), + String.format(SHOULD_THROW, WrongPageNumberException.class.getSimpleName())); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {"abab"}) + final void getByProjectId_shouldCallDatabaseWithDefaultValuesAndReturnCorrectBacklogItemsWhenGivenSortByOrOrderIsNullOrIncorrect(String value) { + //given + long id = 1L; + int pageNumber = 0; + Pageable pageable = PageRequest.of(pageNumber, BACKLOG_ITEM_PAGE_SIZE, + Sort.by(Sort.DEFAULT_DIRECTION, BacklogItemSortBy.of(value).getValue())); + + //when + when(projectRepository.findByIdWithProjectMember(id, SAMPLE_USER)) + .thenReturn(Optional.of(ENTITY_DATA.project())); + + when(backlogItemRepository.getByProject(ENTITY_DATA.project(), pageable)) + .thenReturn(new PageImpl<>(BACKLOG_ITEM_LIST_TEST_DATA.backlogItems())); + + when(backlogItemMapper.backlogItemToBacklogItemResponse(BACKLOG_ITEM_LIST_TEST_DATA.backlogItems().get(0))) + .thenReturn(BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponses().get(0)); + + when(backlogItemMapper.backlogItemToBacklogItemResponse(BACKLOG_ITEM_LIST_TEST_DATA.backlogItems().get(1))) + .thenReturn(BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponses().get(1)); + + BacklogItemResponseList expected = BACKLOG_ITEM_LIST_TEST_DATA.backlogItemResponseList(); + + //then + assertEquals(expected, backlogItemServiceImpl.getByProjectId(id, pageNumber, value, value, SAMPLE_USER), + SHOULD_RETURN_CORRECT_BACKLOG_ITEM_RESPONSE_LIST); + } + @Test final void getDetailsById_shouldReturnCorrectBacklogItemDetailsResponseOnCorrectId() { //given diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/api/project/ProjectServiceTest.java b/corn-backend/src/test/java/dev/corn/cornbackend/api/project/ProjectServiceTest.java index cbf8c29e..8b2a1154 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/api/project/ProjectServiceTest.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/api/project/ProjectServiceTest.java @@ -17,7 +17,6 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -28,7 +27,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/entities/user/UserTest.java b/corn-backend/src/test/java/dev/corn/cornbackend/entities/user/UserTest.java index 8a533c9a..66effd9f 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/entities/user/UserTest.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/entities/user/UserTest.java @@ -18,7 +18,6 @@ import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.util.Collections; -import java.util.List; import java.util.Objects; import java.util.Set; diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/repositories/backlog/item/BacklogItemRepositoryTest.java b/corn-backend/src/test/java/dev/corn/cornbackend/repositories/backlog/item/BacklogItemRepositoryTest.java index 7879e244..da89c272 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/repositories/backlog/item/BacklogItemRepositoryTest.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/repositories/backlog/item/BacklogItemRepositoryTest.java @@ -11,6 +11,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import java.util.List; import java.util.Optional; @@ -96,12 +98,12 @@ final void test_getBySprintShouldReturnCorrectBacklogItems() { final void test_getByProjectShouldReturnCorrectBacklogItems() { //given Project project = TEST_DATA.project(); + PageRequest pageRequest = PageRequest.of(0, 1); //when - List backlogItems = backlogItemRepository.getByProject(project); - + Page backlogItems = backlogItemRepository.getByProject(project, pageRequest); //then - assertEquals(1, backlogItems.size(), LIST_CORRECT_SIZE); - assertEquals(TEST_DATA.backlogItem(), backlogItems.get(0), BACKLOG_ITEM_EQUAL); + assertEquals(1L, backlogItems.getTotalElements(), LIST_CORRECT_SIZE); + assertEquals(TEST_DATA.backlogItem(), backlogItems.toList().get(0), BACKLOG_ITEM_EQUAL); } } diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/BacklogItemTestDataBuilder.java b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/BacklogItemTestDataBuilder.java index 19241fa6..ea7aa4da 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/BacklogItemTestDataBuilder.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/BacklogItemTestDataBuilder.java @@ -3,6 +3,7 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemDetails; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemRequest; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; +import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponseList; import dev.corn.cornbackend.api.project.data.ProjectResponse; import dev.corn.cornbackend.api.sprint.data.SprintResponse; import dev.corn.cornbackend.entities.backlog.item.BacklogItem; @@ -127,7 +128,11 @@ public static BacklogItemListTestData backlogItemListTestData() { return new BacklogItemListTestData( List.of(backlogItem1, backlogItem2), - List.of(backlogItemResponse1, backlogItemResponse2) + List.of(backlogItemResponse1, backlogItemResponse2), + BacklogItemResponseList.builder() + .backlogItemResponseList(List.of(backlogItemResponse1, backlogItemResponse2)) + .totalNumber(2L) + .build() ); } diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/BacklogItemDetailsTestData.java b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/BacklogItemDetailsTestData.java index 5375eef8..877c666b 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/BacklogItemDetailsTestData.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/BacklogItemDetailsTestData.java @@ -2,7 +2,6 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemDetails; import dev.corn.cornbackend.entities.backlog.item.BacklogItem; -import lombok.Builder; public record BacklogItemDetailsTestData( BacklogItem backlogItem, diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/BacklogItemListTestData.java b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/BacklogItemListTestData.java index b9a4feac..b51c2b1f 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/BacklogItemListTestData.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/BacklogItemListTestData.java @@ -1,13 +1,14 @@ package dev.corn.cornbackend.test.backlog.item.data; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; +import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponseList; import dev.corn.cornbackend.entities.backlog.item.BacklogItem; -import lombok.Builder; import java.util.List; public record BacklogItemListTestData( List backlogItems, - List backlogItemResponses + List backlogItemResponses, + BacklogItemResponseList backlogItemResponseList ) { } diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/EntityData.java b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/EntityData.java index f960fb3d..8caafa20 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/EntityData.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/EntityData.java @@ -3,7 +3,6 @@ import dev.corn.cornbackend.entities.project.Project; import dev.corn.cornbackend.entities.project.member.ProjectMember; import dev.corn.cornbackend.entities.sprint.Sprint; -import lombok.Builder; public record EntityData(ProjectMember projectmember, Sprint sprint, Project project) { } diff --git a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/UpdateBacklogItemTestData.java b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/UpdateBacklogItemTestData.java index c4f02a65..30443f23 100644 --- a/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/UpdateBacklogItemTestData.java +++ b/corn-backend/src/test/java/dev/corn/cornbackend/test/backlog/item/data/UpdateBacklogItemTestData.java @@ -3,7 +3,6 @@ import dev.corn.cornbackend.api.backlog.item.data.BacklogItemRequest; import dev.corn.cornbackend.api.backlog.item.data.BacklogItemResponse; import dev.corn.cornbackend.entities.backlog.item.BacklogItem; -import lombok.Builder; public record UpdateBacklogItemTestData( BacklogItemRequest backlogItemRequest, diff --git a/corn-frontend/angular.json b/corn-frontend/angular.json index 9da75462..431aab43 100644 --- a/corn-frontend/angular.json +++ b/corn-frontend/angular.json @@ -46,18 +46,6 @@ "namedChunks": false, "aot": true, "extractLicenses": true, - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kb", - "maximumError": "1mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], "fileReplacements": [ { "replace": "src/environments/environment.ts", diff --git a/corn-frontend/package-lock.json b/corn-frontend/package-lock.json index b5a33f0b..6e308d88 100644 --- a/corn-frontend/package-lock.json +++ b/corn-frontend/package-lock.json @@ -20,11 +20,13 @@ "@angular/router": "^17.1.0", "@angular/service-worker": "^17.1.0", "@ng-icons/akar-icons": "^26.3.0", - "@ng-icons/bootstrap-icons": "^26.3.0", + "@ng-icons/bootstrap-icons": "^26.5.0", "@ng-icons/core": "^26.3.0", + "@ng-icons/feather-icons": "^27.1.0", "@ng-icons/heroicons": "^26.3.0", "@ng-icons/material-icons": "^26.3.0", "@ng-icons/octicons": "^26.3.0", + "@ng-icons/ux-aspects": "^26.3.0", "keycloak-angular": "^15.1.0", "keycloak-js": "^23.0.5", "rxjs": "~7.8.0", @@ -75,12 +77,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1701.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1701.2.tgz", - "integrity": "sha512-g3gn5Ht6r9bCeFeAYF+HboZB8IvgvqqdeOnaWNaXJLI0ymEkpbqRdqrHGuVKHJV7JOMNXC7GPJEctBC6SXxOxA==", + "version": "0.1702.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1702.1.tgz", + "integrity": "sha512-eYYtR3kCG0V7aHsL34O4v8W2nW6MX4+SebhBO2dHGz2nCAS09LPtyO2fZZGawPgXOrN0nkLfghghI0hJ0dDaOw==", "dev": true, "dependencies": { - "@angular-devkit/core": "17.1.2", + "@angular-devkit/core": "17.2.1", "rxjs": "7.8.1" }, "engines": { @@ -90,71 +92,70 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.1.2.tgz", - "integrity": "sha512-QIDTP+TjiCKCYRZYb8to4ymvIV1Djcfd5c17VdgMGhRqIQAAK1V4f4A1njdhGYOrgsLajZQAnKvFfk2ZMeI37A==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.2.1.tgz", + "integrity": "sha512-Wq3ggliCMQCRVCucbjE4/9BJCN1KMSGfF6Bx1ke2B+vW3ElLt+M4x4Eeyg2dSPEYB7slgY9WOx7qtyOkUy15tQ==", "dev": true, "dependencies": { "@ampproject/remapping": "2.2.1", - "@angular-devkit/architect": "0.1701.2", - "@angular-devkit/build-webpack": "0.1701.2", - "@angular-devkit/core": "17.1.2", - "@babel/core": "7.23.7", + "@angular-devkit/architect": "0.1702.1", + "@angular-devkit/build-webpack": "0.1702.1", + "@angular-devkit/core": "17.2.1", + "@babel/core": "7.23.9", "@babel/generator": "7.23.6", "@babel/helper-annotate-as-pure": "7.22.5", "@babel/helper-split-export-declaration": "7.22.6", - "@babel/plugin-transform-async-generator-functions": "7.23.7", + "@babel/plugin-transform-async-generator-functions": "7.23.9", "@babel/plugin-transform-async-to-generator": "7.23.3", - "@babel/plugin-transform-runtime": "7.23.7", - "@babel/preset-env": "7.23.7", - "@babel/runtime": "7.23.7", + "@babel/plugin-transform-runtime": "7.23.9", + "@babel/preset-env": "7.23.9", + "@babel/runtime": "7.23.9", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "17.1.2", - "@vitejs/plugin-basic-ssl": "1.0.2", + "@ngtools/webpack": "17.2.1", + "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", - "autoprefixer": "10.4.16", + "autoprefixer": "10.4.17", "babel-loader": "9.1.3", "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.21.5", "copy-webpack-plugin": "11.0.0", "critters": "0.0.20", - "css-loader": "6.8.1", - "esbuild-wasm": "0.19.11", + "css-loader": "6.10.0", + "esbuild-wasm": "0.20.0", "fast-glob": "3.3.2", "http-proxy-middleware": "2.0.6", "https-proxy-agent": "7.0.2", - "inquirer": "9.2.12", - "jsonc-parser": "3.2.0", + "inquirer": "9.2.14", + "jsonc-parser": "3.2.1", "karma-source-map-support": "1.4.0", "less": "4.2.0", "less-loader": "11.1.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.1", - "magic-string": "0.30.5", - "mini-css-extract-plugin": "2.7.6", + "magic-string": "0.30.7", + "mini-css-extract-plugin": "2.8.0", "mrmime": "2.0.0", "open": "8.4.2", "ora": "5.4.1", "parse5-html-rewriting-stream": "7.0.0", - "picomatch": "3.0.1", - "piscina": "4.2.1", - "postcss": "8.4.33", - "postcss-loader": "7.3.4", + "picomatch": "4.0.1", + "piscina": "4.3.1", + "postcss": "8.4.35", + "postcss-loader": "8.1.0", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", - "sass": "1.69.7", - "sass-loader": "13.3.3", - "semver": "7.5.4", + "sass": "1.70.0", + "sass-loader": "14.1.0", + "semver": "7.6.0", "source-map-loader": "5.0.0", "source-map-support": "0.5.21", - "terser": "5.26.0", - "text-table": "0.2.0", + "terser": "5.27.0", "tree-kill": "1.2.2", "tslib": "2.6.2", - "undici": "6.2.1", + "undici": "6.6.2", "vite": "5.0.12", "watchpack": "2.4.0", - "webpack": "5.89.0", + "webpack": "5.90.1", "webpack-dev-middleware": "6.1.1", "webpack-dev-server": "4.15.1", "webpack-merge": "5.10.0", @@ -166,7 +167,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.19.11" + "esbuild": "0.20.0" }, "peerDependencies": { "@angular/compiler-cli": "^17.0.0", @@ -219,78 +220,13 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/autoprefixer": { - "version": "10.4.16", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", - "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "browserslist": "^4.21.10", - "caniuse-lite": "^1.0.30001538", - "fraction.js": "^4.3.6", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/postcss": { - "version": "8.4.33", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", - "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1701.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1701.2.tgz", - "integrity": "sha512-LqfSO5iTbiYByDadUET/8uIun8vSHMEdtoxiil/kdZ5T0NG0p7K8QqUMnWgg6suwO6kFfYJkMiS8Dq3Y/ONUNQ==", + "version": "0.1702.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1702.1.tgz", + "integrity": "sha512-cmtGn8IYqruHuq1yPYEA17tLDTGmMhDPLagAbjZPVAjTpwCwC28H6sRXyhLTiSpzXdXUgROTO6bSXTvtJyyDSA==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1701.2", + "@angular-devkit/architect": "0.1702.1", "rxjs": "7.8.1" }, "engines": { @@ -304,15 +240,15 @@ } }, "node_modules/@angular-devkit/core": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.1.2.tgz", - "integrity": "sha512-ku+/W/HMCBacSWFppenr9y6Lx8mDuTuQvn1IkTyBLiJOpWnzgVbx9kHDeaDchGa1PwLlJUBBrv27t3qgJOIDPw==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.2.1.tgz", + "integrity": "sha512-4jWG7akd5wVxjKkLKDT1zUTyLJeBP5mDmGUPooZ6zVHy39X6htYC+BV3uu/T6gVrD4FyONMDezedpBOrQPtZ6A==", "dev": true, "dependencies": { "ajv": "8.12.0", "ajv-formats": "2.1.1", - "jsonc-parser": "3.2.0", - "picomatch": "3.0.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", "rxjs": "7.8.1", "source-map": "0.7.4" }, @@ -331,14 +267,14 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.1.2.tgz", - "integrity": "sha512-8S9RuM8olFN/gwN+mjbuF1CwHX61f0i59EGXz9tXLnKRUTjsRR+8vVMTAmX0dvVAT5fJTG/T69X+HX7FeumdqA==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.2.1.tgz", + "integrity": "sha512-PgbjZgMSk1Q8QAH4mAx/dHDzPjNnXFONsNmwo80JPp6eJcBN0pODbchulFYdY7kPry07sNtGGWpQeWtdPAZHPw==", "dev": true, "dependencies": { - "@angular-devkit/core": "17.1.2", - "jsonc-parser": "3.2.0", - "magic-string": "0.30.5", + "@angular-devkit/core": "17.2.1", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.7", "ora": "5.4.1", "rxjs": "7.8.1" }, @@ -349,9 +285,9 @@ } }, "node_modules/@angular/animations": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.1.2.tgz", - "integrity": "sha512-ZsHa/zoWBOZdispjcNgXCoF9MAtc6Zyzc/QFUjtOFI9vigOI8tWP6GY1Wfeg4cyL+R3uDGYBgMrdr8l84VfuKg==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.2.2.tgz", + "integrity": "sha512-ENr35pDVslioJO8zBLo1QClzC7NqTc0Du36UMtWkw3cg+QRLnAZ7zfju5w0O8K7Z3omDtFzgVSPfyS0VDkrXPQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -359,13 +295,13 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.1.2" + "@angular/core": "17.2.2" } }, "node_modules/@angular/cdk": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-17.1.2.tgz", - "integrity": "sha512-eu9D60RQv213qi7oh6ae9Z+d6+AG/aqi0y70Ag9BjwqTiatDiYvSySxswxYYKdzPp0hx0ZUTGi16LqtT6pyj6Q==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-17.2.1.tgz", + "integrity": "sha512-9cWV9MyWnpImns/WQApgoQBKblXA9Zx2CpCkDNipRgx9RyvGrvCLjpEfwQI4HjpPAQDI1trsbeJKihzgz4tFgw==", "dependencies": { "tslib": "^2.3.0" }, @@ -379,27 +315,27 @@ } }, "node_modules/@angular/cli": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.1.2.tgz", - "integrity": "sha512-U1W6XZNrfeRkXW2fO3AU25rRttqZahVkhzcK3lAtJ8+lSrStCOF7x1gz6tmFZFte1fNHQrXqD0yIDkd8H2/cvw==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.2.1.tgz", + "integrity": "sha512-zurPJunprq6ZRpNd6Icx7Ne819WN+pL7tQAlwTof7xuCnwfnIV32xiylFkvn77eyRN0Qh+so1FLlFy0t1jH4Mw==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1701.2", - "@angular-devkit/core": "17.1.2", - "@angular-devkit/schematics": "17.1.2", - "@schematics/angular": "17.1.2", + "@angular-devkit/architect": "0.1702.1", + "@angular-devkit/core": "17.2.1", + "@angular-devkit/schematics": "17.2.1", + "@schematics/angular": "17.2.1", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "4.1.1", - "inquirer": "9.2.12", - "jsonc-parser": "3.2.0", + "inquirer": "9.2.14", + "jsonc-parser": "3.2.1", "npm-package-arg": "11.0.1", "npm-pick-manifest": "9.0.0", "open": "8.4.2", "ora": "5.4.1", - "pacote": "17.0.5", + "pacote": "17.0.6", "resolve": "1.22.8", - "semver": "7.5.4", + "semver": "7.6.0", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -413,9 +349,9 @@ } }, "node_modules/@angular/common": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.1.2.tgz", - "integrity": "sha512-y/wD+zuPaPgK3dB80Q63qBtuu5TuryKuUgjWrOmrguBWV9oiJRhKQrcp1gVw9vVrowmbDBKGtPMS622Q4oxOWQ==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.2.2.tgz", + "integrity": "sha512-F2wQj/lYcZUNZuNmuuDb8RK8tU7e1w7IzN8J6nT2gQHq6NiZfYiUL2XrToGtdd/cZjBeYKGiWRBW/PsZzKyC3A==", "dependencies": { "tslib": "^2.3.0" }, @@ -423,14 +359,14 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.1.2", + "@angular/core": "17.2.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.1.2.tgz", - "integrity": "sha512-1vJuQRM5V01nC6qsLvBKrHVZXpzbK0YKubwVQUXCSfDNZBcDFak3SQcwU4C2t880rU3ZvFDB1UWfk7CKn5w9Kw==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.2.2.tgz", + "integrity": "sha512-loRr4+9/JkSDszExZiS+iuhjXj7wvLF4gJeqlbp2PbPl4eUoGKYq0RVZ3a7IkIXxB5sgoYB5MjKsbdm/uaMK1A==", "dependencies": { "tslib": "^2.3.0" }, @@ -438,7 +374,7 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.1.2" + "@angular/core": "17.2.2" }, "peerDependenciesMeta": { "@angular/core": { @@ -447,16 +383,16 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.1.2.tgz", - "integrity": "sha512-4P4ttCe4IF9yq7bxCDxbVW7purN7qV0nqofP5Tth1xCsgIJeGmOMMQJN5RJCZNrAPMkvMv39eV878sgcDjbpOA==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.2.2.tgz", + "integrity": "sha512-tFfbamdLhn8R30/aKxhXNG6CwelJOpVxfUnTizb7pWUJ/UQ4py0xzJp7s0QzKjR1lpRAq3rPtsE3f9BbcHD1HA==", "dev": true, "dependencies": { - "@babel/core": "7.23.2", + "@babel/core": "7.23.9", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", - "reflect-metadata": "^0.1.2", + "reflect-metadata": "^0.2.0", "semver": "^7.0.0", "tslib": "^2.3.0", "yargs": "^17.2.1" @@ -470,59 +406,14 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/compiler": "17.1.2", + "@angular/compiler": "17.2.2", "typescript": ">=5.2 <5.4" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", - "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.0", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@angular/core": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.1.2.tgz", - "integrity": "sha512-0M787BZVgYSVogHCUzo/dFrT56TgfQoEsOQngHMpyERJZv6dycXZlRdHc6TzvHUa+Uu/MNjn/RclBR8063bdWA==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.2.2.tgz", + "integrity": "sha512-jXnrOVsA9b34PJN383EOss3ejd5+xUTeijuUy5njPRXpxMxrGjV5gkk0lSxsALRxw2ICax2tMoGmHXfXO1x9gw==", "dependencies": { "tslib": "^2.3.0" }, @@ -535,9 +426,9 @@ } }, "node_modules/@angular/forms": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.1.2.tgz", - "integrity": "sha512-n1WsZAL2IVOB6ocROKR6CFOR14PIC9RGAB41SwTfPhJeBM1kjW48bXY0sw97TasxM4mWJKGCmFXu0jQwkoeSpQ==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.2.2.tgz", + "integrity": "sha512-xxy1Khpun2TpSDQch6BK4uHkqIxZvxsBU2LZgo/3W604lKoVjBGKPZqoYFRew2OPeCQ3VjK9P8a8ZhitsLLlKQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -545,16 +436,16 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.1.2", - "@angular/core": "17.1.2", - "@angular/platform-browser": "17.1.2", + "@angular/common": "17.2.2", + "@angular/core": "17.2.2", + "@angular/platform-browser": "17.2.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/material": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-17.1.2.tgz", - "integrity": "sha512-50n7JDWtWGCxfrMKVKZ2wqkdozukA3IWeypQgXxzZc+4jqgT6Vj8/U4xNvcO9OgPLMOaTvktfT+wzUmCKJ0sng==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-17.2.1.tgz", + "integrity": "sha512-NLQJkX4XiwIm32dGdNseoc+ARn6JvuB2xMY5XfWTtjJBbQaPk5sIvjH4wsAEeYqDKtZbRCjxGwRz0K1djyaVqQ==", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/auto-init": "15.0.0-canary.7f224ddd4.0", @@ -607,7 +498,7 @@ }, "peerDependencies": { "@angular/animations": "^17.0.0 || ^18.0.0", - "@angular/cdk": "17.1.2", + "@angular/cdk": "17.2.1", "@angular/common": "^17.0.0 || ^18.0.0", "@angular/core": "^17.0.0 || ^18.0.0", "@angular/forms": "^17.0.0 || ^18.0.0", @@ -616,9 +507,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.1.2.tgz", - "integrity": "sha512-unfpA5OLnqDmDb/oAQR2t2iROpOg02qwZayxyFg4MUZdDdnghPCfX77L2sr6oVVa7OJfKYFlmwmBXX1H3zjcXA==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.2.2.tgz", + "integrity": "sha512-6AZhQfZpo/apiRKwhy6es1RpoxgCXMR4y7Eo7GvVHpMKBwioWwP2H+qg83ed2xv0/GXIyqZsHjpEjsLPE83uyw==", "dependencies": { "tslib": "^2.3.0" }, @@ -626,9 +517,9 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/animations": "17.1.2", - "@angular/common": "17.1.2", - "@angular/core": "17.1.2" + "@angular/animations": "17.2.2", + "@angular/common": "17.2.2", + "@angular/core": "17.2.2" }, "peerDependenciesMeta": { "@angular/animations": { @@ -637,9 +528,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.1.2.tgz", - "integrity": "sha512-xiWVDHbA+owDhKo5SAnzZtawA1ktGthlCl3YTI+vmkJpF6axkYOqR7YL+aEQX/y/5GSK+oR+03SgAnYcpOwKlQ==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.2.2.tgz", + "integrity": "sha512-I52zbDSic4LB0yhCFUEBZKg9QkLKVUCGTco0XFHNRy3EF54Jvs0uWBqG79egsuXmyBNQY0E3op9eqhhn6Mnwbw==", "dependencies": { "tslib": "^2.3.0" }, @@ -647,16 +538,16 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.1.2", - "@angular/compiler": "17.1.2", - "@angular/core": "17.1.2", - "@angular/platform-browser": "17.1.2" + "@angular/common": "17.2.2", + "@angular/compiler": "17.2.2", + "@angular/core": "17.2.2", + "@angular/platform-browser": "17.2.2" } }, "node_modules/@angular/router": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.1.2.tgz", - "integrity": "sha512-8OexxiiscRdfEiB6jOKlZFyAKZtvIQvh0ugW6U7nAXPV5XsA2UL80sXkc829eH0DnJn2Wj/HS6ZNGgG81PWDHg==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.2.2.tgz", + "integrity": "sha512-3mT2+qBF8urFeY6eZVZX5bmAdK9ojJRZi7yB9ocpieE1Jdd/1NYCfIsQxJk032syEGc2NJftijTzuNiflLzlTA==", "dependencies": { "tslib": "^2.3.0" }, @@ -664,16 +555,16 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.1.2", - "@angular/core": "17.1.2", - "@angular/platform-browser": "17.1.2", + "@angular/common": "17.2.2", + "@angular/core": "17.2.2", + "@angular/platform-browser": "17.2.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-17.1.2.tgz", - "integrity": "sha512-SD528iC0PwJ7g3NWQ6hoyLyr97eC5SsSmMArPC+ZIuvzgnWsKBa80YAAVJjW/kT0JlspUbK2H5606ZMsnEmcIw==", + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-17.2.2.tgz", + "integrity": "sha512-UwqUbVjod2eo0d72bJQNj5IZBu1v74ugPHJDjHZM+sUmQIhaeQxyVHwmDsZcBJL5RCi03ZeyprpOX6Aj23+WMw==", "dependencies": { "tslib": "^2.3.0" }, @@ -684,16 +575,10 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.1.2", - "@angular/core": "17.1.2" + "@angular/common": "17.2.2", + "@angular/core": "17.2.2" } }, - "node_modules/@assemblyscript/loader": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true - }, "node_modules/@babel/code-frame": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", @@ -717,9 +602,9 @@ } }, "node_modules/@babel/core": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", - "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -727,11 +612,11 @@ "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.7", - "@babel/parser": "^7.23.6", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.7", - "@babel/types": "^7.23.6", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -1459,9 +1344,9 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.7.tgz", - "integrity": "sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -2077,16 +1962,16 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.7.tgz", - "integrity": "sha512-fa0hnfmiXc9fq/weK34MUV0drz2pOL/vfKWvN7Qw127hiUPabFCUMgAbYWcchRzMJit4o5ARsK/s+5h0249pLw==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.9.tgz", + "integrity": "sha512-A7clW3a0aSjm3ONU9o2HAILSegJCYlEZmOhmBRReVtIpY/Z/p7yIZ+wR41Z+UipwdGuqwtID/V/dOdZXjwi9gQ==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.7", - "babel-plugin-polyfill-corejs3": "^0.8.7", - "babel-plugin-polyfill-regenerator": "^0.5.4", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", "semver": "^6.3.1" }, "engines": { @@ -2245,9 +2130,9 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.7.tgz", - "integrity": "sha512-SY27X/GtTz/L4UryMNJ6p4fH4nsgWbz84y9FE0bQeWJP6O5BhgVCt53CotQKHCOeXJel8VyhlhujhlltKms/CA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", "dev": true, "dependencies": { "@babel/compat-data": "^7.23.5", @@ -2277,13 +2162,13 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.7", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", "@babel/plugin-transform-async-to-generator": "^7.23.3", "@babel/plugin-transform-block-scoped-functions": "^7.23.3", "@babel/plugin-transform-block-scoping": "^7.23.4", "@babel/plugin-transform-class-properties": "^7.23.3", "@babel/plugin-transform-class-static-block": "^7.23.4", - "@babel/plugin-transform-classes": "^7.23.5", + "@babel/plugin-transform-classes": "^7.23.8", "@babel/plugin-transform-computed-properties": "^7.23.3", "@babel/plugin-transform-destructuring": "^7.23.3", "@babel/plugin-transform-dotall-regex": "^7.23.3", @@ -2299,7 +2184,7 @@ "@babel/plugin-transform-member-expression-literals": "^7.23.3", "@babel/plugin-transform-modules-amd": "^7.23.3", "@babel/plugin-transform-modules-commonjs": "^7.23.3", - "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", "@babel/plugin-transform-modules-umd": "^7.23.3", "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", "@babel/plugin-transform-new-target": "^7.23.3", @@ -2325,9 +2210,9 @@ "@babel/plugin-transform-unicode-regex": "^7.23.3", "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.7", - "babel-plugin-polyfill-corejs3": "^0.8.7", - "babel-plugin-polyfill-regenerator": "^0.5.4", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -2368,9 +2253,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.23.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.7.tgz", - "integrity": "sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA==", + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -2447,9 +2332,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz", - "integrity": "sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.0.tgz", + "integrity": "sha512-fGFDEctNh0CcSwsiRPxiaqX0P5rq+AqE0SRhYGZ4PX46Lg1FNR6oCxJghf8YgY0WQEgQuh3lErUFE4KxLeRmmw==", "cpu": [ "ppc64" ], @@ -2463,9 +2348,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.11.tgz", - "integrity": "sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.0.tgz", + "integrity": "sha512-3bMAfInvByLHfJwYPJRlpTeaQA75n8C/QKpEaiS4HrFWFiJlNI0vzq/zCjBrhAYcPyVPG7Eo9dMrcQXuqmNk5g==", "cpu": [ "arm" ], @@ -2479,9 +2364,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz", - "integrity": "sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.0.tgz", + "integrity": "sha512-aVpnM4lURNkp0D3qPoAzSG92VXStYmoVPOgXveAUoQBWRSuQzt51yvSju29J6AHPmwY1BjH49uR29oyfH1ra8Q==", "cpu": [ "arm64" ], @@ -2495,9 +2380,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.11.tgz", - "integrity": "sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.0.tgz", + "integrity": "sha512-uK7wAnlRvjkCPzh8jJ+QejFyrP8ObKuR5cBIsQZ+qbMunwR8sbd8krmMbxTLSrDhiPZaJYKQAU5Y3iMDcZPhyQ==", "cpu": [ "x64" ], @@ -2511,9 +2396,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz", - "integrity": "sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.0.tgz", + "integrity": "sha512-AjEcivGAlPs3UAcJedMa9qYg9eSfU6FnGHJjT8s346HSKkrcWlYezGE8VaO2xKfvvlZkgAhyvl06OJOxiMgOYQ==", "cpu": [ "arm64" ], @@ -2527,9 +2412,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz", - "integrity": "sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.0.tgz", + "integrity": "sha512-bsgTPoyYDnPv8ER0HqnJggXK6RyFy4PH4rtsId0V7Efa90u2+EifxytE9pZnsDgExgkARy24WUQGv9irVbTvIw==", "cpu": [ "x64" ], @@ -2543,9 +2428,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz", - "integrity": "sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.0.tgz", + "integrity": "sha512-kQ7jYdlKS335mpGbMW5tEe3IrQFIok9r84EM3PXB8qBFJPSc6dpWfrtsC/y1pyrz82xfUIn5ZrnSHQQsd6jebQ==", "cpu": [ "arm64" ], @@ -2559,9 +2444,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz", - "integrity": "sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.0.tgz", + "integrity": "sha512-uG8B0WSepMRsBNVXAQcHf9+Ko/Tr+XqmK7Ptel9HVmnykupXdS4J7ovSQUIi0tQGIndhbqWLaIL/qO/cWhXKyQ==", "cpu": [ "x64" ], @@ -2575,9 +2460,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz", - "integrity": "sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.0.tgz", + "integrity": "sha512-2ezuhdiZw8vuHf1HKSf4TIk80naTbP9At7sOqZmdVwvvMyuoDiZB49YZKLsLOfKIr77+I40dWpHVeY5JHpIEIg==", "cpu": [ "arm" ], @@ -2591,9 +2476,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz", - "integrity": "sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.0.tgz", + "integrity": "sha512-uTtyYAP5veqi2z9b6Gr0NUoNv9F/rOzI8tOD5jKcCvRUn7T60Bb+42NDBCWNhMjkQzI0qqwXkQGo1SY41G52nw==", "cpu": [ "arm64" ], @@ -2607,9 +2492,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz", - "integrity": "sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.0.tgz", + "integrity": "sha512-c88wwtfs8tTffPaoJ+SQn3y+lKtgTzyjkD8NgsyCtCmtoIC8RDL7PrJU05an/e9VuAke6eJqGkoMhJK1RY6z4w==", "cpu": [ "ia32" ], @@ -2623,9 +2508,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz", - "integrity": "sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.0.tgz", + "integrity": "sha512-lR2rr/128/6svngnVta6JN4gxSXle/yZEZL3o4XZ6esOqhyR4wsKyfu6qXAL04S4S5CgGfG+GYZnjFd4YiG3Aw==", "cpu": [ "loong64" ], @@ -2639,9 +2524,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz", - "integrity": "sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.0.tgz", + "integrity": "sha512-9Sycc+1uUsDnJCelDf6ZNqgZQoK1mJvFtqf2MUz4ujTxGhvCWw+4chYfDLPepMEvVL9PDwn6HrXad5yOrNzIsQ==", "cpu": [ "mips64el" ], @@ -2655,9 +2540,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz", - "integrity": "sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.0.tgz", + "integrity": "sha512-CoWSaaAXOZd+CjbUTdXIJE/t7Oz+4g90A3VBCHLbfuc5yUQU/nFDLOzQsN0cdxgXd97lYW/psIIBdjzQIwTBGw==", "cpu": [ "ppc64" ], @@ -2671,9 +2556,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz", - "integrity": "sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.0.tgz", + "integrity": "sha512-mlb1hg/eYRJUpv8h/x+4ShgoNLL8wgZ64SUr26KwglTYnwAWjkhR2GpoKftDbPOCnodA9t4Y/b68H4J9XmmPzA==", "cpu": [ "riscv64" ], @@ -2687,9 +2572,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz", - "integrity": "sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.0.tgz", + "integrity": "sha512-fgf9ubb53xSnOBqyvWEY6ukBNRl1mVX1srPNu06B6mNsNK20JfH6xV6jECzrQ69/VMiTLvHMicQR/PgTOgqJUQ==", "cpu": [ "s390x" ], @@ -2703,9 +2588,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz", - "integrity": "sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.0.tgz", + "integrity": "sha512-H9Eu6MGse++204XZcYsse1yFHmRXEWgadk2N58O/xd50P9EvFMLJTQLg+lB4E1cF2xhLZU5luSWtGTb0l9UeSg==", "cpu": [ "x64" ], @@ -2719,9 +2604,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz", - "integrity": "sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.0.tgz", + "integrity": "sha512-lCT675rTN1v8Fo+RGrE5KjSnfY0x9Og4RN7t7lVrN3vMSjy34/+3na0q7RIfWDAj0e0rCh0OL+P88lu3Rt21MQ==", "cpu": [ "x64" ], @@ -2735,9 +2620,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz", - "integrity": "sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.0.tgz", + "integrity": "sha512-HKoUGXz/TOVXKQ+67NhxyHv+aDSZf44QpWLa3I1lLvAwGq8x1k0T+e2HHSRvxWhfJrFxaaqre1+YyzQ99KixoA==", "cpu": [ "x64" ], @@ -2751,9 +2636,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz", - "integrity": "sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.0.tgz", + "integrity": "sha512-GDwAqgHQm1mVoPppGsoq4WJwT3vhnz/2N62CzhvApFD1eJyTroob30FPpOZabN+FgCjhG+AgcZyOPIkR8dfD7g==", "cpu": [ "x64" ], @@ -2767,9 +2652,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz", - "integrity": "sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.0.tgz", + "integrity": "sha512-0vYsP8aC4TvMlOQYozoksiaxjlvUcQrac+muDqj1Fxy6jh9l9CZJzj7zmh8JGfiV49cYLTorFLxg7593pGldwQ==", "cpu": [ "arm64" ], @@ -2783,9 +2668,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz", - "integrity": "sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.0.tgz", + "integrity": "sha512-p98u4rIgfh4gdpV00IqknBD5pC84LCub+4a3MO+zjqvU5MVXOc3hqR2UgT2jI2nh3h8s9EQxmOsVI3tyzv1iFg==", "cpu": [ "ia32" ], @@ -2799,9 +2684,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz", - "integrity": "sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.0.tgz", + "integrity": "sha512-NgJnesu1RtWihtTtXGFMU5YSE6JyyHPMxCwBZK7a6/8d31GuSo9l0Ss7w1Jw5QnKUawG6UEehs883kcXf5fYwg==", "cpu": [ "x64" ], @@ -2951,9 +2836,9 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz", + "integrity": "sha512-Oud2QPM5dHviZNn4y/WhhYKSXksv+1xLEIsNrAbGcFzUN3ubqWRFT5gwPchNc5NuzILOU4tPBDTZ4VwhL8Y7cw==", "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", @@ -2965,9 +2850,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" @@ -2999,9 +2884,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz", + "integrity": "sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -3779,57 +3664,73 @@ } }, "node_modules/@ng-icons/akar-icons": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/@ng-icons/akar-icons/-/akar-icons-26.3.0.tgz", - "integrity": "sha512-NpJwUMdJ0Jf2XvnQJppLaXGw1zFKMUwCKdGgrg5uci+ruIXWOrLA1rLq1Vrk4wfC2lkrxnujdClGy+otoIL0Tw==", + "version": "26.5.0", + "resolved": "https://registry.npmjs.org/@ng-icons/akar-icons/-/akar-icons-26.5.0.tgz", + "integrity": "sha512-3FRjrKQbJnCBNYPNuTAf5bO9sKdjING+zvYzWPhmjDcKYCPmbUmScRHAFmlw7zlz/HOEdWY79er1NE8yO2MAaw==", "dependencies": { "tslib": "^2.2.0" } }, "node_modules/@ng-icons/bootstrap-icons": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/@ng-icons/bootstrap-icons/-/bootstrap-icons-26.3.0.tgz", - "integrity": "sha512-4iNbE5Z0SrADbRN41xQmtDVPiCMK91MqGhxdasBKNaWN69geQvZZZxwfZ/p8v8a3xURbfuRojO7KKfZS6rdkdg==", + "version": "26.5.0", + "resolved": "https://registry.npmjs.org/@ng-icons/bootstrap-icons/-/bootstrap-icons-26.5.0.tgz", + "integrity": "sha512-M7N/LdxWjr+b13N5t2+PKG0V0ERb3S9wQWAOmqvSGN5X7CvoYy+3J/mYYDcH8zRraunqWUz1mYSvwvB0HfQpug==", "dependencies": { "tslib": "^2.2.0" } }, "node_modules/@ng-icons/core": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/@ng-icons/core/-/core-26.3.0.tgz", - "integrity": "sha512-4gUGz8yShbMX/4S2B4DzcQHrZ1+t29NqmYS70LScN0XMgiFmbg3uUW/Sc14fPiwmhHVNrKSMmX248U61uBZzGw==", + "version": "26.5.0", + "resolved": "https://registry.npmjs.org/@ng-icons/core/-/core-26.5.0.tgz", + "integrity": "sha512-QaincZw6O22pNuI/7lwM1fVeEFANRNAHNi+TYwCn2bAt7v91Fzj7g44J1cyOoApdqkanSWZUWbuyzznPFimOEw==", + "dependencies": { + "tslib": "^2.2.0" + } + }, + "node_modules/@ng-icons/feather-icons": { + "version": "27.1.0", + "resolved": "https://registry.npmjs.org/@ng-icons/feather-icons/-/feather-icons-27.1.0.tgz", + "integrity": "sha512-JgdLahKLW7Lc5eMh4ufXTbQHuBsTfIDZj+1MgQ4Ooc/J7jsZHX41Ha/0IaXkRl6EoYN7/B6+SP45LOIZHApKfg==", "dependencies": { "tslib": "^2.2.0" } }, "node_modules/@ng-icons/heroicons": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/@ng-icons/heroicons/-/heroicons-26.3.0.tgz", - "integrity": "sha512-rj0Y6lWtQqADtMGx/cipY/ezocSVwSKEFYZEvRMFOrDIvTx80aQKldmnCVl97OQlmBKfefVpT6NQgd3G4ZNGWQ==", + "version": "26.5.0", + "resolved": "https://registry.npmjs.org/@ng-icons/heroicons/-/heroicons-26.5.0.tgz", + "integrity": "sha512-hdyY0ZFZe4D+ELuPXdE3StLGr9+avwtjT+A7FedcFoYyNotvLwMTefnA/1I2KfcCGoE5qGt2uRzS9O45fw86MQ==", "dependencies": { "tslib": "^2.2.0" } }, "node_modules/@ng-icons/material-icons": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/@ng-icons/material-icons/-/material-icons-26.3.0.tgz", - "integrity": "sha512-9b7BRK2vrs0cJIC6IIWF1hYnXUVLms8joRW/YEmntMi05Dqe3+97zKe1pfNOp7Rbo6NWtBJpnCFbEnRt7nv5Sw==", + "version": "26.5.0", + "resolved": "https://registry.npmjs.org/@ng-icons/material-icons/-/material-icons-26.5.0.tgz", + "integrity": "sha512-Jld/UUHZ6stt93J12k++jzEzfkYSrf3TsY1fbXe4P25X1pvMfvzDaoS3hItYYIHn9BIxMYjaUXkKDQO7j7PUZQ==", "dependencies": { "tslib": "^2.2.0" } }, "node_modules/@ng-icons/octicons": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/@ng-icons/octicons/-/octicons-26.3.0.tgz", - "integrity": "sha512-FSvfGzfppVzBC883z/Jo42AWi0jTmn1zIXm9ZiHwk1t+mvpERGsPmZwfxcv812OEDcQDlcFso/VLlQdOc8ZJ3A==", + "version": "26.5.0", + "resolved": "https://registry.npmjs.org/@ng-icons/octicons/-/octicons-26.5.0.tgz", + "integrity": "sha512-E/8ziJsjGXqATaz53ZDcdVvVeCq9e3Zsk5D664Sr7R20y9PKpG8moW7+aNXqb1PIKVjzD/5bY2X5srOl6H4pZw==", + "dependencies": { + "tslib": "^2.2.0" + } + }, + "node_modules/@ng-icons/ux-aspects": { + "version": "26.5.0", + "resolved": "https://registry.npmjs.org/@ng-icons/ux-aspects/-/ux-aspects-26.5.0.tgz", + "integrity": "sha512-5b+MN9Y8OTxnwzwVLduGiSl349yY2tDn3ZVWqWIPNaKA5wgelIrY9gA2FKIlB+fTsIbVa02r7nXn8nm+T+4asw==", "dependencies": { "tslib": "^2.2.0" } }, "node_modules/@ngtools/webpack": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.1.2.tgz", - "integrity": "sha512-MdNVSIp0x8AK26L+CxMTXH4weq2sNIp4C09RSdk7y6UkfBxMA3O0jTto9tW3ehkBaaGZ4dSiWkXA8L/ydMiQmA==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.2.1.tgz", + "integrity": "sha512-5O493oqZw0os1Gj3otVTcIXS3nGs60eXZ9w3vsK5w7tZ5x6XqZvO00X8WZQhcxXA9HMG4iDCsU2ll3lcYZVxmg==", "dev": true, "engines": { "node": "^18.13.0 || >=20.9.0", @@ -4142,9 +4043,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz", - "integrity": "sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz", + "integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==", "cpu": [ "arm" ], @@ -4155,9 +4056,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz", - "integrity": "sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz", + "integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==", "cpu": [ "arm64" ], @@ -4168,9 +4069,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz", - "integrity": "sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz", + "integrity": "sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==", "cpu": [ "arm64" ], @@ -4181,9 +4082,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz", - "integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz", + "integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==", "cpu": [ "x64" ], @@ -4194,9 +4095,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz", - "integrity": "sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz", + "integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==", "cpu": [ "arm" ], @@ -4207,9 +4108,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz", - "integrity": "sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz", + "integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==", "cpu": [ "arm64" ], @@ -4220,9 +4121,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz", - "integrity": "sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz", + "integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==", "cpu": [ "arm64" ], @@ -4233,9 +4134,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz", - "integrity": "sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz", + "integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==", "cpu": [ "riscv64" ], @@ -4246,9 +4147,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz", - "integrity": "sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz", + "integrity": "sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==", "cpu": [ "x64" ], @@ -4259,9 +4160,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz", - "integrity": "sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz", + "integrity": "sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==", "cpu": [ "x64" ], @@ -4272,9 +4173,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz", - "integrity": "sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz", + "integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==", "cpu": [ "arm64" ], @@ -4285,9 +4186,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz", - "integrity": "sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz", + "integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==", "cpu": [ "ia32" ], @@ -4298,9 +4199,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz", - "integrity": "sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz", + "integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==", "cpu": [ "x64" ], @@ -4311,14 +4212,14 @@ ] }, "node_modules/@schematics/angular": { - "version": "17.1.2", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.1.2.tgz", - "integrity": "sha512-1GlH0POaN7hVDF1sAm90E5SvAqnKK+PbD1oKSpug9l+1AUQ3vOamyGhEAaO+IxUqvNdgqZexxd5o9MyySTT2Zw==", + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.2.1.tgz", + "integrity": "sha512-OUKupokfgmomWVysBpZ6CB7S3gzyjbVBb5L6UyhNLKAGRFxKOG5XWMPOo0ZdZjfuHB++HyRVj9Dh/rq0+PKHfA==", "dev": true, "dependencies": { - "@angular-devkit/core": "17.1.2", - "@angular-devkit/schematics": "17.1.2", - "jsonc-parser": "3.2.0" + "@angular-devkit/core": "17.2.1", + "@angular-devkit/schematics": "17.2.1", + "jsonc-parser": "3.2.1" }, "engines": { "node": "^18.13.0 || >=20.9.0", @@ -4327,44 +4228,44 @@ } }, "node_modules/@sigstore/bundle": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.1.1.tgz", - "integrity": "sha512-v3/iS+1nufZdKQ5iAlQKcCsoh0jffQyABvYIxKsZQFWc4ubuGjwZklFHpDgV6O6T7vvV78SW5NHI91HFKEcxKg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.2.0.tgz", + "integrity": "sha512-5VI58qgNs76RDrwXNhpmyN/jKpq9evV/7f1XrcqcAfvxDl5SeVY/I5Rmfe96ULAV7/FK5dge9RBKGBJPhL1WsQ==", "dev": true, "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1" + "@sigstore/protobuf-specs": "^0.3.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@sigstore/core": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-0.2.0.tgz", - "integrity": "sha512-THobAPPZR9pDH2CAvDLpkrYedt7BlZnsyxDe+Isq4ZmGfPy5juOFZq487vCU2EgKD7aHSiTfE/i7sN7aEdzQnA==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.0.0.tgz", + "integrity": "sha512-dW2qjbWLRKGu6MIDUTBuJwXCnR8zivcSpf5inUzk7y84zqy/dji0/uahppoIgMoKeR+6pUZucrwHfkQQtiG9Rw==", "dev": true, "engines": { "node": "^16.14.0 || >=18.0.0" } }, "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.0.tgz", + "integrity": "sha512-zxiQ66JFOjVvP9hbhGj/F/qNdsZfkGb/dVXSanNRNuAzMlr4MC95voPUBX8//ZNnmv3uSYzdfR/JSkrgvZTGxA==", "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/@sigstore/sign": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.1.tgz", - "integrity": "sha512-U5sKQEj+faE1MsnLou1f4DQQHeFZay+V9s9768lw48J4pKykPj34rWyI1lsMOGJ3Mae47Ye6q3HAJvgXO21rkQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.3.tgz", + "integrity": "sha512-LqlA+ffyN02yC7RKszCdMTS6bldZnIodiox+IkT8B2f8oRYXCB3LQ9roXeiEL21m64CVH1wyveYAORfD65WoSw==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", "make-fetch-happen": "^13.0.0" }, "engines": { @@ -4372,12 +4273,12 @@ } }, "node_modules/@sigstore/tuf": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.0.tgz", - "integrity": "sha512-S98jo9cpJwO1mtQ+2zY7bOdcYyfVYCUaofCG6wWRzk3pxKHVAkSfshkfecto2+LKsx7Ovtqbgb2LS8zTRhxJ9Q==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.1.tgz", + "integrity": "sha512-9Iv40z652td/QbV0o5n/x25H9w6IYRt2pIGbTX55yFDYlApDQn/6YZomjz6+KBx69rXHLzHcbtTS586mDdFD+Q==", "dev": true, "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/protobuf-specs": "^0.3.0", "tuf-js": "^2.2.0" }, "engines": { @@ -4385,14 +4286,14 @@ } }, "node_modules/@sigstore/verify": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-0.1.0.tgz", - "integrity": "sha512-2UzMNYAa/uaz11NhvgRnIQf4gpLTJ59bhb8ESXaoSS5sxedfS+eLak8bsdMc+qpNQfITUTFoSKFx5h8umlRRiA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.1.0.tgz", + "integrity": "sha512-1fTqnqyTBWvV7cftUUFtDcHPdSox0N3Ub7C0lRyReYx4zZUlNTZjCV+HPy4Lre+r45dV7Qx5JLKvqqsgxuyYfg==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1" + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -4504,9 +4405,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.56.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", - "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", + "version": "8.56.3", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.3.tgz", + "integrity": "sha512-PvSf1wfv2wJpVIFUMSb+i4PvqNYkB9Rkp9ZDO3oaWzq4SKhsQk4mrMBr3ZH06I0hKrVGLBacmgl8JM4WVjb9dg==", "dev": true, "dependencies": { "@types/estree": "*", @@ -4587,9 +4488,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", - "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "version": "20.11.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.20.tgz", + "integrity": "sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -4671,9 +4572,9 @@ } }, "node_modules/@vitejs/plugin-basic-ssl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.2.tgz", - "integrity": "sha512-DKHKVtpI+eA5fvObVgQ3QtTGU70CcCnedalzqmGSR050AzKZMdUzgC8KmlOneHWH8dF2hJ3wkC9+8FDVAaDRCw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", "dev": true, "engines": { "node": ">=14.6.0" @@ -5189,29 +5090,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", - "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.4", - "core-js-compat": "^3.33.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", - "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -5376,9 +5261,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -5395,8 +5280,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -5534,15 +5419,16 @@ } }, "node_modules/call-bind": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz", - "integrity": "sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dev": true, "dependencies": { + "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", - "set-function-length": "^1.2.0" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -5579,9 +5465,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001585", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001585.tgz", - "integrity": "sha512-yr2BWR1yLXQ8fMpdS/4ZZXpseBgE7o4g41x3a6AJOqZuOi+iE/WdJYAuZ6Y95i4Ohd2Y+9MzIWRR+uGABH4s3Q==", + "version": "1.0.30001591", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", + "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", "dev": true, "funding": [ { @@ -6021,12 +5907,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.1.tgz", - "integrity": "sha512-sftHa5qUJY3rs9Zht1WEnmkvXputCyDBczPnr7QDgL8n3qrF3CMXY4VPSYtOLLiOUJcah2WNXREd48iOl6mQIw==", + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", + "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", "dev": true, "dependencies": { - "browserslist": "^4.22.2" + "browserslist": "^4.22.3" }, "funding": { "type": "opencollective", @@ -6053,15 +5939,15 @@ } }, "node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "dependencies": { + "env-paths": "^2.2.1", "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" @@ -6211,19 +6097,19 @@ } }, "node_modules/css-loader": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz", - "integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", + "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", "dev": true, "dependencies": { "icss-utils": "^5.1.0", - "postcss": "^8.4.21", + "postcss": "^8.4.33", "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.3", - "postcss-modules-scope": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.4", + "postcss-modules-scope": "^3.1.1", "postcss-modules-values": "^4.0.0", "postcss-value-parser": "^4.2.0", - "semver": "^7.3.8" + "semver": "^7.5.4" }, "engines": { "node": ">= 12.13.0" @@ -6233,7 +6119,16 @@ "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/css-select": { @@ -6333,18 +6228,20 @@ } }, "node_modules/define-data-property": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.2.tgz", - "integrity": "sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "dependencies": { + "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.2", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-lazy-prop": { @@ -6503,9 +6400,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.660", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.660.tgz", - "integrity": "sha512-1BqvQG0BBQrAA7FVL2EMrb5A1sVyXF3auwJneXjGWa1TpN+g0C4KbUsYWePz6OZ0mXZfXGy+RmQDELJWwE8v/Q==", + "version": "1.4.682", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.682.tgz", + "integrity": "sha512-oCglfs8yYKs9RQjJFOHonSnhikPK3y+0SvSYc/YpYJV//6rqc0/hbwd0c7vgK4vrl6y2gJAwjkhkSGWK+z4KRA==", "dev": true }, "node_modules/emoji-regex": { @@ -6653,6 +6550,18 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", @@ -6669,11 +6578,12 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.11.tgz", - "integrity": "sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.0.tgz", + "integrity": "sha512-6iwE3Y2RVYCME1jLpBqq7LQWK3MW6vjV2bZy6gt/WrqkY+WE74Spyc0ThAOYpMtITvnjX09CrC6ym7A/m9mebA==", "dev": true, "hasInstallScript": true, + "optional": true, "bin": { "esbuild": "bin/esbuild" }, @@ -6681,35 +6591,35 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.11", - "@esbuild/android-arm": "0.19.11", - "@esbuild/android-arm64": "0.19.11", - "@esbuild/android-x64": "0.19.11", - "@esbuild/darwin-arm64": "0.19.11", - "@esbuild/darwin-x64": "0.19.11", - "@esbuild/freebsd-arm64": "0.19.11", - "@esbuild/freebsd-x64": "0.19.11", - "@esbuild/linux-arm": "0.19.11", - "@esbuild/linux-arm64": "0.19.11", - "@esbuild/linux-ia32": "0.19.11", - "@esbuild/linux-loong64": "0.19.11", - "@esbuild/linux-mips64el": "0.19.11", - "@esbuild/linux-ppc64": "0.19.11", - "@esbuild/linux-riscv64": "0.19.11", - "@esbuild/linux-s390x": "0.19.11", - "@esbuild/linux-x64": "0.19.11", - "@esbuild/netbsd-x64": "0.19.11", - "@esbuild/openbsd-x64": "0.19.11", - "@esbuild/sunos-x64": "0.19.11", - "@esbuild/win32-arm64": "0.19.11", - "@esbuild/win32-ia32": "0.19.11", - "@esbuild/win32-x64": "0.19.11" + "@esbuild/aix-ppc64": "0.20.0", + "@esbuild/android-arm": "0.20.0", + "@esbuild/android-arm64": "0.20.0", + "@esbuild/android-x64": "0.20.0", + "@esbuild/darwin-arm64": "0.20.0", + "@esbuild/darwin-x64": "0.20.0", + "@esbuild/freebsd-arm64": "0.20.0", + "@esbuild/freebsd-x64": "0.20.0", + "@esbuild/linux-arm": "0.20.0", + "@esbuild/linux-arm64": "0.20.0", + "@esbuild/linux-ia32": "0.20.0", + "@esbuild/linux-loong64": "0.20.0", + "@esbuild/linux-mips64el": "0.20.0", + "@esbuild/linux-ppc64": "0.20.0", + "@esbuild/linux-riscv64": "0.20.0", + "@esbuild/linux-s390x": "0.20.0", + "@esbuild/linux-x64": "0.20.0", + "@esbuild/netbsd-x64": "0.20.0", + "@esbuild/openbsd-x64": "0.20.0", + "@esbuild/sunos-x64": "0.20.0", + "@esbuild/win32-arm64": "0.20.0", + "@esbuild/win32-ia32": "0.20.0", + "@esbuild/win32-x64": "0.20.0" } }, "node_modules/esbuild-wasm": { - "version": "0.19.11", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.19.11.tgz", - "integrity": "sha512-MIhnpc1TxERUHomteO/ZZHp+kUawGEc03D/8vMHGzffLvbFLeDe6mwxqEZwlqBNY7SLWbyp6bBQAcCen8+wpjQ==", + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.0.tgz", + "integrity": "sha512-Lc9KeQCg1Zf8kCtfDXgy29rx0x8dOuhDWbkP76Wc64q7ctOOc1Zv1C39AxiE+y4N6ONyXtJk4HKpM7jlU7/jSA==", "dev": true, "bin": { "esbuild": "bin/esbuild" @@ -7062,28 +6972,15 @@ } }, "node_modules/figures": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", - "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "dependencies": { - "escape-string-regexp": "^5.0.0", - "is-unicode-supported": "^1.2.0" - }, - "engines": { - "node": ">=14" + "escape-string-regexp": "^1.0.5" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7185,9 +7082,9 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/follow-redirects": { @@ -7488,21 +7385,21 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "dev": true, "engines": { "node": ">= 0.4" @@ -7524,9 +7421,9 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -7535,23 +7432,6 @@ "node": ">= 0.4" } }, - "node_modules/hdr-histogram-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", - "dev": true, - "dependencies": { - "@assemblyscript/loader": "^0.10.1", - "base64-js": "^1.2.0", - "pako": "^1.0.3" - } - }, - "node_modules/hdr-histogram-percentiles-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true - }, "node_modules/hosted-git-info": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", @@ -7714,9 +7594,9 @@ } }, "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "dependencies": { "agent-base": "^7.1.0", @@ -7949,18 +7829,18 @@ } }, "node_modules/inquirer": { - "version": "9.2.12", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.12.tgz", - "integrity": "sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==", + "version": "9.2.14", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.14.tgz", + "integrity": "sha512-4ByIMt677Iz5AvjyKrDpzaepIyMewNvDcvwpVVRZNmy9dLakVoVgdCHZXbK1SlVJra1db0JZ6XkJyHsanpdrdQ==", "dev": true, "dependencies": { - "@ljharb/through": "^2.3.11", + "@ljharb/through": "^2.3.12", "ansi-escapes": "^4.3.2", "chalk": "^5.3.0", "cli-cursor": "^3.1.0", "cli-width": "^4.1.0", "external-editor": "^3.1.0", - "figures": "^5.0.0", + "figures": "^3.2.0", "lodash": "^4.17.21", "mute-stream": "1.0.0", "ora": "^5.4.1", @@ -7971,7 +7851,7 @@ "wrap-ansi": "^6.2.0" }, "engines": { - "node": ">=14.18.0" + "node": ">=18" } }, "node_modules/inquirer/node_modules/chalk": { @@ -7986,10 +7866,23 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "dev": true }, "node_modules/ipaddr.js": { @@ -8137,12 +8030,12 @@ } }, "node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8292,9 +8185,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -8323,9 +8216,9 @@ } }, "node_modules/jasmine-core": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.1.1.tgz", - "integrity": "sha512-UrzO3fL7nnxlQXlvTynNAenL+21oUQRlzqQFsA2U11ryb4+NLOCOePZ70PTojEaUKhiFugh7dG0Q+I58xlPdWg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-5.1.2.tgz", + "integrity": "sha512-2oIUMGn00FdUiqz6epiiJr7xcFyNYj3rDcfmnzfkBnHyBQ3cBQUs4mmyGsOb7TTLb9kxk7dBcmEmqhDKkBoDyA==", "dev": true }, "node_modules/jest-worker": { @@ -8399,6 +8292,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -8439,9 +8338,9 @@ } }, "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true }, "node_modules/jsonfile": { @@ -8471,9 +8370,9 @@ } }, "node_modules/karma": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.2.tgz", - "integrity": "sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ==", + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.3.tgz", + "integrity": "sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q==", "dev": true, "dependencies": { "@colors/colors": "1.5.0", @@ -8495,7 +8394,7 @@ "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", - "socket.io": "^4.4.1", + "socket.io": "^4.7.2", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", @@ -8699,9 +8598,9 @@ } }, "node_modules/keycloak-js": { - "version": "23.0.6", - "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-23.0.6.tgz", - "integrity": "sha512-Pn7iIEHPn7BcQFCbViKRv+8+v9l82oWNRVQr9wQGjp2BNEl9JpTsXjp84xQjwzaLKghG7QV7VwZrWBhiXJeM0Q==", + "version": "23.0.7", + "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-23.0.7.tgz", + "integrity": "sha512-OmszsKzBhhm5yP4W1q/tMd+nNnKpOAdeVYcoGhphlv8Fj1bNk4wRTYzp7pn5BkvueLz7fhvKHz7uOc33524YrA==", "dependencies": { "base64-js": "^1.5.1", "js-sha256": "^0.10.1", @@ -8987,18 +8886,6 @@ "node": ">=8" } }, - "node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/log-symbols/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9037,9 +8924,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", + "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -9204,12 +9091,13 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.7.6", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", - "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.0.tgz", + "integrity": "sha512-CxmUYPFcTgET1zImteG/LZOy/4T5rTojesQXkSNBiquhydn78tfbCE9sjIjnJ/UcjNjOC1bphTCCW5rrS7cXAg==", "dev": true, "dependencies": { - "schema-utils": "^4.0.0" + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" }, "engines": { "node": ">= 12.13.0" @@ -10043,18 +9931,6 @@ "node": ">=8" } }, - "node_modules/ora/node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ora/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10150,9 +10026,9 @@ } }, "node_modules/pacote": { - "version": "17.0.5", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.5.tgz", - "integrity": "sha512-TAE0m20zSDMnchPja9vtQjri19X3pZIyRpm2TJVeI+yU42leJBBDTRYhOcWFsPhaMxf+3iwQkFiKz16G9AEeeA==", + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", "dev": true, "dependencies": { "@npmcli/git": "^5.0.0", @@ -10170,7 +10046,7 @@ "promise-retry": "^2.0.1", "read-package-json": "^7.0.0", "read-package-json-fast": "^3.0.0", - "sigstore": "^2.0.0", + "sigstore": "^2.2.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, @@ -10181,12 +10057,6 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -10359,12 +10229,12 @@ "dev": true }, "node_modules/picomatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", - "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -10389,14 +10259,10 @@ } }, "node_modules/piscina": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.2.1.tgz", - "integrity": "sha512-LShp0+lrO+WIzB9LXO+ZmO4zGHxtTJNZhEO56H9SSu+JPaUQb6oLcTCzWi5IL2DS8/vIkCE88ElahuSSw4TAkA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.3.1.tgz", + "integrity": "sha512-MBj0QYm3hJQ/C/wIXTN1OCYC8uQ4BBJ4LVele2P4ZwVQAH04vkk8E1SpDbuemLAL1dZorbuOob9rYqJeWCcCRg==", "dev": true, - "dependencies": { - "hdr-histogram-js": "^2.0.1", - "hdr-histogram-percentiles-obj": "^3.0.0" - }, "optionalDependencies": { "nice-napi": "^1.0.2" } @@ -10586,34 +10452,46 @@ } }, "node_modules/postcss-load-config/node_modules/lilconfig": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", - "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", "dev": true, "engines": { "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/postcss-loader": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.4.tgz", - "integrity": "sha512-iW5WTTBSC5BfsBJ9daFMPVrLT36MrNiC6fqOZTTaHjBNX6Pfd5p+hSBqe/fEeNd7pc13QiAyGt7VdGMw4eRC4A==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.0.tgz", + "integrity": "sha512-AbperNcX3rlob7Ay7A/HQcrofug1caABBkopoFeOQMspZBqcqj6giYn1Bwey/0uiOPAcR+NQD0I2HC7rXzk91w==", "dev": true, "dependencies": { - "cosmiconfig": "^8.3.5", + "cosmiconfig": "^9.0.0", "jiti": "^1.20.0", "semver": "^7.5.4" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { + "@rspack/core": "0.x || 1.x", "postcss": "^7.0.0 || ^8.0.1", "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/postcss-modules-extract-imports": { @@ -10996,9 +10874,9 @@ } }, "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", + "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==", "dev": true }, "node_modules/regenerate": { @@ -11221,9 +11099,9 @@ } }, "node_modules/rollup": { - "version": "4.9.6", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz", - "integrity": "sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.0.tgz", + "integrity": "sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -11236,19 +11114,19 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.6", - "@rollup/rollup-android-arm64": "4.9.6", - "@rollup/rollup-darwin-arm64": "4.9.6", - "@rollup/rollup-darwin-x64": "4.9.6", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.6", - "@rollup/rollup-linux-arm64-gnu": "4.9.6", - "@rollup/rollup-linux-arm64-musl": "4.9.6", - "@rollup/rollup-linux-riscv64-gnu": "4.9.6", - "@rollup/rollup-linux-x64-gnu": "4.9.6", - "@rollup/rollup-linux-x64-musl": "4.9.6", - "@rollup/rollup-win32-arm64-msvc": "4.9.6", - "@rollup/rollup-win32-ia32-msvc": "4.9.6", - "@rollup/rollup-win32-x64-msvc": "4.9.6", + "@rollup/rollup-android-arm-eabi": "4.12.0", + "@rollup/rollup-android-arm64": "4.12.0", + "@rollup/rollup-darwin-arm64": "4.12.0", + "@rollup/rollup-darwin-x64": "4.12.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.0", + "@rollup/rollup-linux-arm64-gnu": "4.12.0", + "@rollup/rollup-linux-arm64-musl": "4.12.0", + "@rollup/rollup-linux-riscv64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-musl": "4.12.0", + "@rollup/rollup-win32-arm64-msvc": "4.12.0", + "@rollup/rollup-win32-ia32-msvc": "4.12.0", + "@rollup/rollup-win32-x64-msvc": "4.12.0", "fsevents": "~2.3.2" } }, @@ -11324,9 +11202,9 @@ "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" }, "node_modules/sass": { - "version": "1.69.7", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.7.tgz", - "integrity": "sha512-rzj2soDeZ8wtE2egyLXgOOHQvaC2iosZrkF6v3EUG+tBwEvhqUCzm0VP3k9gHF9LXbSrRhT5SksoI56Iw8NPnQ==", + "version": "1.70.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.70.0.tgz", + "integrity": "sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -11341,29 +11219,29 @@ } }, "node_modules/sass-loader": { - "version": "13.3.3", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.3.tgz", - "integrity": "sha512-mt5YN2F1MOZr3d/wBRcZxeFgwgkH44wVc2zohO2YF6JiOMkiXe4BYRZpSu2sO1g71mo/j16txzUhsKZlqjVGzA==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.1.0.tgz", + "integrity": "sha512-LS2mLeFWA+orYxHNu+O18Xe4jR0kyamNOOUsE3NyBP4DvIL+8stHpNX0arYTItdPe80kluIiJ7Wfe/9iHSRO0Q==", "dev": true, "dependencies": { "neo-async": "^2.6.2" }, "engines": { - "node": ">= 14.15.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "fibers": ">= 3.1.0", + "@rspack/core": "0.x || 1.x", "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", "sass": "^1.3.0", "sass-embedded": "*", "webpack": "^5.0.0" }, "peerDependenciesMeta": { - "fibers": { + "@rspack/core": { "optional": true }, "node-sass": { @@ -11374,6 +11252,9 @@ }, "sass-embedded": { "optional": true + }, + "webpack": { + "optional": true } } }, @@ -11423,9 +11304,9 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -11704,17 +11585,17 @@ "dev": true }, "node_modules/sigstore": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.0.tgz", - "integrity": "sha512-fcU9clHwEss2/M/11FFM8Jwc4PjBgbhXoNskoK5guoK0qGQBSeUbQZRJ+B2fDFIvhyf0gqCaPrel9mszbhAxug==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.2.tgz", + "integrity": "sha512-2A3WvXkQurhuMgORgT60r6pOWiCOO5LlEqY2ADxGBDGVYLSo5HN0uLtb68YpVpuL/Vi8mLTe7+0Dx2Fq8lLqEg==", "dev": true, "dependencies": { - "@sigstore/bundle": "^2.1.1", - "@sigstore/core": "^0.2.0", - "@sigstore/protobuf-specs": "^0.2.1", - "@sigstore/sign": "^2.2.1", - "@sigstore/tuf": "^2.3.0", - "@sigstore/verify": "^0.1.0" + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "@sigstore/sign": "^2.2.3", + "@sigstore/tuf": "^2.3.1", + "@sigstore/verify": "^1.1.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -11761,11 +11642,12 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", - "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.4.tgz", + "integrity": "sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==", "dev": true, "dependencies": { + "debug": "~4.3.4", "ws": "~8.11.0" } }, @@ -11794,16 +11676,16 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", "dev": true, "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -11901,9 +11783,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", - "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -11917,9 +11799,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, "node_modules/spdy": { @@ -12293,9 +12175,9 @@ "dev": true }, "node_modules/terser": { - "version": "5.26.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", - "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", + "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -12413,12 +12295,6 @@ "node": ">=8" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -12590,9 +12466,9 @@ } }, "node_modules/undici": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.2.1.tgz", - "integrity": "sha512-7Wa9thEM6/LMnnKtxJHlc8SrTlDmxqJecgz1iy8KlsN0/iskQXOQCuPkrZLXbElPaSw5slFFyKIKXyJ3UtbApw==", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.6.2.tgz", + "integrity": "sha512-vSqvUE5skSxQJ5sztTZ/CdeJb1Wq0Hf44hlYMciqHghvz+K88U0l7D6u1VsndoFgskDcnU+nG3gYmMzJVzd9Qg==", "dev": true, "dependencies": { "@fastify/busboy": "^2.0.0" @@ -12838,6 +12714,412 @@ } } }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", @@ -12879,19 +13161,19 @@ } }, "node_modules/webpack": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", - "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "version": "5.90.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.1.tgz", + "integrity": "sha512-SstPdlAC5IvgFnhiRok8hqJo/+ArAbNv7rhU4fnWGHNVfN59HSQFaxZDSAL3IFG2YmqxuRs+IU33milSxbPlog==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", + "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.11.5", "@webassemblyjs/wasm-edit": "^1.11.5", "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", @@ -12905,7 +13187,7 @@ "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", + "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -13337,10 +13619,13 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", + "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", "dev": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } @@ -13385,9 +13670,9 @@ } }, "node_modules/zone.js": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.3.tgz", - "integrity": "sha512-jYoNqF046Q+JfcZSItRSt+oXFcpXL88yq7XAZjb/NKTS7w2hHpKjRJ3VlFD1k75wMaRRXNUt5vrZVlygiMyHbA==", + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.4.tgz", + "integrity": "sha512-NtTUvIlNELez7Q1DzKVIFZBzNb646boQMgpATo9z3Ftuu/gWvzxCW7jdjcUDoRGxRikrhVHB/zLXh1hxeJawvw==", "dependencies": { "tslib": "^2.3.0" } diff --git a/corn-frontend/package.json b/corn-frontend/package.json index 242e844c..dba0d471 100644 --- a/corn-frontend/package.json +++ b/corn-frontend/package.json @@ -23,11 +23,13 @@ "@angular/router": "^17.1.0", "@angular/service-worker": "^17.1.0", "@ng-icons/akar-icons": "^26.3.0", - "@ng-icons/bootstrap-icons": "^26.3.0", + "@ng-icons/bootstrap-icons": "^26.5.0", "@ng-icons/core": "^26.3.0", + "@ng-icons/feather-icons": "^27.1.0", "@ng-icons/heroicons": "^26.3.0", "@ng-icons/material-icons": "^26.3.0", "@ng-icons/octicons": "^26.3.0", + "@ng-icons/ux-aspects": "^26.3.0", "keycloak-angular": "^15.1.0", "keycloak-js": "^23.0.5", "rxjs": "~7.8.0", diff --git a/corn-frontend/src/app/app.config.ts b/corn-frontend/src/app/app.config.ts index 2246a513..c7f53e87 100644 --- a/corn-frontend/src/app/app.config.ts +++ b/corn-frontend/src/app/app.config.ts @@ -4,7 +4,7 @@ import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { provideServiceWorker } from '@angular/service-worker'; import { provideAnimations } from '@angular/platform-browser/animations'; -import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { ErrorInterceptor } from '@core/interceptors/error.interceptor'; import { KeycloakAngularModule, KeycloakBearerInterceptor, KeycloakService } from 'keycloak-angular'; @@ -32,6 +32,7 @@ export const appConfig: ApplicationConfig = { registrationStrategy: 'registerWhenStable:30000' }), provideAnimations(), + provideHttpClient(withInterceptorsFromDi()), { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, diff --git a/corn-frontend/src/app/app.routes.ts b/corn-frontend/src/app/app.routes.ts index b0bed513..affa9436 100644 --- a/corn-frontend/src/app/app.routes.ts +++ b/corn-frontend/src/app/app.routes.ts @@ -1,7 +1,6 @@ import { Routes } from '@angular/router'; import { BoardsPaths } from '@core/enum/BoardsPaths'; import { RouterPaths } from "@core/enum/RouterPaths"; -import { authGuard } from "@core/guards/auth.guard"; export const routes: Routes = [ { @@ -9,11 +8,16 @@ export const routes: Routes = [ loadComponent: () => import("@pages/home/home.component") .then(c => c.HomeComponent) }, + { + path: RouterPaths.PROJECT_LIST_PATH, + loadComponent: () => import("@pages/project-list/project-list.component") + .then(c => c.ProjectListComponent) + }, { path: RouterPaths.BOARDS_PATH, loadComponent: () => import("@pages/boards/boards.component") .then(c => c.BoardsComponent), - canActivate: [authGuard], + // canActivate: [authGuard], children: [ { path: BoardsPaths.BACKLOG, diff --git a/corn-frontend/src/app/core/enum/BacklogItemStatus.ts b/corn-frontend/src/app/core/enum/BacklogItemStatus.ts new file mode 100644 index 00000000..39cdea35 --- /dev/null +++ b/corn-frontend/src/app/core/enum/BacklogItemStatus.ts @@ -0,0 +1,6 @@ +export enum BacklogItemStatus { + TODO = 'TODO', + IN_PROGRESS = 'IN_PROGRESS', + DONE = 'DONE' +} + diff --git a/corn-frontend/src/app/core/enum/BacklogItemType.ts b/corn-frontend/src/app/core/enum/BacklogItemType.ts new file mode 100644 index 00000000..2a197abd --- /dev/null +++ b/corn-frontend/src/app/core/enum/BacklogItemType.ts @@ -0,0 +1,6 @@ +export enum BacklogItemType { + BUG = 'BUG', + TASK = 'TASK', + STORY = 'STORY', + EPIC = 'EPIC', +} \ No newline at end of file diff --git a/corn-frontend/src/app/core/enum/RouterPaths.ts b/corn-frontend/src/app/core/enum/RouterPaths.ts index a924ee01..21c1ee0c 100644 --- a/corn-frontend/src/app/core/enum/RouterPaths.ts +++ b/corn-frontend/src/app/core/enum/RouterPaths.ts @@ -5,5 +5,6 @@ export enum RouterPaths { HOME_DIRECT_PATH = "/home", BOARDS_PATH = "boards", - UNKNOWN_PATH = "**", + PROJECT_LIST_PATH = "projects", + UNKNOWN_PATH = "**" } diff --git a/corn-frontend/src/app/core/enum/api-url.ts b/corn-frontend/src/app/core/enum/api-url.ts new file mode 100644 index 00000000..240e28db --- /dev/null +++ b/corn-frontend/src/app/core/enum/api-url.ts @@ -0,0 +1,14 @@ +export enum ApiUrl { + SPRINT_API_URL = '/api/v1/sprint', + BACKLOG_ITEM_API_URL = '/api/v1/backlog/item', + PROJECT_MEMBER_API_URL = '/api/v1/project/assignee', + + GET_BACKLOG_ITEMS_BY_PROJECT_ID = BACKLOG_ITEM_API_URL + '/getByProject', + CREATE_BACKLOG_ITEM = BACKLOG_ITEM_API_URL + '/add', + UPDATE_BACKLOG_ITEM = BACKLOG_ITEM_API_URL + '/update', + DELETE_BACKLOG_ITEM = BACKLOG_ITEM_API_URL + '/delete', + + GET_SPRINTS_ON_PAGE = SPRINT_API_URL + '/getSprintsOnPage', + + GET_PROJECT_MEMBERS = PROJECT_MEMBER_API_URL + '/getMembers' +} diff --git a/corn-frontend/src/app/core/interfaces/boards/backlog/backlog.item.list.ts b/corn-frontend/src/app/core/interfaces/boards/backlog/backlog.item.list.ts new file mode 100644 index 00000000..f8381658 --- /dev/null +++ b/corn-frontend/src/app/core/interfaces/boards/backlog/backlog.item.list.ts @@ -0,0 +1,6 @@ +import { BacklogItem } from "@interfaces/boards/backlog/backlog.item"; + +export interface BacklogItemList { + backlogItemResponseList: BacklogItem[], + totalNumber: number +} \ No newline at end of file diff --git a/corn-frontend/src/app/core/interfaces/boards/backlog/backlog.item.ts b/corn-frontend/src/app/core/interfaces/boards/backlog/backlog.item.ts new file mode 100644 index 00000000..d8d173f0 --- /dev/null +++ b/corn-frontend/src/app/core/interfaces/boards/backlog/backlog.item.ts @@ -0,0 +1,14 @@ +import { BacklogItemStatus } from "@core/enum/BacklogItemStatus"; +import { BacklogItemType } from "@core/enum/BacklogItemType"; +import { User } from "@interfaces/boards/user"; + +export interface BacklogItem { + backlogItemId: number, + title: string, + description: string, + status: BacklogItemStatus, + itemType: BacklogItemType, + assignee: User, + sprintId: number, + projectId: number +} diff --git a/corn-frontend/src/app/core/interfaces/boards/backlog/sprint.ts b/corn-frontend/src/app/core/interfaces/boards/backlog/sprint.ts new file mode 100644 index 00000000..201c05f7 --- /dev/null +++ b/corn-frontend/src/app/core/interfaces/boards/backlog/sprint.ts @@ -0,0 +1,8 @@ +export interface Sprint { + sprintId: number, + projectId: number, + sprintName: string, + sprintDescription: string, + startDate: Date, + endDate: Date +} \ No newline at end of file diff --git a/corn-frontend/src/app/core/interfaces/boards/user.ts b/corn-frontend/src/app/core/interfaces/boards/user.ts new file mode 100644 index 00000000..82a304ba --- /dev/null +++ b/corn-frontend/src/app/core/interfaces/boards/user.ts @@ -0,0 +1,6 @@ +export interface User { + userId: number; + name: string; + surname: string; + username: string; +} diff --git a/corn-frontend/src/app/core/services/boards/backlog/backlog-item/backlog-item.service.spec.ts b/corn-frontend/src/app/core/services/boards/backlog/backlog-item/backlog-item.service.spec.ts new file mode 100644 index 00000000..633eea2c --- /dev/null +++ b/corn-frontend/src/app/core/services/boards/backlog/backlog-item/backlog-item.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { BacklogItemService } from './backlog-item.service'; + +describe('BacklogItemService', () => { + let service: BacklogItemService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(BacklogItemService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/corn-frontend/src/app/core/services/boards/backlog/backlog-item/backlog-item.service.ts b/corn-frontend/src/app/core/services/boards/backlog/backlog-item/backlog-item.service.ts new file mode 100644 index 00000000..fad92431 --- /dev/null +++ b/corn-frontend/src/app/core/services/boards/backlog/backlog-item/backlog-item.service.ts @@ -0,0 +1,64 @@ +import { Injectable } from "@angular/core"; +import { HttpClient } from "@angular/common/http"; +import { Observable } from "rxjs"; +import { BacklogItem } from "@interfaces/boards/backlog/backlog.item"; +import { environment } from "@environments/environment"; +import { ApiUrl } from "@core/enum/api-url"; +import { BacklogItemType } from "@core/enum/BacklogItemType"; +import { BacklogItemList } from "@interfaces/boards/backlog/backlog.item.list"; + +@Injectable({ + providedIn: 'root' +}) +export class BacklogItemService { + + constructor(private http: HttpClient) { + } + + getAllByProjectId(projectId: number, pageNumber: number, sortBy: string, order: string): Observable { + return this.http.get(`${ environment.httpBackend }${ ApiUrl.GET_BACKLOG_ITEMS_BY_PROJECT_ID }`, { + params: { + projectId: projectId, + pageNumber: pageNumber, + sortBy: sortBy, + order: order + } + }); + } + + createNewBacklogItem(title: string, description: string, projectMemberId: number, sprintId: number, + projectId: number, itemType: BacklogItemType): Observable { + return this.http.post(`${ ApiUrl.CREATE_BACKLOG_ITEM }`, { + title: title, + description: description, + projectMemberId: projectMemberId, + sprintId: sprintId, + projectId: projectId, + itemType: itemType.toString() + }) + } + + updateBacklogItem(item: BacklogItem): Observable { + return this.http.put(`${ApiUrl.UPDATE_BACKLOG_ITEM}`, { + title: item.title, + description: item.description, + projectMemberId: item.assignee.userId, + sprintId: item.sprintId, + projectId: item.projectId, + itemType: item.itemType.toString(), + itemStatus: item.status.toString() + }, { + params: { + id: item.backlogItemId + } + }) + } + + deleteBacklogItem(item: BacklogItem): Observable { + return this.http.delete(`${ApiUrl.DELETE_BACKLOG_ITEM}`, { + params: { + id: item.backlogItemId + } + }) + } +} \ No newline at end of file diff --git a/corn-frontend/src/app/core/services/boards/backlog/sprint/sprint.service.ts b/corn-frontend/src/app/core/services/boards/backlog/sprint/sprint.service.ts new file mode 100644 index 00000000..f5cc482c --- /dev/null +++ b/corn-frontend/src/app/core/services/boards/backlog/sprint/sprint.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from "@angular/core"; +import { HttpClient } from "@angular/common/http"; +import { Observable } from "rxjs"; +import { Sprint } from "@interfaces/boards/backlog/sprint"; +import { ApiUrl } from "@core/enum/api-url"; + +@Injectable({ + providedIn: 'root' +}) +export class SprintService { + + constructor(private http: HttpClient) { + + } + + getSprintsOnPageForProject(projectId: number, pageNumber: number): Observable { + return this.http.get(`${ ApiUrl.GET_SPRINTS_ON_PAGE }`, { + params: { + page: pageNumber, + projectId: projectId + } + }); + } +} \ No newline at end of file diff --git a/corn-frontend/src/app/core/services/users/user.service.spec.ts b/corn-frontend/src/app/core/services/users/user.service.spec.ts new file mode 100644 index 00000000..ae806389 --- /dev/null +++ b/corn-frontend/src/app/core/services/users/user.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UserService } from './user.service'; + +describe('UserServiceService', () => { + let service: UserService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UserService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/corn-frontend/src/app/core/services/users/user.service.ts b/corn-frontend/src/app/core/services/users/user.service.ts new file mode 100644 index 00000000..58339182 --- /dev/null +++ b/corn-frontend/src/app/core/services/users/user.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { User } from "@interfaces/boards/user"; +import { HttpClient } from "@angular/common/http"; +import { Observable } from "rxjs"; +import { ApiUrl } from "@core/enum/api-url"; + +@Injectable({ + providedIn: 'root' +}) +export class UserService { + + constructor(private http: HttpClient) { + } + + getProjectMembersOnPage(projectId: number, page: number): Observable { + return this.http.get(`${ApiUrl.GET_PROJECT_MEMBERS}`, { + params: { + projectId: projectId, + page: page + } + }) + } +} diff --git a/corn-frontend/src/app/core/validators/custom-validators.spec.ts b/corn-frontend/src/app/core/validators/custom-validators.spec.ts new file mode 100644 index 00000000..9d0c0620 --- /dev/null +++ b/corn-frontend/src/app/core/validators/custom-validators.spec.ts @@ -0,0 +1,7 @@ +import { CustomValidators } from './custom-validators'; + +describe('CustomValidators', () => { + it('should create an instance', () => { + expect(new CustomValidators()).toBeTruthy(); + }); +}); diff --git a/corn-frontend/src/app/core/validators/custom-validators.ts b/corn-frontend/src/app/core/validators/custom-validators.ts new file mode 100644 index 00000000..9e5703fa --- /dev/null +++ b/corn-frontend/src/app/core/validators/custom-validators.ts @@ -0,0 +1,14 @@ +import { AbstractControl, ValidationErrors, ValidatorFn } from "@angular/forms"; + +export class CustomValidators { + + static notWhitespace(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + if(control.value === null) { + return null; + } + const isNotWhitespace = (control.value || '').trim().length > 0; + return isNotWhitespace ? null : {'notWhitespace': true}; + } + } +} diff --git a/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.html b/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.html new file mode 100644 index 00000000..bf0e4059 --- /dev/null +++ b/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.html @@ -0,0 +1,161 @@ +

Add Backlog Item

+ +
+ + Title + + + @if(itemForm.controls['title'].hasError('required')) { + Title is required + } @else if (itemForm.controls['title'].hasError('maxlength')) { + Title cannot be more than 100 characters + } @else if (itemForm.controls['title'].hasError('notWhitespace')) { + Title cannot be only whitespace + } + + + + Description + + {{textArea.textLength}} / {{textArea.maxLength}} + + @if(itemForm.controls['description'].hasError('required')) { + Description is required + } @else if (itemForm.controls['description'].hasError('maxlength')) { + Description cannot be more than 500 characters + } @else if (itemForm.controls['description'].hasError('notWhitespace')) { + Description cannot be only whitespace + } + + + + +
+
+

Type

+ + + + @switch(currentType) { + @case (BacklogItemType.BUG) { +
+ +
+ } + + @case (BacklogItemType.STORY) { +
+ +
+ } + + @case (BacklogItemType.TASK) { +
+ +
+ } + + @case (BacklogItemType.EPIC) { +
+ +
+ } + } +
+ @for (type of types; track type) { + + @switch (type) { + @case (BacklogItemType.BUG) { +
+
+ +
+

Bug

+
+ } + + @case (BacklogItemType.STORY) { +
+
+ +
+

Story

+
+ } + + @case (BacklogItemType.TASK) { +
+
+ +
+

Task

+
+ } + + @case (BacklogItemType.EPIC) { +
+
+ +
+

Epic

+
+ } + } +
+ } +
+ + @if(itemForm.controls['type'].hasError('required')) { + Type is required + } +
+
+ +
+

Assignee

+ + + +
+ +
+
+ @for (user of users; track user) { + +
+ +
+
+ } +
+ + @if(itemForm.controls['assignee'].hasError('required')) { + Assignee is required + } +
+
+ + + Sprint + + @for (sprint of sprints; track sprint) { + + {{sprint.sprintName}} + + } + + + @if(itemForm.controls['sprint'].hasError('required')) { + Sprint is required + } + +
+
+
+ + +
+ + +
+
\ No newline at end of file diff --git a/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.scss b/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.spec.ts b/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.spec.ts new file mode 100644 index 00000000..0ea53413 --- /dev/null +++ b/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { BacklogFormComponent } from './backlog-form.component'; + +describe('BacklogFormComponent', () => { + let component: BacklogFormComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [BacklogFormComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(BacklogFormComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.ts b/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.ts new file mode 100644 index 00000000..10e73a09 --- /dev/null +++ b/corn-frontend/src/app/pages/boards/backlog/backlog-form/backlog-form.component.ts @@ -0,0 +1,222 @@ +import { AfterViewInit, Component, NgZone, OnDestroy, ViewChild } from '@angular/core'; +import { + MatDialogActions, + MatDialogClose, + MatDialogContent, + MatDialogRef, + MatDialogTitle +} from "@angular/material/dialog"; +import { FormControl, FormGroup, ReactiveFormsModule, Validators } from "@angular/forms"; +import { CustomValidators } from "@core/validators/custom-validators"; +import { MatError, MatHint } from "@angular/material/form-field"; +import { MatInput } from "@angular/material/input"; +import { MatButton, } from "@angular/material/button"; +import { + MatFormField, + MatLabel, + MatOption, + MatSelect, + MatSelectChange, + MatSelectTrigger +} from "@angular/material/select"; +import { BacklogItemType } from "@core/enum/BacklogItemType"; +import { MatTooltip } from "@angular/material/tooltip"; +import { NgIcon, provideIcons } from "@ng-icons/core"; +import { bootstrapBugFill } from "@ng-icons/bootstrap-icons"; +import { featherBook } from "@ng-icons/feather-icons"; +import { matTask } from "@ng-icons/material-icons/baseline"; +import { octContainer } from "@ng-icons/octicons"; +import { User } from "@core/interfaces/boards/user"; +import { UserAvatarComponent } from "@pages/utils/user-avatar/user-avatar.component"; +import { MatIcon } from "@angular/material/icon"; +import { CdkTextareaAutosize } from "@angular/cdk/text-field"; +import { Sprint } from "@interfaces/boards/backlog/sprint"; +import { CdkScrollable, ScrollDispatcher, ScrollingModule } from "@angular/cdk/scrolling"; +import { Subject, take, takeUntil } from "rxjs"; +import { SprintService } from "@core/services/boards/backlog/sprint/sprint.service"; +import { UserService } from "@core/services/users/user.service"; + +@Component({ + selector: 'app-backlog-form', + standalone: true, + imports: [ + MatDialogTitle, + MatDialogContent, + ReactiveFormsModule, + MatError, + MatFormField, + MatInput, + MatLabel, + MatDialogActions, + MatDialogClose, + MatButton, + MatHint, + MatSelect, + MatOption, + MatTooltip, + NgIcon, + UserAvatarComponent, + MatSelectTrigger, + MatIcon, + CdkTextareaAutosize, + ScrollingModule + ], + templateUrl: './backlog-form.component.html', + providers: [provideIcons({ bootstrapBugFill, featherBook, matTask, octContainer })], + styleUrl: './backlog-form.component.scss' +}) +export class BacklogFormComponent implements AfterViewInit, OnDestroy { + + constructor(public dialogRef: MatDialogRef, + private scrollDispatcher: ScrollDispatcher, + private ngZone: NgZone, + private sprintService: SprintService, + private userService: UserService) { + } + + private readonly sprintPageSize: number = 20; + private sprintsPageNumber: number = 0; + + private readonly membersPageSize: number = 20; + private membersPageNumber: number = 0; + + destroy$: Subject = new Subject(); + + sprints: Sprint[] = []; + + currentUser ?: User; + currentType ?: BacklogItemType; + + @ViewChild('sprintSelect') sprintSelect !: MatSelect; + @ViewChild('memberSelect') memberSelect !: MatSelect; + + itemForm: FormGroup = new FormGroup({ + title: new FormControl('', [ + Validators.required, + Validators.maxLength(100), + CustomValidators.notWhitespace(), + ]), + description: new FormControl('', [ + Validators.required, + Validators.maxLength(500), + CustomValidators.notWhitespace(), + ]), + type: new FormControl('', [ + Validators.required + ]), + assignee: new FormControl('', [ + Validators.required + ]), + sprint: new FormControl('', [ + Validators.required + ]) + }); + + protected readonly BacklogItemType = BacklogItemType; + + types: BacklogItemType[] = [ + BacklogItemType.STORY, + BacklogItemType.BUG, + BacklogItemType.TASK, + BacklogItemType.EPIC + ]; + users: User[] = []; + + submitForm(): void { + if (this.itemForm.invalid) { + return; + } + let data = { + title: this.itemForm.get('title')?.value, + description: this.itemForm.get('description')?.value, + sprintId: this.itemForm.get('sprint')?.value, + type: this.itemForm.get('type')?.value, + assignee: this.itemForm.get('assignee')?.value + }; + + this.dialogRef.close(data); + } + + changeCurrentUser(event: MatSelectChange): void { + this.currentUser = event.value; + } + + changeCurrentType(event: MatSelectChange): void { + this.currentType = event.value; + } + + ngAfterViewInit(): void { + this.userService.getProjectMembersOnPage(1, this.membersPageNumber).pipe(take(1)).subscribe(users => { + this.users = users; + }); + this.sprintService.getSprintsOnPageForProject(1, this.sprintsPageNumber).pipe(take(1)).subscribe(sprints => { + this.sprints = sprints; + }); + + this.subscribeToSprintScroll(); + this.subscribeToMemberScroll(); + + } + + subscribeToSprintScroll(): void { + this.sprintSelect.openedChange.pipe(takeUntil(this.destroy$)).subscribe(opened => { + if (!opened) { + return; + } + const scrollable = new CdkScrollable(this.sprintSelect.panel, this.scrollDispatcher, this.ngZone); + scrollable.elementScrolled().pipe(takeUntil(this.destroy$)).subscribe(() => { + this.ngZone.runOutsideAngular(() => { + if (this.sprints.length % this.sprintPageSize !== 0) { + return; + } + const element = scrollable.getElementRef().nativeElement; + const atBottom = element.scrollTop + element.offsetHeight >= element.scrollHeight; + if (!atBottom) { + return; + } + this.sprintsPageNumber++; + this.sprintService.getSprintsOnPageForProject(1, this.sprintsPageNumber).pipe(take(1)).subscribe(newSprints => { + this.ngZone.run(() => { + this.sprints = [...this.sprints, ...newSprints]; + }) + }) + }) + }); + }) + } + + subscribeToMemberScroll(): void { + this.memberSelect.openedChange.pipe(takeUntil(this.destroy$)).subscribe(opened => { + if (!opened) { + return; + } + const scrollable: CdkScrollable = new CdkScrollable(this.memberSelect.panel, this.scrollDispatcher, this.ngZone); + scrollable.elementScrolled().pipe(takeUntil(this.destroy$)).subscribe(() => { + this.ngZone.runOutsideAngular(() => { + if (this.users.length % this.membersPageSize !== 0) { + return; + } + const element = scrollable.getElementRef().nativeElement; + const atBottom = element.scrollTop + element.offsetHeight >= element.scrollHeight; + if (!atBottom) { + return; + } + this.membersPageNumber++; + this.userService.getProjectMembersOnPage(1, this.membersPageNumber).pipe(take(1)).subscribe(newUsers => { + this.ngZone.run(() => { + this.users = [...this.users, ...newUsers]; + }) + }) + }) + }) + }) + } + + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + +} diff --git a/corn-frontend/src/app/pages/boards/backlog/backlog.component.html b/corn-frontend/src/app/pages/boards/backlog/backlog.component.html index 0b28b473..2dc64f10 100644 --- a/corn-frontend/src/app/pages/boards/backlog/backlog.component.html +++ b/corn-frontend/src/app/pages/boards/backlog/backlog.component.html @@ -1 +1,88 @@ -

Backlog

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Status +
+ + @for (status of statuses; track status) { + {{ status.replace('_', ' ')}} + + } + +
+
Title{{ backlogItem.title }}Description{{ backlogItem.description }}Type + @switch (backlogItem.itemType) { + @case (BacklogItemType.BUG) { +
+ +
+ } + @case (BacklogItemType.STORY) { +
+ +
+ } + @case (BacklogItemType.TASK) { +
+ +
+ } + @case (BacklogItemType.EPIC) { +
+ +
+ } + } +
Assignee +
+
+ +
+ @if (backlogItem == hoveredRow) { + + } +
+
+ + + + + +@if (isLoading) { +
+ +
+} \ No newline at end of file diff --git a/corn-frontend/src/app/pages/boards/backlog/backlog.component.scss b/corn-frontend/src/app/pages/boards/backlog/backlog.component.scss new file mode 100644 index 00000000..65781724 --- /dev/null +++ b/corn-frontend/src/app/pages/boards/backlog/backlog.component.scss @@ -0,0 +1,107 @@ +@import '../../../../styles/theme'; +$background-color: map-get($dark-color-settings, container-background-color); +$background-color-hover: lighten($background-color, 5%); + +.todo { + background-color: #737373; +} + +.in-progress { + background-color: #0089c5; +} + +.done { + background-color: #029b40; +} + +table .table-row:hover { + cursor: pointer; + background-color: $background-color-hover; + outline: 1.5px solid rgba(194, 194, 194, 0.8); +} + +.status-background { + border-radius: 5px; + width: max-content; + height: 2em; + display: flex; + align-items: center; + justify-content: center; +} + +.status-background:hover { + cursor: pointer; +} + +.status-background.TODO { + background-color: #464444; +} + +.status-background.TODO:hover { + background-color: lighten(#464444, 10%); +} + +.status-background.IN_PROGRESS { + background-color: rgba(67,183,239,0.35); +} + +.status-background.IN_PROGRESS:hover { + background-color: lighten(rgba(67,183,239,0.35), 10%); +} + +.status-background.DONE { + background-color: rgba(14,168,4,0.35); +} + +.status-background.DONE:hover { + background-color: lighten(rgba(14,168,4,0.35), 10%); +} + +.status-panel { + font-size: 0.5em; + width: 3em; +} + +.status-panel-TODO { + background-color: #464444!important; +} + +.status-panel-TODO:hover { + background-color: lighten(#464444, 10%)!important; +} + +.status-panel-IN_PROGRESS { + background-color: rgba(67,183,239,0.35)!important; +} + +.status-panel-IN_PROGRESS:hover { + background-color: lighten(rgba(67,183,239,0.35), 10%)!important; +} + +.status-panel-DONE { + background-color: rgba(14,168,4, 0.55)!important; +} + +.status-panel-DONE:hover { + background-color: lighten(rgba(14,168,4, 0.55), 10%)!important; +} + +.type-icon { + height: 2em; + width: 2em; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; +} + +mat-select { + width: max-content; + margin-left: 0.5em; + margin-right: 0.5em; +} + +.avatar-container { + width: 2.5em; + height: 2.5em; +} \ No newline at end of file diff --git a/corn-frontend/src/app/pages/boards/backlog/backlog.component.ts b/corn-frontend/src/app/pages/boards/backlog/backlog.component.ts index 8664bf22..5e672494 100644 --- a/corn-frontend/src/app/pages/boards/backlog/backlog.component.ts +++ b/corn-frontend/src/app/pages/boards/backlog/backlog.component.ts @@ -1,10 +1,193 @@ -import { Component } from '@angular/core'; +import { AfterViewInit, Component, OnDestroy, ViewChild, ViewEncapsulation } from '@angular/core'; +import { + MatCell, + MatCellDef, + MatColumnDef, + MatHeaderCell, + MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + MatTable, +} from "@angular/material/table"; +import { BacklogItem } from '@interfaces/boards/backlog/backlog.item'; +import { NgIcon, provideIcons } from "@ng-icons/core"; +import { matDelete, matTask } from "@ng-icons/material-icons/baseline"; +import { BacklogItemStatus } from "@core/enum/BacklogItemStatus"; +import { BacklogItemType } from "@core/enum/BacklogItemType"; +import { MatFormField, MatLabel, MatOption, MatSelect } from "@angular/material/select"; +import { NgClass, NgForOf } from "@angular/common"; +import { UserAvatarComponent } from "@pages/utils/user-avatar/user-avatar.component"; +import { bootstrapBugFill } from "@ng-icons/bootstrap-icons"; +import { MatTooltip } from "@angular/material/tooltip"; +import { featherBook } from "@ng-icons/feather-icons"; +import { octContainer } from "@ng-icons/octicons"; +import { MatSort, MatSortHeader } from "@angular/material/sort"; +import { MatButton, MatButtonModule, MatFabButton, MatIconButton } from "@angular/material/button"; +import { FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { MatInput } from "@angular/material/input"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatDialog } from "@angular/material/dialog"; +import { BacklogFormComponent } from "@pages/boards/backlog/backlog-form/backlog-form.component"; +import { MatProgressSpinner } from "@angular/material/progress-spinner"; +import { MatPaginator } from "@angular/material/paginator"; +import { catchError, merge, of, startWith, Subject, switchMap, take, takeUntil } from "rxjs"; +import { BacklogItemService } from "@core/services/boards/backlog/backlog-item/backlog-item.service"; +import { map } from "rxjs/operators"; +import { MatIcon } from "@angular/material/icon"; @Component({ selector: 'app-backlog', standalone: true, - imports: [], + imports: [ + MatTable, + MatColumnDef, + MatHeaderCell, + MatCell, + MatCellDef, + MatHeaderCellDef, + MatHeaderRow, + MatHeaderRowDef, + MatRow, + MatRowDef, + NgIcon, + MatSelect, + MatOption, + NgClass, + NgForOf, + UserAvatarComponent, + MatTooltip, + MatSortHeader, + MatSort, + MatButton, + MatFabButton, + FormsModule, + ReactiveFormsModule, + MatLabel, + MatInput, + MatFormField, + MatFormFieldModule, + MatProgressSpinner, + MatPaginator, + MatIcon, + MatIconButton, + MatButtonModule + ], templateUrl: './backlog.component.html', + styleUrl: './backlog.component.scss', + providers: [provideIcons({ bootstrapBugFill, featherBook, matTask, octContainer, matDelete })], + encapsulation: ViewEncapsulation.None }) -export class BacklogComponent { +export class BacklogComponent implements AfterViewInit, OnDestroy { + + constructor(public dialog: MatDialog, + private backlogItemService: BacklogItemService) { + } + + @ViewChild(MatSort) sort!: MatSort; + @ViewChild(MatPaginator) paginator!: MatPaginator; + + destroy$: Subject = new Subject(); + + resultsLength: number = 0; + hoveredRow: BacklogItem | null = null; + isLoading: boolean = true; + + statuses: BacklogItemStatus[] = [ + BacklogItemStatus.TODO, + BacklogItemStatus.IN_PROGRESS, + BacklogItemStatus.DONE + ]; + + dataToDisplay: BacklogItem[] = []; + displayedColumns = ['title', 'description', 'status', 'type', 'assignee']; + + protected readonly BacklogItemType = BacklogItemType; + + ngAfterViewInit(): void { + this.sort.sortChange.pipe(takeUntil(this.destroy$)).subscribe( + () => (this.paginator.pageIndex = 0)); + + merge(this.sort.sortChange, this.paginator.page) + .pipe( + startWith({}), + switchMap(() => { + this.fetchBacklogItems(); + return of(null); + }) + ).pipe(takeUntil(this.destroy$)).subscribe(); + } + + fetchBacklogItems(): void { + this.isLoading = true; + let active: string = this.sort.active === 'type' ? 'itemType' : this.sort.active; + this.backlogItemService.getAllByProjectId( + 1, //TODO get real projectId from somewhere + this.paginator.pageIndex, + active, + this.sort.direction.toUpperCase()) + .pipe( + catchError(() => of(null)), + map(data => { + this.isLoading = false; + + if (!data) { + return []; + } + + this.resultsLength = data.totalNumber; + return data.backlogItemResponseList; + }), + takeUntil(this.destroy$) + ).subscribe(data => { + this.dataToDisplay = data; + }) + } + + getStatusClass(status: BacklogItemStatus): string { + return status.replace(' ', '_'); + } + + deleteItem(item: BacklogItem): void { + this.backlogItemService.deleteBacklogItem(item).pipe(take(1)).subscribe((deletedItem: BacklogItem) => { + this.dataToDisplay = this.dataToDisplay.filter((i) => i !== item); + this.resultsLength -= 1; + }); + } + + showItemForm(): void { + const dialogRef = this.dialog.open(BacklogFormComponent, { + width: '500px', + enterAnimationDuration: '300ms', + exitAnimationDuration: '100ms', + }); + + dialogRef.afterClosed().pipe(take(1)).subscribe(result => { + if (!result) { + return; + } + this.backlogItemService.createNewBacklogItem( + result.title, + result.description, + result.assignee.userId, + result.sprintId, + 1, //TODO get real projectId from somewhere + result.type + ).pipe(take(1)).subscribe((newItem) => { + this.fetchBacklogItems(); + }) + }) + } + + updateStatus(item: BacklogItem): void { + this.backlogItemService.updateBacklogItem(item).pipe(take(1)).subscribe((newItem) => { + this.dataToDisplay[this.dataToDisplay.indexOf(item)] = newItem; + }) + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } } diff --git a/corn-frontend/src/app/pages/boards/board/change_assignee_menu/change_assignee_menu.component.ts b/corn-frontend/src/app/pages/boards/board/change_assignee_menu/change_assignee_menu.component.ts index 98da266f..9c405cf6 100644 --- a/corn-frontend/src/app/pages/boards/board/change_assignee_menu/change_assignee_menu.component.ts +++ b/corn-frontend/src/app/pages/boards/board/change_assignee_menu/change_assignee_menu.component.ts @@ -1,6 +1,5 @@ -import { ElementRef, Input } from '@angular/core'; +import { Component, ElementRef, Input, ViewChild } from '@angular/core'; import { MatMenuModule } from '@angular/material/menu'; -import { Component, ViewChild } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MatInputModule } from '@angular/material/input'; import { MatButtonModule } from '@angular/material/button'; diff --git a/corn-frontend/src/app/pages/boards/boards.component.ts b/corn-frontend/src/app/pages/boards/boards.component.ts index 0e49a518..8c7cf712 100644 --- a/corn-frontend/src/app/pages/boards/boards.component.ts +++ b/corn-frontend/src/app/pages/boards/boards.component.ts @@ -14,6 +14,8 @@ import { UserinfoComponent } from '@pages/boards/userinfo/userinfo.component'; import { KeycloakService } from 'keycloak-angular'; import { KeycloakProfile } from 'keycloak-js'; import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu'; +import { RouterPaths } from '@core/enum/RouterPaths'; +import { BoardsPaths } from '@core/enum/BoardsPaths'; @Component({ selector: 'app-boards', @@ -70,16 +72,15 @@ export class BoardsComponent implements OnInit { } navigateToBacklog(): void { - this.router.navigate(['/boards/backlog']); + this.router.navigate([`/${RouterPaths.BOARDS_PATH}/${BoardsPaths.BACKLOG}`]); } navigateToTimeline(): void { - this.router.navigate(['/boards/timeline']); + this.router.navigate([`/${RouterPaths.BOARDS_PATH}/${BoardsPaths.TIMELINE}`]); } navigateToBoard(): void { - //TODO substitute literals with values from BoardPaths.ts enum in these methods - this.router.navigate(['/boards/board']); + this.router.navigate([`/${RouterPaths.BOARDS_PATH}/${BoardsPaths.BOARD}`]); } toggleSidebar(): void { diff --git a/corn-frontend/src/app/pages/home/home.component.html b/corn-frontend/src/app/pages/home/home.component.html index 744c5edb..188802b5 100644 --- a/corn-frontend/src/app/pages/home/home.component.html +++ b/corn-frontend/src/app/pages/home/home.component.html @@ -1,6 +1,6 @@
- icon + icon
diff --git a/corn-frontend/src/app/pages/project-list/project-list.component.html b/corn-frontend/src/app/pages/project-list/project-list.component.html index 72d5ae8a..9374e9a4 100644 --- a/corn-frontend/src/app/pages/project-list/project-list.component.html +++ b/corn-frontend/src/app/pages/project-list/project-list.component.html @@ -1 +1,18 @@ -

project-list works!

+
+ + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/corn-frontend/src/app/pages/project-list/project-list.component.scss b/corn-frontend/src/app/pages/project-list/project-list.component.scss index e69de29b..c5dda732 100644 --- a/corn-frontend/src/app/pages/project-list/project-list.component.scss +++ b/corn-frontend/src/app/pages/project-list/project-list.component.scss @@ -0,0 +1,15 @@ +@import '../../../styles/screen'; + +.project-list { + overflow-x: auto; + width: 100%; + height: 100%; +} + +mat-grid-list { + min-width: calc(5*16em + 10em); + + @media(max-width: $screen-840) { + min-width: calc(3*11em + 6em); + } +} diff --git a/corn-frontend/src/app/pages/project-list/project-list.component.ts b/corn-frontend/src/app/pages/project-list/project-list.component.ts index 6f8e88e3..d0d40915 100644 --- a/corn-frontend/src/app/pages/project-list/project-list.component.ts +++ b/corn-frontend/src/app/pages/project-list/project-list.component.ts @@ -1,12 +1,41 @@ -import { Component } from '@angular/core'; +import { Component, HostListener } from '@angular/core'; +import { ProjectComponent } from "@pages/project-list/project/project.component"; +import { MatGridList, MatGridTile } from "@angular/material/grid-list"; +import { User } from "@core/interfaces/boards/user"; @Component({ - selector: 'app-project-list', - standalone: true, - imports: [], - templateUrl: './project-list.component.html', - styleUrl: './project-list.component.scss' + selector: 'app-project-list', + standalone: true, + imports: [ + ProjectComponent, + MatGridList, + MatGridTile + ], + templateUrl: './project-list.component.html', + styleUrl: './project-list.component.scss' }) export class ProjectListComponent { + cols = 5; + + exampleUsers: User[] = [ + {userId: 0, name: 'John', surname: 'Doe', username: 'johndoe'}, + {userId: 1, name: 'Szymon', surname: 'Kowalski', username: 'szymoneks'}, + {userId: 2, name: 'Andrzej', surname: 'Switch', username: 'manual'}, + {userId: 3, name: 'Paweł', surname: 'Tagowski', username: 'dziendobrypanstwu'} + ]; + + @HostListener('window:resize', ['$event']) + onResize(event: any) { + this.adjustCols(); + } + + adjustCols() { + if(window.innerWidth <= 840) { + this.cols = 3; + } else { + this.cols = 5; + } + } + } diff --git a/corn-frontend/src/app/pages/project-list/project/_project.component-theme.scss b/corn-frontend/src/app/pages/project-list/project/_project.component-theme.scss new file mode 100644 index 00000000..8d9a1710 --- /dev/null +++ b/corn-frontend/src/app/pages/project-list/project/_project.component-theme.scss @@ -0,0 +1,13 @@ +@use 'sass:map'; +@use '@angular/material' as mat; + + +@mixin color($theme) { + .background { + background-color: mat.get-theme-color($theme, primary, 700); + } +} + +@mixin theme($theme) { + @include color($theme); +} \ No newline at end of file diff --git a/corn-frontend/src/app/pages/project-list/project/project.component.html b/corn-frontend/src/app/pages/project-list/project/project.component.html index 8ea00ea1..2c5f5cd9 100644 --- a/corn-frontend/src/app/pages/project-list/project/project.component.html +++ b/corn-frontend/src/app/pages/project-list/project/project.component.html @@ -1 +1,27 @@ -

project works!

+
+
+
+ +
+

{{ title }}

+ @if(title !== '') { +
+ } +
+ +
+ @for (member of members | slice:0:3; track 1) { +
+ +
+ } + @if (members.length > 3) { +
+ +
+ } +
+ +
+
+
diff --git a/corn-frontend/src/app/pages/project-list/project/project.component.scss b/corn-frontend/src/app/pages/project-list/project/project.component.scss index e69de29b..ed2a373a 100644 --- a/corn-frontend/src/app/pages/project-list/project/project.component.scss +++ b/corn-frontend/src/app/pages/project-list/project/project.component.scss @@ -0,0 +1,104 @@ +@import '../../../../styles/theme'; +@import '../../../../styles/screen'; + +.background { + width: 16em; + height: 15em; + border-radius: 5px; + margin-left: 1em; + margin-right: 1em; + box-shadow: #000000 0 0 1em; + z-index: -2; + + @media(max-width: $screen-840) { + width: 11em; + height: 10em; + } +} + +.background:hover { + cursor: pointer; + outline: 1.5px solid rgba(194, 194, 194, 0.8); + box-shadow: #000000 0 10px 1em, #000000 0 0 1em; +} + +.project { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + margin-left: 1.05em; + width: 15em; + height: 15em; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + background-color: map-get($dark-color-settings, container-background-color); + + @media(max-width: $screen-840) { + width: 10em; + height: 10em; + } + + &:before { + content: ''; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 1.05em; + background-image: url('../../../../assets/icons/icon-512x512.png'); + background-size: cover; + opacity: 0.07; + } +} + +.project h1 { + max-width: 80%; + margin-top: 0.5em; + font-weight: bold; + font-size: 1.5em; + text-overflow: ellipsis; + overflow: hidden; + z-index: 1; + + @media(max-width: $screen-840) { + font-size: 1em; + margin-top: 0.25em; + } +} + +.line { + width: 80%; + height: 1px; + background-color: white; + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +.title { + display: flex; + flex-direction: column; + margin-top: 0.5em; + align-items: center; + width: 100%; +} + +.member{ + width: 2.7em; + height: 2.7em; + + @media (max-width: $screen-840) { + width: 1.8em; + height: 1.8em; + } +} + +.member-row { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 1em; + gap: 0.7em; + z-index: 1; +} + diff --git a/corn-frontend/src/app/pages/project-list/project/project.component.ts b/corn-frontend/src/app/pages/project-list/project/project.component.ts index 1cdb1b14..d27d4fb3 100644 --- a/corn-frontend/src/app/pages/project-list/project/project.component.ts +++ b/corn-frontend/src/app/pages/project-list/project/project.component.ts @@ -1,12 +1,25 @@ -import { Component } from '@angular/core'; +import { Component, Input } from '@angular/core'; +import { MatRipple } from "@angular/material/core"; +import { NgOptimizedImage, SlicePipe } from "@angular/common"; +import { MatTooltip } from "@angular/material/tooltip"; +import { User } from "@core/interfaces/boards/user"; +import { UserAvatarComponent } from "@pages/utils/user-avatar/user-avatar.component"; @Component({ selector: 'app-project', standalone: true, - imports: [], + imports: [ + MatRipple, + SlicePipe, + NgOptimizedImage, + MatTooltip, + UserAvatarComponent + ], templateUrl: './project.component.html', styleUrl: './project.component.scss' }) export class ProjectComponent { + @Input() title: string = ''; + @Input() members: User[] = []; } diff --git a/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.html b/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.html new file mode 100644 index 00000000..324e679a --- /dev/null +++ b/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.html @@ -0,0 +1,14 @@ +@if (user !== undefined) { +
+

+ {{getInitials()}} +

+
+} @else { +
+

+ {{getInitials()}} +

+
+} + diff --git a/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.scss b/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.scss new file mode 100644 index 00000000..7f7ae5ea --- /dev/null +++ b/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.scss @@ -0,0 +1,19 @@ +.avatar { + width: 100%; + height: 100%; + background-color: #43b7ef; + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; +} + +.avatar h2 { + color: white; + height: 100%; + width: 100%; + font-weight: bold; + display: flex; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.spec.ts b/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.spec.ts new file mode 100644 index 00000000..2209debb --- /dev/null +++ b/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserAvatarComponent } from './user-avatar.component'; + +describe('UserAvatarComponent', () => { + let component: UserAvatarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UserAvatarComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UserAvatarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.ts b/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.ts new file mode 100644 index 00000000..9b421cb2 --- /dev/null +++ b/corn-frontend/src/app/pages/utils/user-avatar/user-avatar.component.ts @@ -0,0 +1,26 @@ +import { Component, Input } from '@angular/core'; +import { User } from "@core/interfaces/boards/user"; +import { MatTooltip } from "@angular/material/tooltip"; + +@Component({ + selector: 'app-user-avatar', + standalone: true, + imports: [ + MatTooltip + ], + templateUrl: './user-avatar.component.html', + styleUrl: './user-avatar.component.scss' +}) +export class UserAvatarComponent { + + @Input() user: User | undefined; + @Input() usersLeft: number = 0; + + getInitials(): string { + if (this.user !== undefined) { + return this.user.name.charAt(0) + this.user.surname.charAt(0); + } else { + return '+' + this.usersLeft; + } + } +} diff --git a/corn-frontend/src/assets/corn-icons/icon-128x128.png b/corn-frontend/src/assets/corn-icons/icon-128x128.png deleted file mode 100644 index 5adde5ac..00000000 Binary files a/corn-frontend/src/assets/corn-icons/icon-128x128.png and /dev/null differ diff --git a/corn-frontend/src/assets/corn-icons/icon-144x144.png b/corn-frontend/src/assets/corn-icons/icon-144x144.png deleted file mode 100644 index 274e188e..00000000 Binary files a/corn-frontend/src/assets/corn-icons/icon-144x144.png and /dev/null differ diff --git a/corn-frontend/src/assets/corn-icons/icon-152x152.png b/corn-frontend/src/assets/corn-icons/icon-152x152.png deleted file mode 100644 index c3d62f42..00000000 Binary files a/corn-frontend/src/assets/corn-icons/icon-152x152.png and /dev/null differ diff --git a/corn-frontend/src/assets/corn-icons/icon-192x192.png b/corn-frontend/src/assets/corn-icons/icon-192x192.png deleted file mode 100644 index bacf06b9..00000000 Binary files a/corn-frontend/src/assets/corn-icons/icon-192x192.png and /dev/null differ diff --git a/corn-frontend/src/assets/corn-icons/icon-384x384.png b/corn-frontend/src/assets/corn-icons/icon-384x384.png deleted file mode 100644 index 4d8c2943..00000000 Binary files a/corn-frontend/src/assets/corn-icons/icon-384x384.png and /dev/null differ diff --git a/corn-frontend/src/assets/corn-icons/icon-512x512.png b/corn-frontend/src/assets/corn-icons/icon-512x512.png deleted file mode 100644 index c3604472..00000000 Binary files a/corn-frontend/src/assets/corn-icons/icon-512x512.png and /dev/null differ diff --git a/corn-frontend/src/assets/corn-icons/icon-72x72.png b/corn-frontend/src/assets/corn-icons/icon-72x72.png deleted file mode 100644 index 4d0d1b8c..00000000 Binary files a/corn-frontend/src/assets/corn-icons/icon-72x72.png and /dev/null differ diff --git a/corn-frontend/src/assets/corn-icons/icon-96x96.png b/corn-frontend/src/assets/corn-icons/icon-96x96.png deleted file mode 100644 index 51749177..00000000 Binary files a/corn-frontend/src/assets/corn-icons/icon-96x96.png and /dev/null differ diff --git a/corn-frontend/src/assets/icons/icon-128x128.png b/corn-frontend/src/assets/icons/icon-128x128.png index 5a9a2ccd..5adde5ac 100644 Binary files a/corn-frontend/src/assets/icons/icon-128x128.png and b/corn-frontend/src/assets/icons/icon-128x128.png differ diff --git a/corn-frontend/src/assets/icons/icon-144x144.png b/corn-frontend/src/assets/icons/icon-144x144.png index 11702cd7..274e188e 100644 Binary files a/corn-frontend/src/assets/icons/icon-144x144.png and b/corn-frontend/src/assets/icons/icon-144x144.png differ diff --git a/corn-frontend/src/assets/icons/icon-152x152.png b/corn-frontend/src/assets/icons/icon-152x152.png index ff4e06b8..c3d62f42 100644 Binary files a/corn-frontend/src/assets/icons/icon-152x152.png and b/corn-frontend/src/assets/icons/icon-152x152.png differ diff --git a/corn-frontend/src/assets/icons/icon-192x192.png b/corn-frontend/src/assets/icons/icon-192x192.png index afd36a48..bacf06b9 100644 Binary files a/corn-frontend/src/assets/icons/icon-192x192.png and b/corn-frontend/src/assets/icons/icon-192x192.png differ diff --git a/corn-frontend/src/assets/icons/icon-384x384.png b/corn-frontend/src/assets/icons/icon-384x384.png index 613ac793..4d8c2943 100644 Binary files a/corn-frontend/src/assets/icons/icon-384x384.png and b/corn-frontend/src/assets/icons/icon-384x384.png differ diff --git a/corn-frontend/src/assets/icons/icon-512x512.png b/corn-frontend/src/assets/icons/icon-512x512.png index 7574990f..c3604472 100644 Binary files a/corn-frontend/src/assets/icons/icon-512x512.png and b/corn-frontend/src/assets/icons/icon-512x512.png differ diff --git a/corn-frontend/src/assets/icons/icon-72x72.png b/corn-frontend/src/assets/icons/icon-72x72.png index 033724e1..4d0d1b8c 100644 Binary files a/corn-frontend/src/assets/icons/icon-72x72.png and b/corn-frontend/src/assets/icons/icon-72x72.png differ diff --git a/corn-frontend/src/assets/icons/icon-96x96.png b/corn-frontend/src/assets/icons/icon-96x96.png index 3090dc2d..51749177 100644 Binary files a/corn-frontend/src/assets/icons/icon-96x96.png and b/corn-frontend/src/assets/icons/icon-96x96.png differ diff --git a/corn-frontend/src/environments/environment.ts b/corn-frontend/src/environments/environment.ts index 0875cfa2..467f850f 100644 --- a/corn-frontend/src/environments/environment.ts +++ b/corn-frontend/src/environments/environment.ts @@ -1,4 +1,4 @@ export const environment = { production: false, - httpBackend: "http://localhost:8080" + httpBackend: "http://localhost:4200" }; diff --git a/corn-frontend/src/styles/theme.scss b/corn-frontend/src/styles/theme.scss index b9165f02..d0dd9de6 100644 --- a/corn-frontend/src/styles/theme.scss +++ b/corn-frontend/src/styles/theme.scss @@ -1,5 +1,6 @@ @use '@angular/material/index' as mat; @use '@fireflysemantics/sass-logger' as logger; +@use '../app/pages/project-list/project/_project.component-theme' as project-component; @import "palette"; @@ -52,4 +53,5 @@ $dark-background: map-merge($dark-background, ( )); $dark-theme: replace-color($dark-theme, #424242, #292627); -@include mat.all-component-themes($dark-theme); \ No newline at end of file +@include mat.all-component-themes($dark-theme); +@include project-component.theme($dark-theme); \ No newline at end of file diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index e08833a5..ce065daa 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -22,6 +22,7 @@ services: - POSTGRES_DB=corn - SPRING_DATASOURCE_URL=jdbc:postgresql://corn-postgres:5432/corn - FRONTEND_URL=corn-frontend + - CREATE_PLACEHOLDER_DATA=true build: context: corn-backend dockerfile: Dockerfile.dev @@ -57,6 +58,7 @@ services: condition: service_healthy environment: - KCCFG_OVERRIDE_EXISTING=true + - KCCFG_CREATE_PLACEHOLDER_USERS=true - KCCFG_LOGIN_THEME_NAME=corn - KC_SERVER_URL=http://corn-keycloak:8080 volumes: @@ -97,7 +99,7 @@ services: healthcheck: test: "curl -f http://localhost:8080/admin || exit 1" interval: 1s - retries: 30 + retries: 120 start_period: 15s timeout: 5s volumes: @@ -115,7 +117,7 @@ services: healthcheck: test: "pg_isready -U keycloak" interval: 1s - retries: 30 + retries: 50 start_period: 5s timeout: 3s diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index c87ea775..c7da2695 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -46,11 +46,15 @@ services: condition: service_healthy environment: - KCCFG_OVERRIDE_EXISTING=false + - KCCFG_LOGIN_THEME_NAME=corn - KC_SERVER_URL=http://corn-keycloak:8080 corn-keycloak: container_name: corn-keycloak - image: quay.io/keycloak/keycloak:20.0.1 + image: corn-keycloak + build: + context: auth-server/keycloak-theme + dockerfile: Dockerfile.keycloak.prod depends_on: corn-keycloak-postgres: condition: service_healthy @@ -65,7 +69,7 @@ services: healthcheck: test: "curl -f http://localhost:8080/admin || exit 1" interval: 1s - retries: 30 + retries: 120 start_period: 15s timeout: 5s @@ -81,7 +85,7 @@ services: healthcheck: test: "pg_isready -U keycloak" interval: 1s - retries: 30 + retries: 50 start_period: 5s timeout: 3s diff --git a/nginx/Dockerfile.dev b/nginx/Dockerfile.dev index 8bfb343b..6f41e3c9 100644 --- a/nginx/Dockerfile.dev +++ b/nginx/Dockerfile.dev @@ -1,7 +1,7 @@ FROM nginx:1.25.3-alpine3.18 COPY ./nginx.conf /etc/nginx/nginx.conf -COPY ./env.conf.template /etc/nginx/templates/env.conf.template +COPY ./proxy_pass_corn_frontend.conf.template /etc/nginx/templates/proxy_pass_corn_frontend.conf.template EXPOSE 4200 EXPOSE 8080 diff --git a/nginx/env.conf.template b/nginx/env.conf.template deleted file mode 100644 index c3a1b0e5..00000000 --- a/nginx/env.conf.template +++ /dev/null @@ -1,3 +0,0 @@ -map $uri $frontend_port_container { - default "$FRONTEND_PORT_CONTAINER"; -} diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 79f6836c..727c9d16 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -4,8 +4,6 @@ events { http { - include /etc/nginx/conf.d/env.conf; - # server { # listen 443 ssl; # @@ -18,6 +16,7 @@ http { # } server { + listen 4200; # Backend @@ -31,7 +30,7 @@ http { # Frontend location / { - proxy_pass "http://corn-frontend:${frontend_port_container}"; + include /etc/nginx/conf.d/proxy_pass_corn_frontend.conf; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; @@ -43,7 +42,7 @@ http { # Angular Dev location /ng-cli-ws { - proxy_pass "http://corn-frontend:4200"; + include /etc/nginx/conf.d/proxy_pass_corn_frontend.conf; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; diff --git a/nginx/proxy_pass_corn_frontend.conf.template b/nginx/proxy_pass_corn_frontend.conf.template new file mode 100644 index 00000000..afb92852 --- /dev/null +++ b/nginx/proxy_pass_corn_frontend.conf.template @@ -0,0 +1 @@ +proxy_pass "http://corn-frontend:$FRONTEND_PORT_CONTAINER";