Commit Graph

225 Commits

Author SHA1 Message Date
Nate Kelley 279d903de2
defferred updatate 2025-02-05 22:42:22 -07:00
Nate Kelley f3a4fb96ef
mock data update 2025-02-05 22:35:46 -07:00
Nate Kelley 6c5f4c7b5f
dashboard config 2025-02-05 16:43:18 -07:00
Nate Kelley 1a373d1e04
popup selet file container 2025-02-05 14:31:32 -07:00
Nate Kelley 2fc8c9a221
Update useMetricLayout.ts 2025-02-05 13:19:49 -07:00
Nate Kelley 55e307b677
do not allow dragging app data grid 2025-02-05 13:06:25 -07:00
Nate Kelley f4866b790d
save sql container 2025-02-05 12:54:06 -07:00
Nate Kelley e7843d5a83
created results file pt1 2025-02-05 11:27:53 -07:00
Nate Kelley 39d5601158
update how we pass inputs 2025-02-05 09:55:09 -07:00
Nate Kelley b984e9863f
Merge branch 'staging' into big-nate/bus-939-create-new-structure-for-chats 2025-02-05 09:15:30 -07:00
Nate Kelley 255c1514ad
Update MetricTitle.tsx 2025-02-05 08:01:55 -07:00
Nate Kelley 3f46086ca7
Update ChatInput.tsx 2025-02-04 22:40:59 -07:00
Nate Kelley bc93d18f7e
Update SubmitButton.tsx 2025-02-04 22:22:55 -07:00
Nate Kelley 3977d7bb34
make submit button a little better 2025-02-04 22:04:26 -07:00
Nate Kelley e02ac8e35f
pass row count 2025-02-04 21:04:24 -07:00
Nate Kelley 535b6658a9
rename metric controller
update version

your message

