Files
Kifungo Aandgreptile-apps[bot] 246401d452 [Feat] Implement UI for soundshot/camshot (#9002)
* feat(videos-ui): add camshots state management and service

Add Akita store, effects, queries, and actions for managing camshot state.
Implement Angular service to fetch camshots from the API endpoint.
Define camshot model interface and class.

* refactor(videos-ui): simplify camshot query and model usage

Update CamshotQuery to directly use ICamshot interface instead of the Camshot class for camshots and camshot observables. This change enhances type safety and reduces unnecessary object instantiation, streamlining the state management for camshots.

* feat(videos-ui): add components for camshot list

Implement UI components for displaying a list of camshots.
Includes:
- camshot-list component (main container)
- camshot-item component (individual item)
- camshot-item-skeleton component (loading placeholder)
Uses Angular's @defer with 'on viewport' trigger for lazy loading individual camshot items and a minimum placeholder duration.

* refactor(videos-ui/camshots): refactor camshot list data flow

Refactor CamshotListComponent to consume camshots data from the
CamshotQuery observable instead of using an input property.
Refactor CamshotItemComponent to define its action buttons internally
based on the camshot's state (e.g., deleted status) and emit specific
events for each action (view, download, recover, delete, hard delete).
Remove the actions input from CamshotItemComponent.
Add CamshotItemComponent, CamshotItemSkeletonComponent, and
CamshotListComponent to the video-ui module declarations as they are
no longer standalone.

* feat(videos-ui): add camshots tab to video detail page

Display camshots associated with the video's time slot in a new tab on the video detail page.
Implement infinite scroll pagination for the camshot list to efficiently load camshots.
Refactor camshot list component to accept the time slot ID as input and manage its own data fetching and state based on the provided ID.

* feat(videos-ui): improve list display and loading

Introduce deferred loading for video and camshot lists on the detail page to
improve initial page load performance using Angular's @defer syntax.
Redesign the camshot item display by changing action buttons to a popover
menu accessed via an icon and updating the layout and styling of the
thumbnail, title, and meta information.
Adjust the initial and reset skip value in the camshot list component
to fix a potential pagination issue.

* refactor(camshot): restructure item skeleton html and style appearance

Restructure the HTML elements of the camshot item skeleton (e.g.,
using divs instead of semantic tags) to provide better hooks for
styling. Update the SCSS to apply new styles and refine the pulsing
animation colors and layout. Add overflow styling to the camshot
list container.

* refactor(video-detail): improve list loading and infinite scroll

Update camshot and similar video lists on the video detail page to:
- Display more informative 'Loading...' messages using ngx-no-data-message.
- Rename 'Videos' tab to 'Similars'.
- Prevent fetching camshots when timeSlotId is not available.
- Enable infinite scroll pagination for camshots only after the
initial data has loaded and timeSlotId is present.
- Remove unused console.log.
- Add minor styling to tab links.

* feat(camshot-item): emit full camshot object from item actions

Change camshot item action outputs to emit the full ICamshot object
instead of just the ID. Update output event emitter types and
button action callbacks to reflect this change.

* refactor(camshot-item): replace static button labels with i18n keys

Prepare the component for internationalization by using localization keys
instead of hardcoded strings for button labels.

* feat(videos-ui/camshot): add view, delete and restore functionality

Implement actions, effects, store updates, and service methods
for managing individual camshots.
Adds the ability to view, soft delete, hard delete, and restore
camshots from the UI.
Updates the camshot item component to emit events for these actions
and adds a delete confirmation dialog in the list component.

* feat(camshot): add loading state to actions and list deleted

Implement loading state feedback for action buttons in the UI.
Introduce an `ActionButton` class to standardize button properties and include a `loading` observable. Update camshot item component to use this class and bind the loading state of delete and recover actions to the respective query states (`deleting$`, `restoring$`). Update the action button component template to display a spinner based on the loading state.
Modify the `ListCamshotQueryHandler` to include deleted camshots (`withDeleted: true`) in the results, enabling recovery and hard delete actions from the list view. Refine the logic for filtering camshots by the current employee's uploads.
Includes minor UI updates: change recover icon to `refresh-outline` and soft delete button status to `danger`.

* feat(camshot): add downloading state for camshot item

Expose a downloading state observable via the query and add it to the camshot item component to show a loading indicator during download.

* feat(camshot): implement soft-deleted camshot recovery

Add backend endpoint, CQRS command, and handler to recover soft-deleted
camshot entities.
A new PATCH /plugins/camshots/:id endpoint is added to the CamshotController
to trigger the recovery command. The RecoverCamshotCommand and its handler
utilize the softRecover method in the CamshotService to restore the entity.
The DeleteCamshotCommandHandler is updated to correctly query for soft-deleted
entities using `withDeleted: true` when handling deletion commands,
particularly for forceDelete operations.
UI changes in the videos-ui plugin add event handlers and actions
(`onRecover`, `onHardDelete`) for the camshot list component to interact
with the new recovery and updated hard delete logic.

* feat(videos-ui/camshots): add camshot download feature

Implement the download camshot feature.
Adds a new action and effect to handle adding camshots to the download queue service.
Connects the download functionality to the camshot list component.
Updates modal titles for clarity and adds styling for no data message.

* feat(videos-ui/camshot): add dialog to view camshots

Implement a modal dialog component for viewing camshot images.
Replaces the console log action when clicking "view" on a camshot with opening
this new viewer dialog.
The viewer includes basic controls like zooming, loading state, and error
handling.
Updated the camshot query to include the 'uploadedBy' relation for displaying
the uploader's name in the viewer metadata.
Updated the camshot model to include the 'uploadedBy' property.
Includes necessary Angular NgOptimizedImage import for performance.

* feat(camshot-viewer): enhance image viewer with pan, drag, and ui updates

Implement image pan and drag functionality when the image is zoomed.
Redesign the user interface with floating header, updated loading/error states, floating zoom controls, and hoverable metadata.
Improve overall layout, styling, and responsiveness of the viewer dialog.

* fix(soundshot): remove IsUrl validator from file url

* feat(videos-ui/soundshot): add soundshot state management

Add Akita state management slice for soundshots, including:
- Actions for fetch, delete, restore, download
- Effects to handle actions and update store
- Query to select state data
- Store to hold soundshot state
- Service to interact with soundshot API
- Model definition

* feat(videos-ui): add sounshots list and player

Implement feature to display and play sounshots.
- Add `SounshotListComponent` with infinite scroll.
- Create `SounshotPlayerComponent` for audio playback.
- Introduce `SounshotPlayerSkeletonComponent` for loading states.
- Integrate list into video detail page with a new tab.
Includes updates to Codacy configuration, Codacy CLI script,
.gitignore, and .vscode/settings.json.

* feat(videos-ui/soundshot-player): add interactive player controls

Implement play/pause, seeking, and volume control for soundshots.
Display track duration and file size.
Refactor component logic using Angular signals and update template/styles.
Remove outdated spec file and Codacy configuration.

* style(soundshot-player): remove max width from player

Allow the player component to take up the full width of its container.

* refactor(soundshot-skeleton): restructure player skeleton

Rewrite the HTML and SCSS for the soundshot player skeleton
component.
Simplifies the layout structure and updates the animation
style. Also changes the background color variable.

* feat(soundshot-player): add cover image and update layout

Add a cover image element to the soundshot player component.
Adjust the layout to display the cover image alongside the soundshot
title and metadata on wider screens. Maintain a stacked layout on
smaller screens.

* style(soundshot-skeleton): improve skeleton layout and animation

Add a placeholder for the cover image to the soundshot player skeleton.
Refactor the layout of the title and meta information to accommodate
the new cover.
Apply the skeleton loading animation consistently to all significant
elements within the skeleton (cover, title, meta items, controls,
progress, time, volume).

* feat(soundshot-player): add actions popover

Add a popover with action buttons to the soundshot player component.
Include download, delete, and conditionally recover/hard delete actions based on the soundshot status.
Allows users to perform actions directly from the player UI.

* style(soundshot-player): update styling and layout

Adopt CSS variable for border radius for consistency.
Change align-items to flex-start in soundshot info.
Add transition for smoother visual updates.
Add specific styles for the actions element.

* feat(soundshot-player): emit player button action events and add loading state

Replace placeholder console.log actions for player buttons with EventEmitter
outputs. This allows parent components to handle the corresponding actions
such as download, recover, soft delete, and hard delete.
Add loading state indication to buttons based on query status for improved
user experience.

* feat(videos-ui): implement soundshot actions

Implement download, recover, soft delete, and hard delete actions for soundshots.
Add event handlers in the soundshot list component to dispatch corresponding
actions. Use confirmation modals for delete and hard delete operations.
Add visual styling to indicate deleted soundshots in the player component.

* fix(soundshot): include soft-deleted entities in delete lookup

When handling the delete command, the service needs to locate the
soundshot entity even if it has been previously soft-deleted.
Using `findOneByOptions` with `{ withDeleted: true }` ensures the
lookup finds the entity regardless of its soft-delete status.

* feat(soundshot/query): include deleted soundshots

Modify the query handler to pass `withDeleted: true` to the
pagination service, ensuring soft-deleted soundshots are
included in the results.

* feat(videos-ui): add toast notifications for restore and delete

Add toast notifications for camshot and soundshot restore and delete
operations.
These toasts inform the user about the status of the operation,
including when it starts, succeeds, or fails. This provides clearer
feedback than just updating the UI state.

* style(soundshot-player): reduce deleted background opacity

* feat(soundshot): add soundshot recovery endpoint and command

Implement command, handler, and controller endpoint to allow soft-recovering
a previously deleted soundshot record.

* feat(soundshot): allow filtering soundshots

Update GetSoundshotsQueryDTO to accept a generic FindOptionsWhere for the
where clause. This removes the previous limitation requiring
TenantOrganizationBaseDTO and a custom transformation.
Utilize the where clause in the soundshot list component to filter by
timeSlotId.

* refactor(soundshot): remove ValidateNested import

* fix(camshot): correctly apply filters to camshot query

When listing camshots, ensure that users without the
CHANGE_SELECTED_EMPLOYEE permission are correctly filtered by
their uploadedById. If a user lacks this permission and does
not have a current employee ID, return an empty result set
immediately to prevent unauthorized data exposure or query errors.
Also, ensure that the dynamically built 'where' clause (from
permissions or date filters) is correctly merged with any base
'where' conditions provided in the query parameters.
Update internal comments for accuracy.

* fix(videos): refine list query filtering and permissions

Add stricter checks in the list videos query handler:
- Ensure `employeeIds` filter is only applied for users
with the `CHANGE_SELECTED_EMPLOYEE` permission.
- Return empty result if user lacks permission and
current employee ID is missing.
- Include soft-deleted records in the query results.
Also update a comment in the list camshot query handler.

* refactor(videos): refactor video count query handler with validation

Add explicit validation for required query options (organizationId,
tenantId) to ensure the handler receives necessary parameters.
Refactor the handler by extracting validation and where condition
building logic into separate private methods. This improves code
structure, readability, and testability.
Enhance JSDoc comments to better explain the handler's purpose,
parameters, and behavior.

* chore(videos-ui): correct sounshot typo in soundshot components

Update component names, selectors, and file paths from "sounshot" to "soundshot" to fix consistent misspelling. This affects the soundshot list, player, and skeleton components and their imports.

* chore(cspell): ignore rules directory

* chore: ignore .codacy directory in spell check

* fix(video-detail-page): update similar tab title

* fix(camshot): correct recover camshot handler filename and import

Correct a typo in the filename for the recover camshot command handler and update the corresponding import path.

* fix(camshot): improve message for camshot recovery not found

Provide more detailed reasons when camshot recovery fails due
to not found or other issues.

* fix(video-detail-page): fix soundshot loading message status

Change the status of the placeholder message displayed while
soundshots are loading from danger to info. Danger status is misleading
for a simple loading state; info status better reflects the ongoing
process.

* fix(video-detail-page): correct loading message and status

Update the loading message from 'Loading camshots...' to
'Loading similar videos...' to accurately reflect the content.
Change the status from 'danger' to 'info' as the loading state
is not a critical error.

* style(camshot-list): clean up formatting

* fix:  incorrect grammar in description

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix(soundshot-player): improve seek function robustness

Add checks to ensure the audio player and progress bar elements
are available before attempting to calculate the seek position.
Also add a check for zero width on the progress bar.
Wrap the seek operation in a try/catch block to gracefully handle
potential errors during playback updates.
Include console warnings/errors for debugging missing elements
or failed seek operations.

* fix: Duplicate 'nbButton' attribute on lines 2 and 5. Remove one instance.

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix:  property 'border-radius-top-left' is invalid

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix: no feedback shown when isAdded is false. User should be notified if download queue addition fails

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix: command should implement ICommand interface from @nestjs/cqrs to follow CQRS pattern

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* feat(soundshot): return recovered soundshot from patch

Return the updated soundshot object after recovery.
This allows the client to immediately use the refreshed state of the
soundshot without needing a subsequent GET request.
BREAKING CHANGE: The PATCH /soundshots/:id endpoint now returns the
recovered soundshot object instead of nothing.

* fix: API description has a typo 'UUID, version UUID the plugin ID'

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* chore: remove sensitive nx cloud access token

Remove the hardcoded token from nx.json.
Environment variables or secrets management
should be used instead.

* style(camshot): fix formatting and API description typo

Correct constructor formatting in CamshotController and RecoverCamshotCommand. Update API description to remove redundancy in the recover camshot operation.

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-06-21 11:07:03 +02:00
..