splitter resizer
2025-02-04 16:51:37 -07:00
Nate Kelley 6dc40d0ae8
make a card component 2025-02-04 11:13:46 -07:00
Nate Kelley 54810dcf59
document endpoints 2025-02-04 11:01:00 -07:00
Nate Kelley 4992b2b118
metric edit controller 2025-02-03 22:14:54 -07:00
Nate Kelley af5e599dab
make a chart card 2025-02-03 20:57:12 -07:00
Nate Kelley 679295cff8
metric chart update 1 2025-02-03 16:37:18 -07:00
Nate Kelley 9c847ca6f1
animate buttons in and out 2025-02-03 11:44:06 -07:00
Nate Kelley e6655554d0
close secondary when open primary 2025-02-03 11:24:32 -07:00
Nate Kelley 2be183889b
metric toggle secondary 2025-02-03 10:46:20 -07:00
Nate Kelley d17899f3d4
toggle for metric slideout 2025-02-03 10:31:15 -07:00
Nate Kelley 4ca917195c
additinal typing 2025-02-03 09:33:02 -07:00
Nate Kelley 45f814ff04
change how dashboards are routed 2025-02-03 09:26:40 -07:00
Nate Kelley 40d4532788
move permission to asset interfaces 2025-02-01 21:53:01 -07:00
Nate Kelley d2e7c65ca4
move addtional files to asset 2025-02-01 21:27:54 -07:00
Nate Kelley 4cee544cf3
move dataset to shared asset 2025-02-01 20:59:24 -07:00
Nate Kelley 90fac0a5c7
Start removing thread context 2025-01-31 22:33:57 -07:00
Nate Kelley 58551de620
start moving api interfaces to folder 2025-01-31 11:09:11 -07:00
Nate Kelley 731969aa49
Merge branch 'staging' into big-nate/bus-939-create-new-structure-for-chats 2025-01-30 17:16:39 -07:00
Nate Kelley 5b231e1efd
make dashboard header sizing more consistent 2025-01-30 17:16:19 -07:00
Nate Kelley 17c57f6d75
metric interfaces in correct place 2025-01-30 16:53:57 -07:00
Nate Kelley 22337e17d1
share menu structures 2025-01-30 16:51:37 -07:00
Nate Kelley 70d770f565
add additional components 2025-01-30 15:33:06 -07:00
Nate Kelley f234825029
add chat layout context 2025-01-30 10:44:37 -07:00
Nate Kelley 7d7e637d50
update animation 2025-01-29 15:10:41 -07:00
Nate Kelley 9d5ed6b10f
Update ChatResponseMessages.tsx 2025-01-29 14:51:19 -07:00
Nate Kelley ce4d061325
add additional animation 2025-01-29 13:58:27 -07:00
Nate Kelley 372e394100
smoother hide transntion 2025-01-29 13:11:37 -07:00
Nate Kelley 97316c11cc
Merge branch 'staging' into big-nate/bus-939-create-new-structure-for-chats 2025-01-29 12:47:31 -07:00
Nate Kelley 4bade2114a
attempt to fix cursor bug 2025-01-29 12:46:26 -07:00
Nate Kelley 284dd43369
remove warning for show undefeine 2025-01-29 12:17:16 -07:00
Nate Kelley 75e36b8e93
replace missing data with 2025-01-29 10:35:34 -07:00
Nate Kelley dc152628f0
hidden items 2025-01-28 17:12:23 -07:00
Nate Kelley 44df60c695
chat content update 2025-01-28 16:21:00 -07:00
Nate Kelley f686403141
do not show next line 2025-01-28 15:54:41 -07:00
Nate Kelley 2a881479ee
message updated 2025-01-28 15:38:43 -07:00
Nate Kelley 330c3067d5
version id update 2025-01-28 15:21:07 -07:00
Nate Kelley 29b2c8996f
bleed into message block 2025-01-28 14:21:22 -07:00
Nate Kelley f41c4da9ff
thought transitions complete 2025-01-28 14:07:30 -07:00
Nate Kelley 2d8d2baa6f
Update ChatResponseMessage_ThoughtPills.tsx 2025-01-28 13:29:07 -07:00
Nate Kelley e653d3953b
better pill handling 2025-01-28 12:55:53 -07:00
Nate Kelley b850a85199
width 2025-01-28 12:47:14 -07:00
Nate Kelley df3c216b3e
pill click events 2025-01-28 12:24:31 -07:00
Nate Kelley aec79d84a6
thoughts pills 2025-01-28 11:50:11 -07:00
Nate Kelley 52c4521750
pill styles 2025-01-28 10:57:26 -07:00
Nate Kelley b8e1270f36
Update ChatResponseMessage_Thought.tsx 2025-01-28 10:07:37 -07:00
Nate Kelley 975b8dd8d9
add streaming text 2025-01-28 10:04:54 -07:00
Nate Kelley 20c31af9da
started adding responses 2025-01-27 17:08:52 -07:00
Nate Kelley 90d30c93af
add additional context provider for chats 2025-01-27 16:23:08 -07:00
Nate Kelley be050b3521
select file update 2025-01-27 15:48:29 -07:00
Nate Kelley 604bfbdd6c
create chat interfaces 2025-01-27 13:21:42 -07:00
Nate Kelley 9f4dcb6baa
animation for collapse button 2025-01-25 11:23:19 -07:00
Nate Kelley d7aeb14569
pass down file type to container 2025-01-24 21:21:53 -07:00
Nate Kelley b3af7267ef
default file passthrough 2025-01-24 16:59:38 -07:00
Nate Kelley de0d46bb2e
more chat container info 2025-01-24 16:33:32 -07:00
Nate Kelley 2068cf2046
add scroll indicator 2025-01-24 14:39:15 -07:00
Nate Kelley 8b21e0d50c
chat file headers 2025-01-24 13:36:39 -07:00
Nate Kelley 2fe395b5ea
check if number for chat splitter 2025-01-24 13:05:09 -07:00
Nate Kelley 975f5a1011
Merge branch 'staging' into big-nate/bus-939-create-new-structure-for-chats 2025-01-24 11:12:12 -07:00
Nate Kelley 2208977a87
prevent email param injection 2025-01-24 11:04:34 -07:00
Nate Kelley 15e515720f
add secure middleware checks 2025-01-23 16:33:33 -07:00
Nate Kelley 77c6f57846
can pass in pixels instead of percentage to app splitter animate 2025-01-23 16:15:42 -07:00
Nate Kelley dbaa3c0b06
add chat splitter pt 1 2025-01-23 16:00:33 -07:00
Nate Kelley f638db2299
reorganize components pt 1 2025-01-23 13:15:10 -07:00
Nate Kelley 31e0477b56
Merge branch 'staging' into big-nate/bus-939-create-new-structure-for-chats 2025-01-23 12:58:08 -07:00
Nate Kelley d315d6f410
update how no datasets is presented 2025-01-23 12:57:57 -07:00
Nate Kelley 16866accbb
Merge branch 'staging' into big-nate/bus-939-create-new-structure-for-chats 2025-01-23 12:44:41 -07:00
Nate Kelley 0a7ffc7980
restrict adding people to admins 2025-01-23 11:36:54 -07:00
Nate Kelley cb96002f04
small users page 2025-01-23 11:32:02 -07:00
Nate Kelley 4de70a3420
restrict certain routes to admins 2025-01-23 11:20:48 -07:00
Nate Kelley aa190a73de
disable editing my own user 2025-01-23 11:05:07 -07:00
Nate Kelley b658eb2728
reroute to correct link for datasets 2025-01-23 10:54:21 -07:00
Nate Kelley ac0caac99b
add hidden prop to row listing component 2025-01-23 10:20:23 -07:00
Nate Kelley 237bf529e2
get datasets only if they have an org 2025-01-23 10:05:52 -07:00
Nate Kelley f07d5425b9
user organization can be null 2025-01-23 09:29:07 -07:00
Nate Kelley b45eec6146
add animation to app splitter 2025-01-22 17:35:17 -07:00
Nate Kelley db43289d71
refetch after user default access changed (#58) 2025-01-22 15:11:07 -08:00
Nate Kelley bc36758fea
Big nate/bus 936 if a user is not an admin we should not see the permission (#57)
* app sidebar settings should hide

* rename api directories

* list empty state

* offset for row
2025-01-22 14:58:06 -08:00
dal dc0dd9aa30
Merge branch 'main' into staging 2025-01-22 13:30:49 -07:00
Nate Kelley 5c75fbee03
remove console logs 2025-01-22 12:51:56 -07:00
Nate Kelley 84387396f0
feat: added permission pages
* chore: add release-please configuration

* create virtua list component

* only debounce if there is text

* prefetch on demand

* add a popup for permissions

* update package versions

* Make users page (#39)

* create users pages

* abstract more components to correct folders

* carve out expection if we are hiding the select all

* user query

* Add ability to change default access

* Update package-lock.json

* Update package-lock.json

* Update web/src/components/list/BusterList/BusterListReactWindow.tsx

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Big nate/bus 924 make additional permissions pages (#50)

* create virtua list component

* only debounce if there is text

* prefetch on demand

* add a popup for permissions

* Update web/src/components/list/BusterList/BusterListReactWindow.tsx

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* finalize permission popup

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* more elegant infinite list component

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* add additional bulk popup menus

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* make pages unique

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* change how padding is applied to list

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* infinite list component

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* start user dataset lineage

Co-Authored-By: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Refactor SQL query in list_assets_handler to use a Common Table Expression (CTE) for improved readability and maintainability. The CTE, `distinct_assets`, simplifies the selection of distinct asset records before applying the final ordering and limiting.

* add cursor rules for web directory + jest (#52)

* on change update for segments

* PRevent clicking passthrough on users click

* feat: Add assets module and nest routes in user router

- Introduced a new `assets` module to handle asset-related routes.
- Updated the user router to nest the `assets` routes under the user ID path, enhancing the organization of API endpoints.
- This change improves the structure and maintainability of the user-related routes in the API.

* feat: Enhance user attribute listing with authorization checks

- Updated the `list_attributes_handler` to include authorization checks for user roles and organization IDs.
- Implemented error handling for unauthorized access to user attributes.
- Refactored the SQL query to retrieve user attributes based on the authenticated user's organization, improving security and data integrity.
- This change ensures that only authorized users can list attributes, enhancing the overall security of the API.

* pass through dataset overview

* feat: Update dataset group listing to include permissions

- Enhanced the `list_dataset_groups` function to join with the `dataset_permissions` table, allowing retrieval of permission details for each dataset group.
- Modified the `DatasetGroupInfo` struct to include `permission_id` and `assigned` fields, reflecting the new data structure.
- Refactored the SQL query to group by necessary fields and ensure accurate permission data is returned, improving the functionality and security of dataset group listings.

* feat: Add DatasetGroupPermission model and schema

- Introduced a new `DatasetGroupPermission` struct in `models.rs` to represent permissions associated with dataset groups.
- Updated the database schema in `schema.rs` to include the `dataset_groups_permissions` table, defining its structure and relationships.
- Modified the `is_user_workspace_admin_or_data_admin` function in `checks.rs` to correctly reference the user's organization role, enhancing role validation logic.

* add component for users inputs

* feat: Update dataset group listing to include dataset group permissions

- Modified the `list_dataset_groups` function to accept an additional `id` parameter for filtering dataset groups based on user permissions.
- Updated the SQL query to join with the `dataset_groups_permissions` table, allowing retrieval of permission counts for each dataset group.
- Refactored the `DatasetGroupInfo` struct to replace `permission_id` with `permission_count`, enhancing clarity and accuracy in the data representation.
- Ensured that the query groups by the new permission structure, improving the functionality and security of dataset group listings.

* feat: Refactor dataset listing to include user-specific permissions

- Updated the `list_datasets` function to accept an additional `id` parameter for filtering datasets based on user permissions.
- Enhanced the SQL query to join with the `dataset_permissions` table, allowing retrieval of permission details for each dataset.
- Refactored the `DatasetInfo` struct to include an `assigned` field, improving clarity in the dataset representation.
- Improved error handling for dataset retrieval, ensuring robust logging and response management.

* fix: Correct user role attribute and enhance read-only logic in list_attributes_handler

- Updated the user role attribute key from "role" to "organization_role" for accurate role retrieval.
- Introduced a read-only flag for specific user attributes, improving data integrity by clearly indicating which attributes should not be modified.
- Enhanced error handling for user role retrieval, ensuring robust responses for missing or incorrect attributes.

* normalize header for list

* new line

* popup conatiner for users

* feat: Enhance user authorization checks and refactor related functions

- Added user authorization checks in `list_attributes`, `list_dataset_groups`, `list_datasets`, `list_permission_groups`, and `list_teams` functions to ensure only users with appropriate roles can access these resources.
- Refactored the `list_teams_handler` to accept `user_id` as a parameter, improving clarity and consistency across user-related functions.
- Updated SQL queries to utilize the new authorization checks, enhancing security and data integrity.
- Removed redundant column allowances in `list_teams` permissions, streamlining the codebase.

* pass last child as index

* feat: Enhance permission group handling and streamline SQL queries

- Expanded the `allow_columns_to_appear_in_same_group_by_clause!` macro in `models.rs` to include additional columns for datasets and users, improving query flexibility.
- Refactored the `list_permission_groups` function to include dataset count and assigned status, enhancing the information returned for each permission group.
- Updated SQL queries in `list_permission_groups` to utilize left joins for better data retrieval and to ensure accurate permission checks.
- Removed redundant column allowances in various files, streamlining the codebase and improving maintainability.

* feat: Add PUT route for updating teams in user assets

- Introduced a new module `put_teams` to handle updates for teams.
- Added a PUT route for `/teams` in the user assets router, allowing for team modifications.
- Enhanced the routing capabilities of the user assets API to support both GET and PUT requests for teams.

* onchagne appsegmetned update

* create permission user endpoints

* move files to match new page structure

* refactor: Clean up routing and improve PUT teams handler

- Reformatted imports in `mod.rs` for better readability.
- Commented out the PUT route for `/teams` in the user assets router, indicating a potential future change or deprecation.
- Updated the `put_teams` handler to return a `NoContent` response upon successful execution, enhancing clarity in API responses.
- Improved error handling in the `put_teams` function for better logging and response management.

* refactor: Standardize user ID parameter naming across user-related routes

- Updated all user-related route handlers to use `user_id` instead of `id` for better clarity and consistency.
- Modified the routing definitions in `mod.rs` to reflect the new parameter naming convention.
- Enhanced the `list_permission_groups` function to accept `user_id` as a parameter, improving clarity in the handler's signature.
- Ensured all relevant functions now consistently handle the `user_id` parameter, streamlining the codebase and improving maintainability.

* feat: Enhance team management with role-based assignments

- Introduced a new `TeamInfoRole` enum to represent user roles within teams, replacing the previous boolean `assigned` field.
- Updated the `list_teams` handler to return team roles instead of assignment status, improving clarity on user roles.
- Refactored the `put_teams` handler to support role-based assignments, allowing for more granular control over team memberships.
- Added new PUT routes for dataset groups and permission groups in the user assets router, enhancing API capabilities.
- Improved SQL queries for team assignments to utilize role information, streamlining database interactions.

* feat: Add organization_id to DatasetGroupPermission and update dataset group handler

- Introduced a new `organization_id` field in the `DatasetGroupPermission` struct to associate permissions with specific organizations.
- Updated the `put_dataset_groups_handler` to include `organization_id` when creating or updating dataset group permissions, enhancing the API's capability to manage permissions at the organizational level.
- Improved SQL query formatting for better readability in the handler.

* add list components for permission settings

* feat: Introduce assets module and update routing for permission groups

- Added a new `assets` module to organize related routes.
- Updated the routing in `mod.rs` to nest the `assets` router under the `/:permission_group_id` path, enhancing the structure and clarity of the API.
- Maintained existing routes for managing permission groups while improving modularity.

* create permission group users

* refactor: Update list_permission_groups_handler to use user_id and improve SQL queries

- Changed the parameter in the SQL query from `user.id` to `user_id` for consistency with the updated user ID parameter naming convention.
- Enhanced the SQL query to count distinct dataset permissions and utilize `bool_or` for identity checks, improving accuracy and performance.
- Cleaned up the grouping in the SQL query by removing unnecessary fields, streamlining the data retrieval process.

* add listing for dataset groups

* feat: Add PUT routes for user and dataset management in assets module

- Introduced new PUT routes for managing users and dataset groups in the assets module.
- Updated the router to support PUT requests for `/users`, `/dataset_groups`, and `/datasets`, enhancing the API's functionality for resource updates.
- Improved modularity by organizing related routes within the assets module.

* add listing for dataset groups

* add list for datasets

* assigned permissions

* Add attributes and teams

* feat: Add DatasetToDatasetGroup model and update schema

- Introduced a new `DatasetToDatasetGroup` struct to represent the relationship between datasets and dataset groups, including fields for timestamps and optional deletion.
- Updated the database schema to include `updated_at` and `deleted_at` fields for the `datasets_to_dataset_groups` table, enhancing data tracking capabilities.
- Refactored the routing in `mod.rs` to include a nested router for assets, improving the organization of dataset group routes.

* invalidate query if user id is present

* create a dataset modal added to user page

* add team modal to teams

* assigned popup

* feat: Enhance user retrieval with dataset information

- Added new structs `DatasetLineage` and `DatasetInfo` to represent dataset details and lineage.
- Updated `UserResponse` to include a list of datasets associated with the user.
- Refactored `get_user_information` function to concurrently fetch user info, direct datasets, permission group datasets, and organization datasets using `tokio::spawn` for improved performance.
- Implemented logic to compile datasets based on direct access and permission group access, including lineage tracking for better data representation.
- Enhanced error handling during database queries to ensure robust user information retrieval.

* feat: Enhance dataset access retrieval in user and dataset overview

- Updated `get_dataset_overview` to include dataset group access and permission group to dataset group access, improving the granularity of dataset permissions.
- Introduced new queries to fetch dataset groups and their associated permissions, enhancing the dataset overview for users.
- Refactored `get_user_information` to concurrently retrieve dataset groups and permission group datasets, optimizing performance with `tokio::spawn`.
- Enhanced lineage tracking for datasets, allowing for better representation of user permissions across dataset groups and permission groups.
- Improved error handling during database queries to ensure robust data retrieval.

* lineage props passed

* refactor: Streamline dataset access logic in get_user_information

- Simplified access control logic for datasets based on user roles, consolidating conditions for WorkspaceAdmin, DataAdmin, Querier, Viewer, and RestrictedQuerier.
- Enhanced dataset lineage tracking to provide clearer representation of user permissions across various dataset access types.
- Removed redundant code related to dataset processing, improving readability and maintainability of the `get_user_information` function.
- Ensured that datasets are correctly categorized based on direct access, permission group access, and organization datasets, optimizing the overall data retrieval process.

* feat: Refactor dataset overview access lineage in get_dataset_overview

- Introduced a default access lineage for users, ensuring consistent representation of user permissions.
- Simplified the addition of user roles to the lineage, consolidating logic for WorkspaceAdmin, DataAdmin, Querier, and Viewer roles.
- Enhanced lineage tracking for RestrictedQuerier role to include direct dataset access and permission group lineage, improving granularity of dataset permissions.
- Removed redundant code related to dataset and permission group lineage, optimizing readability and maintainability of the `get_dataset_overview` function.

* add datasetgroup handler

* feat: Improve dataset access control and lineage tracking

- Enhanced the `get_dataset_overview` function to refine access control for the `RestrictedQuerier` role, allowing for more granular permission checks based on various access paths.
- Updated the `get_user_information` function to streamline dataset processing, ensuring that datasets are categorized correctly based on direct access and permission group access.
- Removed redundant code and improved readability by consolidating logic for user roles, enhancing maintainability of both functions.
- Improved lineage tracking for datasets, providing a clearer representation of user permissions across different access types.

* clickable pills

* fix build errors

* add endpoints for dataset groups, and permission groups

* refactor: Enhance dataset access control and lineage tracking

- Streamlined the `get_dataset_overview` function to improve access control for the `RestrictedQuerier` role, ensuring more precise permission checks.
- Updated the `get_user_information` function to optimize dataset processing, categorizing datasets based on direct access and permission group access.
- Removed redundant code and improved readability by consolidating logic for user roles, enhancing maintainability.
- Enhanced lineage tracking for datasets, providing a clearer representation of user permissions across different access types.

* better handling for create a permission group

* Refetch on team created for now

* add additional pages

* permission group modal update

* added pages for permission groups

* add user permission list

* add datasets to permission groups page

* Update dependencies and refactor Snowflake query handling

- Downgraded the `base64` crate version in `Cargo.toml` from `0.22.1` to `0.21`.
- Refactored the `snowflake_query` function in `snowflake_query.rs` to improve data type handling, including support for additional Arrow data types and enhanced null value checks.
- Updated the `route_to_query` function in `query_router.rs` to use mutable `snowflake_client` for better state management during query execution.
- Improved error handling for closing the Snowflake client session, ensuring proper logging of any issues encountered.

* add datasets to permission groups page

* Refactor Snowflake client connection to remove warehouse and database IDs

- Updated the `get_snowflake_client` function to no longer require `warehouse_id` and `database_id`, simplifying the connection process.
- This change enhances flexibility in client initialization and aligns with recent updates to Snowflake API handling.

* add permission groups lists

* add dataset group in permission group area

---------

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
Co-authored-by: dal <dallin@buster.so>
2025-01-22 11:25:06 -08:00
Nate Kelley 0e4f6e7f06
add dataset group in permission group area 2025-01-22 12:08:53 -07:00
Nate Kelley 0d132576d5
add permission groups lists 2025-01-22 11:06:05 -07:00
Nate Kelley aba1cef762
add datasets to permission groups page 2025-01-22 10:32:28 -07:00
Nate Kelley 2f47b45b41
add user permission list 2025-01-22 10:08:43 -07:00
Nate Kelley 30cb2a0ff5
added pages for permission groups 2025-01-21 20:26:09 -07:00