skypilot-nightly 1.0.0.dev20251210__py3-none-any.whl → 1.0.0.dev20260112__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sky/__init__.py +4 -2
- sky/adaptors/slurm.py +159 -72
- sky/backends/backend_utils.py +52 -10
- sky/backends/cloud_vm_ray_backend.py +192 -32
- sky/backends/task_codegen.py +40 -2
- sky/catalog/data_fetchers/fetch_gcp.py +9 -1
- sky/catalog/data_fetchers/fetch_nebius.py +1 -1
- sky/catalog/data_fetchers/fetch_vast.py +4 -2
- sky/catalog/seeweb_catalog.py +30 -15
- sky/catalog/shadeform_catalog.py +5 -2
- sky/catalog/slurm_catalog.py +0 -7
- sky/catalog/vast_catalog.py +30 -6
- sky/check.py +11 -8
- sky/client/cli/command.py +106 -54
- sky/client/interactive_utils.py +190 -0
- sky/client/sdk.py +8 -0
- sky/client/sdk_async.py +9 -0
- sky/clouds/aws.py +60 -2
- sky/clouds/azure.py +2 -0
- sky/clouds/kubernetes.py +2 -0
- sky/clouds/runpod.py +38 -7
- sky/clouds/slurm.py +44 -12
- sky/clouds/ssh.py +1 -1
- sky/clouds/vast.py +30 -17
- sky/core.py +69 -1
- sky/dashboard/out/404.html +1 -1
- sky/dashboard/out/_next/static/3nu-b8raeKRNABZ2d4GAG/_buildManifest.js +1 -0
- sky/dashboard/out/_next/static/chunks/1871-0565f8975a7dcd10.js +6 -0
- sky/dashboard/out/_next/static/chunks/2109-55a1546d793574a7.js +11 -0
- sky/dashboard/out/_next/static/chunks/2521-099b07cd9e4745bf.js +26 -0
- sky/dashboard/out/_next/static/chunks/2755.a636e04a928a700e.js +31 -0
- sky/dashboard/out/_next/static/chunks/3495.05eab4862217c1a5.js +6 -0
- sky/dashboard/out/_next/static/chunks/3785.cfc5dcc9434fd98c.js +1 -0
- sky/dashboard/out/_next/static/chunks/3981.645d01bf9c8cad0c.js +21 -0
- sky/dashboard/out/_next/static/chunks/4083-0115d67c1fb57d6c.js +21 -0
- sky/dashboard/out/_next/static/chunks/{8640.5b9475a2d18c5416.js → 429.a58e9ba9742309ed.js} +2 -2
- sky/dashboard/out/_next/static/chunks/4555.8e221537181b5dc1.js +6 -0
- sky/dashboard/out/_next/static/chunks/4725.937865b81fdaaebb.js +6 -0
- sky/dashboard/out/_next/static/chunks/6082-edabd8f6092300ce.js +25 -0
- sky/dashboard/out/_next/static/chunks/6989-49cb7dca83a7a62d.js +1 -0
- sky/dashboard/out/_next/static/chunks/6990-630bd2a2257275f8.js +1 -0
- sky/dashboard/out/_next/static/chunks/7248-a99800d4db8edabd.js +1 -0
- sky/dashboard/out/_next/static/chunks/754-cfc5d4ad1b843d29.js +18 -0
- sky/dashboard/out/_next/static/chunks/8050-dd8aa107b17dce00.js +16 -0
- sky/dashboard/out/_next/static/chunks/8056-d4ae1e0cb81e7368.js +1 -0
- sky/dashboard/out/_next/static/chunks/8555.011023e296c127b3.js +6 -0
- sky/dashboard/out/_next/static/chunks/8821-93c25df904a8362b.js +1 -0
- sky/dashboard/out/_next/static/chunks/8969-0662594b69432ade.js +1 -0
- sky/dashboard/out/_next/static/chunks/9025.f15c91c97d124a5f.js +6 -0
- sky/dashboard/out/_next/static/chunks/{9353-8369df1cf105221c.js → 9353-7ad6bd01858556f1.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/_app-5a86569acad99764.js +34 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-8297476714acb4ac.js +6 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-337c3ba1085f1210.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/{clusters-9e5d47818b9bdadd.js → clusters-57632ff3684a8b5c.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/infra/[context]-5fd3a453c079c2ea.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/infra-9f85c02c9c6cae9e.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-90f16972cbecf354.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/jobs/pools/[pool]-2dd42fc37aad427a.js +16 -0
- sky/dashboard/out/_next/static/chunks/pages/jobs-ed806aeace26b972.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/users-bec34706b36f3524.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/{volumes-ef19d49c6d0e8500.js → volumes-a83ba9b38dff7ea9.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-96e0f298308da7e2.js → [name]-c781e9c3e52ef9fc.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/workspaces-91e0942f47310aae.js +1 -0
- sky/dashboard/out/_next/static/chunks/webpack-cfe59cf684ee13b9.js +1 -0
- sky/dashboard/out/_next/static/css/b0dbca28f027cc19.css +3 -0
- sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
- sky/dashboard/out/clusters/[cluster].html +1 -1
- sky/dashboard/out/clusters.html +1 -1
- sky/dashboard/out/config.html +1 -1
- sky/dashboard/out/index.html +1 -1
- sky/dashboard/out/infra/[context].html +1 -1
- sky/dashboard/out/infra.html +1 -1
- sky/dashboard/out/jobs/[job].html +1 -1
- sky/dashboard/out/jobs/pools/[pool].html +1 -1
- sky/dashboard/out/jobs.html +1 -1
- sky/dashboard/out/plugins/[...slug].html +1 -1
- sky/dashboard/out/users.html +1 -1
- sky/dashboard/out/volumes.html +1 -1
- sky/dashboard/out/workspace/new.html +1 -1
- sky/dashboard/out/workspaces/[name].html +1 -1
- sky/dashboard/out/workspaces.html +1 -1
- sky/data/data_utils.py +26 -12
- sky/data/mounting_utils.py +29 -4
- sky/global_user_state.py +108 -16
- sky/jobs/client/sdk.py +8 -3
- sky/jobs/controller.py +191 -31
- sky/jobs/recovery_strategy.py +109 -11
- sky/jobs/server/core.py +81 -4
- sky/jobs/server/server.py +14 -0
- sky/jobs/state.py +417 -19
- sky/jobs/utils.py +73 -80
- sky/models.py +9 -0
- sky/optimizer.py +2 -1
- sky/provision/__init__.py +11 -9
- sky/provision/kubernetes/utils.py +122 -15
- sky/provision/kubernetes/volume.py +52 -17
- sky/provision/provisioner.py +2 -1
- sky/provision/runpod/instance.py +3 -1
- sky/provision/runpod/utils.py +13 -1
- sky/provision/runpod/volume.py +25 -9
- sky/provision/slurm/instance.py +75 -29
- sky/provision/slurm/utils.py +213 -107
- sky/provision/vast/utils.py +1 -0
- sky/resources.py +135 -13
- sky/schemas/api/responses.py +4 -0
- sky/schemas/db/global_user_state/010_save_ssh_key.py +1 -1
- sky/schemas/db/spot_jobs/008_add_full_resources.py +34 -0
- sky/schemas/db/spot_jobs/009_job_events.py +32 -0
- sky/schemas/db/spot_jobs/010_job_events_timestamp_with_timezone.py +43 -0
- sky/schemas/db/spot_jobs/011_add_links.py +34 -0
- sky/schemas/generated/jobsv1_pb2.py +9 -5
- sky/schemas/generated/jobsv1_pb2.pyi +12 -0
- sky/schemas/generated/jobsv1_pb2_grpc.py +44 -0
- sky/schemas/generated/managed_jobsv1_pb2.py +32 -28
- sky/schemas/generated/managed_jobsv1_pb2.pyi +11 -2
- sky/serve/serve_utils.py +232 -40
- sky/server/common.py +17 -0
- sky/server/constants.py +1 -1
- sky/server/metrics.py +6 -3
- sky/server/plugins.py +16 -0
- sky/server/requests/payloads.py +18 -0
- sky/server/requests/request_names.py +2 -0
- sky/server/requests/requests.py +28 -10
- sky/server/requests/serializers/encoders.py +5 -0
- sky/server/requests/serializers/return_value_serializers.py +14 -4
- sky/server/server.py +434 -107
- sky/server/uvicorn.py +5 -0
- sky/setup_files/MANIFEST.in +1 -0
- sky/setup_files/dependencies.py +21 -10
- sky/sky_logging.py +2 -1
- sky/skylet/constants.py +22 -5
- sky/skylet/executor/slurm.py +4 -6
- sky/skylet/job_lib.py +89 -4
- sky/skylet/services.py +18 -3
- sky/ssh_node_pools/deploy/tunnel/cleanup-tunnel.sh +62 -0
- sky/ssh_node_pools/deploy/tunnel/ssh-tunnel.sh +379 -0
- sky/templates/kubernetes-ray.yml.j2 +4 -6
- sky/templates/slurm-ray.yml.j2 +32 -2
- sky/templates/websocket_proxy.py +18 -41
- sky/users/permission.py +61 -51
- sky/utils/auth_utils.py +42 -0
- sky/utils/cli_utils/status_utils.py +19 -5
- sky/utils/cluster_utils.py +10 -3
- sky/utils/command_runner.py +256 -94
- sky/utils/command_runner.pyi +16 -0
- sky/utils/common_utils.py +30 -29
- sky/utils/context.py +32 -0
- sky/utils/db/db_utils.py +36 -6
- sky/utils/db/migration_utils.py +41 -21
- sky/utils/infra_utils.py +5 -1
- sky/utils/instance_links.py +139 -0
- sky/utils/interactive_utils.py +49 -0
- sky/utils/kubernetes/generate_kubeconfig.sh +42 -33
- sky/utils/kubernetes/rsync_helper.sh +5 -1
- sky/utils/plugin_extensions/__init__.py +14 -0
- sky/utils/plugin_extensions/external_failure_source.py +176 -0
- sky/utils/resources_utils.py +10 -8
- sky/utils/rich_utils.py +9 -11
- sky/utils/schemas.py +63 -20
- sky/utils/status_lib.py +7 -0
- sky/utils/subprocess_utils.py +17 -0
- sky/volumes/client/sdk.py +6 -3
- sky/volumes/server/core.py +65 -27
- sky_templates/ray/start_cluster +8 -4
- {skypilot_nightly-1.0.0.dev20251210.dist-info → skypilot_nightly-1.0.0.dev20260112.dist-info}/METADATA +53 -57
- {skypilot_nightly-1.0.0.dev20251210.dist-info → skypilot_nightly-1.0.0.dev20260112.dist-info}/RECORD +172 -162
- sky/dashboard/out/_next/static/KYAhEFa3FTfq4JyKVgo-s/_buildManifest.js +0 -1
- sky/dashboard/out/_next/static/chunks/1141-9c810f01ff4f398a.js +0 -11
- sky/dashboard/out/_next/static/chunks/1871-7e202677c42f43fe.js +0 -6
- sky/dashboard/out/_next/static/chunks/2260-7703229c33c5ebd5.js +0 -1
- sky/dashboard/out/_next/static/chunks/2350.fab69e61bac57b23.js +0 -1
- sky/dashboard/out/_next/static/chunks/2369.fc20f0c2c8ed9fe7.js +0 -15
- sky/dashboard/out/_next/static/chunks/2755.edd818326d489a1d.js +0 -26
- sky/dashboard/out/_next/static/chunks/3294.ddda8c6c6f9f24dc.js +0 -1
- sky/dashboard/out/_next/static/chunks/3785.7e245f318f9d1121.js +0 -1
- sky/dashboard/out/_next/static/chunks/3800-b589397dc09c5b4e.js +0 -1
- sky/dashboard/out/_next/static/chunks/4725.172ede95d1b21022.js +0 -1
- sky/dashboard/out/_next/static/chunks/4937.a2baa2df5572a276.js +0 -15
- sky/dashboard/out/_next/static/chunks/6212-7bd06f60ba693125.js +0 -13
- sky/dashboard/out/_next/static/chunks/6856-da20c5fd999f319c.js +0 -1
- sky/dashboard/out/_next/static/chunks/6989-01359c57e018caa4.js +0 -1
- sky/dashboard/out/_next/static/chunks/6990-09cbf02d3cd518c3.js +0 -1
- sky/dashboard/out/_next/static/chunks/7359-c8d04e06886000b3.js +0 -30
- sky/dashboard/out/_next/static/chunks/7411-b15471acd2cba716.js +0 -41
- sky/dashboard/out/_next/static/chunks/7615-019513abc55b3b47.js +0 -1
- sky/dashboard/out/_next/static/chunks/8969-452f9d5cbdd2dc73.js +0 -1
- sky/dashboard/out/_next/static/chunks/9025.fa408f3242e9028d.js +0 -6
- sky/dashboard/out/_next/static/chunks/9360.a536cf6b1fa42355.js +0 -31
- sky/dashboard/out/_next/static/chunks/9847.3aaca6bb33455140.js +0 -30
- sky/dashboard/out/_next/static/chunks/pages/_app-68b647e26f9d2793.js +0 -34
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-33f525539665fdfd.js +0 -16
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]-a7565f586ef86467.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/infra/[context]-12c559ec4d81fdbd.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/infra-d187cd0413d72475.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-895847b6cf200b04.js +0 -16
- sky/dashboard/out/_next/static/chunks/pages/jobs/pools/[pool]-8d0f4655400b4eb9.js +0 -21
- sky/dashboard/out/_next/static/chunks/pages/jobs-e5a98f17f8513a96.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/users-2f7646eb77785a2c.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/workspaces-cb4da3abe08ebf19.js +0 -1
- sky/dashboard/out/_next/static/chunks/webpack-fba3de387ff6bb08.js +0 -1
- sky/dashboard/out/_next/static/css/c5a4cfd2600fc715.css +0 -3
- /sky/dashboard/out/_next/static/{KYAhEFa3FTfq4JyKVgo-s → 3nu-b8raeKRNABZ2d4GAG}/_ssgManifest.js +0 -0
- /sky/dashboard/out/_next/static/chunks/pages/plugins/{[...slug]-4f46050ca065d8f8.js → [...slug]-449a9f5a3bb20fb3.js} +0 -0
- {skypilot_nightly-1.0.0.dev20251210.dist-info → skypilot_nightly-1.0.0.dev20260112.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20251210.dist-info → skypilot_nightly-1.0.0.dev20260112.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20251210.dist-info → skypilot_nightly-1.0.0.dev20260112.dist-info}/licenses/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20251210.dist-info → skypilot_nightly-1.0.0.dev20260112.dist-info}/top_level.txt +0 -0
sky/clouds/aws.py
CHANGED
|
@@ -12,6 +12,7 @@ import typing
|
|
|
12
12
|
from typing import (Any, Callable, Dict, Iterator, List, Literal, Optional, Set,
|
|
13
13
|
Tuple, TypeVar, Union)
|
|
14
14
|
|
|
15
|
+
import colorama
|
|
15
16
|
from typing_extensions import ParamSpec
|
|
16
17
|
|
|
17
18
|
from sky import catalog
|
|
@@ -758,6 +759,36 @@ class AWS(clouds.Cloud):
|
|
|
758
759
|
max_efa_interfaces = 0
|
|
759
760
|
enable_efa = False
|
|
760
761
|
|
|
762
|
+
use_internal_ips = skypilot_config.get_effective_region_config(
|
|
763
|
+
cloud='aws',
|
|
764
|
+
region=region_name,
|
|
765
|
+
keys=('use_internal_ips',),
|
|
766
|
+
default_value=False)
|
|
767
|
+
if max_efa_interfaces > 1 and not use_internal_ips:
|
|
768
|
+
logger.warning(
|
|
769
|
+
f'{colorama.Fore.YELLOW}'
|
|
770
|
+
f'Instance type {resources.instance_type} supports up to '
|
|
771
|
+
f'{max_efa_interfaces} EFA interfaces, but '
|
|
772
|
+
'`use_internal_ips` is not enabled.\nLaunching with the '
|
|
773
|
+
'current configuration will use only 1 EFA interface.\n'
|
|
774
|
+
f'To use all {max_efa_interfaces} EFA interfaces, enable '
|
|
775
|
+
'internal IPs by adding one of the following '
|
|
776
|
+
'configurations to SkyPilot config:\n'
|
|
777
|
+
'Option 1 (with SSM):\n'
|
|
778
|
+
' aws:\n'
|
|
779
|
+
' use_internal_ips: true\n'
|
|
780
|
+
' use_ssm: true\n'
|
|
781
|
+
'Option 2 (with SSH proxy):\n'
|
|
782
|
+
' aws:\n'
|
|
783
|
+
' use_internal_ips: true\n'
|
|
784
|
+
' ssh_proxy_command: ssh -W %h:%p -i <ssh key path> '
|
|
785
|
+
'-o StrictHostKeyChecking=no <user>@<jump server public'
|
|
786
|
+
' ip>\n'
|
|
787
|
+
'Refer to '
|
|
788
|
+
'https://docs.skypilot.co/en/latest/reference/config.html'
|
|
789
|
+
'#aws-use-internal-ips for more details.'
|
|
790
|
+
f'{colorama.Style.RESET_ALL}')
|
|
791
|
+
|
|
761
792
|
docker_run_options = []
|
|
762
793
|
if resources.extract_docker_image() is not None:
|
|
763
794
|
image_id_to_use = None
|
|
@@ -1005,8 +1036,10 @@ class AWS(clouds.Cloud):
|
|
|
1005
1036
|
hints = 'AWS SSO is set.'
|
|
1006
1037
|
if static_credential_exists:
|
|
1007
1038
|
hints += (
|
|
1008
|
-
' To ensure
|
|
1009
|
-
'
|
|
1039
|
+
' To ensure S3 mounting and other features work correctly '
|
|
1040
|
+
'on Kubernetes and other clouds, '
|
|
1041
|
+
'please use SkyPilot with static AWS credentials '
|
|
1042
|
+
'(e.g., ~/.aws/credentials) by unsetting '
|
|
1010
1043
|
'the AWS_PROFILE environment variable.')
|
|
1011
1044
|
else:
|
|
1012
1045
|
hints += single_cloud_hint
|
|
@@ -1081,6 +1114,31 @@ class AWS(clouds.Cloud):
|
|
|
1081
1114
|
return identity_type
|
|
1082
1115
|
return AWSIdentityType.SHARED_CREDENTIALS_FILE
|
|
1083
1116
|
|
|
1117
|
+
@classmethod
|
|
1118
|
+
def should_use_env_auth_for_s3(cls) -> bool:
|
|
1119
|
+
"""Returns True if S3 should use environment-based auth.
|
|
1120
|
+
|
|
1121
|
+
When using non-static AWS credentials (SSO, IAM role, container role),
|
|
1122
|
+
we should not embed credentials into rclone config. Instead, we should
|
|
1123
|
+
use env_auth=true so that rclone uses the AWS SDK credential chain,
|
|
1124
|
+
which properly handles temporary credentials and IAM roles.
|
|
1125
|
+
|
|
1126
|
+
Returns:
|
|
1127
|
+
True if environment-based auth should be used, False for static
|
|
1128
|
+
credentials that can be embedded.
|
|
1129
|
+
"""
|
|
1130
|
+
identity_type = cls._current_identity_type()
|
|
1131
|
+
if identity_type is None:
|
|
1132
|
+
return False
|
|
1133
|
+
# These credential types use temporary credentials that should not be
|
|
1134
|
+
# embedded in config files. They rely on the AWS SDK credential chain.
|
|
1135
|
+
non_static_types = {
|
|
1136
|
+
AWSIdentityType.SSO,
|
|
1137
|
+
AWSIdentityType.IAM_ROLE,
|
|
1138
|
+
AWSIdentityType.CONTAINER_ROLE,
|
|
1139
|
+
}
|
|
1140
|
+
return identity_type in non_static_types
|
|
1141
|
+
|
|
1084
1142
|
@classmethod
|
|
1085
1143
|
@aws_profile_aware_lru_cache(scope='request',
|
|
1086
1144
|
maxsize=_AWS_PROFILE_SCOPED_FUNC_CACHE_SIZE)
|
sky/clouds/azure.py
CHANGED
|
@@ -97,6 +97,8 @@ class Azure(clouds.Cloud):
|
|
|
97
97
|
clouds.CloudImplementationFeatures.HIGH_AVAILABILITY_CONTROLLERS: (
|
|
98
98
|
f'High availability controllers are not supported on {cls._REPR}.'
|
|
99
99
|
),
|
|
100
|
+
clouds.CloudImplementationFeatures.CUSTOM_NETWORK_TIER:
|
|
101
|
+
(f'Custom network tier is not supported on {cls._REPR}.'),
|
|
100
102
|
clouds.CloudImplementationFeatures.CUSTOM_MULTI_NETWORK: (
|
|
101
103
|
f'Customized multiple network interfaces are not supported on {cls._REPR}.'
|
|
102
104
|
),
|
sky/clouds/kubernetes.py
CHANGED
|
@@ -766,6 +766,8 @@ class Kubernetes(clouds.Cloud):
|
|
|
766
766
|
'ha_recovery_log_path':
|
|
767
767
|
constants.HA_PERSISTENT_RECOVERY_LOG_PATH.format(''),
|
|
768
768
|
'sky_python_cmd': constants.SKY_PYTHON_CMD,
|
|
769
|
+
'sky_unset_pythonpath_and_set_cwd':
|
|
770
|
+
constants.SKY_UNSET_PYTHONPATH_AND_SET_CWD,
|
|
769
771
|
'k8s_high_availability_storage_class_name':
|
|
770
772
|
(k8s_ha_storage_class_name),
|
|
771
773
|
'avoid_label_keys': avoid_label_keys,
|
sky/clouds/runpod.py
CHANGED
|
@@ -7,6 +7,7 @@ from typing import Dict, Iterator, List, Optional, Tuple, Union
|
|
|
7
7
|
|
|
8
8
|
from sky import catalog
|
|
9
9
|
from sky import clouds
|
|
10
|
+
from sky.utils import common_utils
|
|
10
11
|
from sky.utils import registry
|
|
11
12
|
from sky.utils import resources_utils
|
|
12
13
|
|
|
@@ -312,18 +313,48 @@ class RunPod(clouds.Cloud):
|
|
|
312
313
|
# If that happens to be set to None, then ValueError is raised.
|
|
313
314
|
return False, dependency_error_msg
|
|
314
315
|
|
|
316
|
+
hint_msg = (
|
|
317
|
+
'Credentials can be set up by running: \n'
|
|
318
|
+
' $ pip install runpod \n'
|
|
319
|
+
' $ runpod config\n'
|
|
320
|
+
' For more information, see https://docs.skypilot.co/en/latest/getting-started/installation.html#runpod' # pylint: disable=line-too-long
|
|
321
|
+
)
|
|
322
|
+
|
|
315
323
|
valid, error = cls._check_runpod_credentials()
|
|
316
324
|
if not valid:
|
|
317
|
-
return False, (
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
)
|
|
325
|
+
return False, (f'{error} \n {hint_msg}')
|
|
326
|
+
|
|
327
|
+
# Validate credentials by making an actual API call
|
|
328
|
+
valid, error = cls._validate_api_key()
|
|
329
|
+
if not valid:
|
|
330
|
+
return False, (f'{error} \n {hint_msg}')
|
|
324
331
|
|
|
325
332
|
return True, None
|
|
326
333
|
|
|
334
|
+
@classmethod
|
|
335
|
+
def _validate_api_key(cls) -> Tuple[bool, Optional[str]]:
|
|
336
|
+
"""Validate RunPod API key by making an actual API call."""
|
|
337
|
+
# Import here to avoid circular imports and ensure runpod is configured
|
|
338
|
+
# pylint: disable=import-outside-toplevel
|
|
339
|
+
from sky.provision.runpod import utils as runpod_utils
|
|
340
|
+
try:
|
|
341
|
+
# Try to list instances to validate the API key works
|
|
342
|
+
runpod_utils.list_instances()
|
|
343
|
+
return True, None
|
|
344
|
+
except Exception as e: # pylint: disable=broad-except
|
|
345
|
+
from sky.adaptors import runpod
|
|
346
|
+
error_msg = common_utils.format_exception(e, use_bracket=True)
|
|
347
|
+
if isinstance(e, runpod.runpod.error.QueryError):
|
|
348
|
+
error_msg_lower = str(e).lower()
|
|
349
|
+
auth_keywords = ['unauthorized', 'forbidden', '401', '403']
|
|
350
|
+
if any(keyword in error_msg_lower for keyword in auth_keywords):
|
|
351
|
+
return False, (
|
|
352
|
+
'RunPod API key is invalid or lacks required '
|
|
353
|
+
f'permissions. {error_msg}')
|
|
354
|
+
return False, (f'Failed to verify RunPod API key. {error_msg}')
|
|
355
|
+
return False, ('An unexpected error occurred during RunPod API '
|
|
356
|
+
f'key validation. {error_msg}')
|
|
357
|
+
|
|
327
358
|
@classmethod
|
|
328
359
|
def _check_runpod_credentials(cls, profile: str = 'default'):
|
|
329
360
|
"""Checks if the credentials file exists and is valid."""
|
sky/clouds/slurm.py
CHANGED
|
@@ -9,6 +9,7 @@ from sky import sky_logging
|
|
|
9
9
|
from sky import skypilot_config
|
|
10
10
|
from sky.adaptors import slurm
|
|
11
11
|
from sky.provision.slurm import utils as slurm_utils
|
|
12
|
+
from sky.skylet import constants
|
|
12
13
|
from sky.utils import annotations
|
|
13
14
|
from sky.utils import common_utils
|
|
14
15
|
from sky.utils import registry
|
|
@@ -55,10 +56,20 @@ class Slurm(clouds.Cloud):
|
|
|
55
56
|
_regions: List[clouds.Region] = []
|
|
56
57
|
_INDENT_PREFIX = ' '
|
|
57
58
|
|
|
59
|
+
# Same as Kubernetes.
|
|
60
|
+
_DEFAULT_NUM_VCPUS_WITH_GPU = 4
|
|
61
|
+
_DEFAULT_MEMORY_CPU_RATIO_WITH_GPU = 4
|
|
62
|
+
|
|
58
63
|
# Using the latest SkyPilot provisioner API to provision and check status.
|
|
59
64
|
PROVISIONER_VERSION = clouds.ProvisionerVersion.SKYPILOT
|
|
60
65
|
STATUS_VERSION = clouds.StatusVersion.SKYPILOT
|
|
61
66
|
|
|
67
|
+
_SSH_CONFIG_KEY_MAPPING = {
|
|
68
|
+
'identityfile': 'IdentityFile',
|
|
69
|
+
'user': 'User',
|
|
70
|
+
'hostname': 'HostName',
|
|
71
|
+
}
|
|
72
|
+
|
|
62
73
|
@classmethod
|
|
63
74
|
def _unsupported_features_for_resources(
|
|
64
75
|
cls,
|
|
@@ -323,7 +334,13 @@ class Slurm(clouds.Cloud):
|
|
|
323
334
|
if zones and len(zones) > 0:
|
|
324
335
|
partition = zones[0].name
|
|
325
336
|
else:
|
|
326
|
-
|
|
337
|
+
partitions = slurm_utils.get_partitions(cluster)
|
|
338
|
+
if not partitions:
|
|
339
|
+
raise ValueError(f'No partitions found for cluster {cluster}.')
|
|
340
|
+
# get_partitions returns the default partition first, then sorted
|
|
341
|
+
# alphabetically, so this also handles the case where the cluster
|
|
342
|
+
# does not have a default partition.
|
|
343
|
+
partition = partitions[0]
|
|
327
344
|
|
|
328
345
|
# cluster is our target slurmctld host.
|
|
329
346
|
ssh_config = slurm_utils.get_slurm_ssh_config()
|
|
@@ -344,6 +361,10 @@ class Slurm(clouds.Cloud):
|
|
|
344
361
|
# Optionally populate accelerator information.
|
|
345
362
|
acc_count = s.accelerator_count if s.accelerator_count else 0
|
|
346
363
|
acc_type = s.accelerator_type if s.accelerator_type else None
|
|
364
|
+
# Resolve the actual GPU type as it appears in the cluster's GRES.
|
|
365
|
+
# Slurm GRES types are case-sensitive.
|
|
366
|
+
if acc_type:
|
|
367
|
+
acc_type = slurm_utils.get_gres_gpu_type(cluster, acc_type)
|
|
347
368
|
|
|
348
369
|
deploy_vars = {
|
|
349
370
|
'instance_type': resources.instance_type,
|
|
@@ -359,9 +380,14 @@ class Slurm(clouds.Cloud):
|
|
|
359
380
|
'ssh_port': str(ssh_config_dict.get('port', 22)),
|
|
360
381
|
'ssh_user': ssh_config_dict['user'],
|
|
361
382
|
'slurm_proxy_command': ssh_config_dict.get('proxycommand', None),
|
|
383
|
+
'slurm_proxy_jump': ssh_config_dict.get('proxyjump', None),
|
|
362
384
|
# TODO(jwj): Solve naming collision with 'ssh_private_key'.
|
|
363
385
|
# Please refer to slurm-ray.yml.j2 'ssh' and 'auth' sections.
|
|
364
386
|
'slurm_private_key': ssh_config_dict['identityfile'][0],
|
|
387
|
+
'slurm_sshd_host_key_filename':
|
|
388
|
+
(slurm_utils.SLURM_SSHD_HOST_KEY_FILENAME),
|
|
389
|
+
'slurm_cluster_name_env_var':
|
|
390
|
+
(constants.SKY_CLUSTER_NAME_ENV_VAR_KEY),
|
|
365
391
|
}
|
|
366
392
|
|
|
367
393
|
return deploy_vars
|
|
@@ -423,13 +449,12 @@ class Slurm(clouds.Cloud):
|
|
|
423
449
|
from_instance_type(default_instance_type))
|
|
424
450
|
|
|
425
451
|
gpu_task_cpus = slurm_instance_type.cpus
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
#
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
# self._DEFAULT_MEMORY_CPU_RATIO_WITH_GPU)
|
|
452
|
+
if resources.cpus is None:
|
|
453
|
+
gpu_task_cpus = self._DEFAULT_NUM_VCPUS_WITH_GPU * acc_count
|
|
454
|
+
# Special handling to bump up memory multiplier for GPU instances
|
|
455
|
+
gpu_task_memory = (float(resources.memory.strip('+')) if
|
|
456
|
+
resources.memory is not None else gpu_task_cpus *
|
|
457
|
+
self._DEFAULT_MEMORY_CPU_RATIO_WITH_GPU)
|
|
433
458
|
|
|
434
459
|
chosen_instance_type = (
|
|
435
460
|
slurm_utils.SlurmInstanceType.from_resources(
|
|
@@ -470,8 +495,8 @@ class Slurm(clouds.Cloud):
|
|
|
470
495
|
existing_allowed_clusters = cls.existing_allowed_clusters()
|
|
471
496
|
|
|
472
497
|
if not existing_allowed_clusters:
|
|
473
|
-
return (False, 'No
|
|
474
|
-
'Please configure at least one
|
|
498
|
+
return (False, 'No Slurm clusters found in ~/.slurm/config. '
|
|
499
|
+
'Please configure at least one Slurm cluster.')
|
|
475
500
|
|
|
476
501
|
# Check credentials for each cluster and return ctx2text mapping
|
|
477
502
|
ctx2text = {}
|
|
@@ -479,18 +504,25 @@ class Slurm(clouds.Cloud):
|
|
|
479
504
|
for cluster in existing_allowed_clusters:
|
|
480
505
|
# Retrieve the config options for a given SlurmctldHost name alias.
|
|
481
506
|
ssh_config_dict = ssh_config.lookup(cluster)
|
|
482
|
-
|
|
483
507
|
try:
|
|
484
508
|
client = slurm.SlurmClient(
|
|
485
509
|
ssh_config_dict['hostname'],
|
|
486
510
|
int(ssh_config_dict.get('port', 22)),
|
|
487
511
|
ssh_config_dict['user'],
|
|
488
512
|
ssh_config_dict['identityfile'][0],
|
|
489
|
-
ssh_proxy_command=ssh_config_dict.get('proxycommand', None)
|
|
513
|
+
ssh_proxy_command=ssh_config_dict.get('proxycommand', None),
|
|
514
|
+
ssh_proxy_jump=ssh_config_dict.get('proxyjump', None))
|
|
490
515
|
info = client.info()
|
|
491
516
|
logger.debug(f'Slurm cluster {cluster} sinfo: {info}')
|
|
492
517
|
ctx2text[cluster] = 'enabled'
|
|
493
518
|
success = True
|
|
519
|
+
except KeyError as e:
|
|
520
|
+
key = e.args[0]
|
|
521
|
+
ctx2text[cluster] = (
|
|
522
|
+
f'disabled. '
|
|
523
|
+
f'{cls._SSH_CONFIG_KEY_MAPPING.get(key, key.capitalize())} '
|
|
524
|
+
'is missing, please check your ~/.slurm/config '
|
|
525
|
+
'and try again.')
|
|
494
526
|
except Exception as e: # pylint: disable=broad-except
|
|
495
527
|
error_msg = (f'Credential check failed: '
|
|
496
528
|
f'{common_utils.format_exception(e)}')
|
sky/clouds/ssh.py
CHANGED
|
@@ -255,7 +255,7 @@ class SSH(kubernetes.Kubernetes):
|
|
|
255
255
|
@classmethod
|
|
256
256
|
def expand_infras(cls) -> List[str]:
|
|
257
257
|
return [
|
|
258
|
-
f'{cls.canonical_name()}/{
|
|
258
|
+
f'{cls.canonical_name()}/{common_utils.removeprefix(c, "ssh-")}'
|
|
259
259
|
for c in cls.existing_allowed_contexts(silent=True)
|
|
260
260
|
]
|
|
261
261
|
|
sky/clouds/vast.py
CHANGED
|
@@ -147,20 +147,24 @@ class Vast(clouds.Cloud):
|
|
|
147
147
|
return 0.0
|
|
148
148
|
|
|
149
149
|
@classmethod
|
|
150
|
-
def get_default_instance_type(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
150
|
+
def get_default_instance_type(
|
|
151
|
+
cls,
|
|
152
|
+
cpus: Optional[str] = None,
|
|
153
|
+
memory: Optional[str] = None,
|
|
154
|
+
disk_tier: Optional[resources_utils.DiskTier] = None,
|
|
155
|
+
region: Optional[str] = None,
|
|
156
|
+
zone: Optional[str] = None,
|
|
157
|
+
datacenter_only: bool = False) -> Optional[str]:
|
|
157
158
|
"""Returns the default instance type for Vast."""
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
159
|
+
# pylint: disable=import-outside-toplevel
|
|
160
|
+
from sky.catalog import vast_catalog
|
|
161
|
+
return vast_catalog.get_default_instance_type(
|
|
162
|
+
cpus=cpus,
|
|
163
|
+
memory=memory,
|
|
164
|
+
disk_tier=disk_tier,
|
|
165
|
+
region=region,
|
|
166
|
+
zone=zone,
|
|
167
|
+
datacenter_only=datacenter_only)
|
|
164
168
|
|
|
165
169
|
@classmethod
|
|
166
170
|
def get_accelerators_from_instance_type(
|
|
@@ -200,7 +204,7 @@ class Vast(clouds.Cloud):
|
|
|
200
204
|
secure_only = skypilot_config.get_effective_region_config(
|
|
201
205
|
cloud='vast',
|
|
202
206
|
region=region.name,
|
|
203
|
-
keys=('
|
|
207
|
+
keys=('datacenter_only',),
|
|
204
208
|
default_value=False,
|
|
205
209
|
override_configs=resources.cluster_config_overrides,
|
|
206
210
|
)
|
|
@@ -217,6 +221,8 @@ class Vast(clouds.Cloud):
|
|
|
217
221
|
self, resources: 'resources_lib.Resources'
|
|
218
222
|
) -> 'resources_utils.FeasibleResources':
|
|
219
223
|
"""Returns a list of feasible resources for the given resources."""
|
|
224
|
+
# pylint: disable=import-outside-toplevel
|
|
225
|
+
from sky.catalog import vast_catalog
|
|
220
226
|
if resources.instance_type is not None:
|
|
221
227
|
assert resources.is_launchable(), resources
|
|
222
228
|
resources = resources.copy(accelerators=None)
|
|
@@ -234,6 +240,12 @@ class Vast(clouds.Cloud):
|
|
|
234
240
|
resource_list.append(r)
|
|
235
241
|
return resource_list
|
|
236
242
|
|
|
243
|
+
# Resolve datacenter_only config first (used for all instance filtering)
|
|
244
|
+
datacenter_only = skypilot_config.get_nested(
|
|
245
|
+
('vast', 'datacenter_only'),
|
|
246
|
+
False,
|
|
247
|
+
override_configs=resources.cluster_config_overrides)
|
|
248
|
+
|
|
237
249
|
# Currently, handle a filter on accelerators only.
|
|
238
250
|
accelerators = resources.accelerators
|
|
239
251
|
if accelerators is None:
|
|
@@ -243,7 +255,8 @@ class Vast(clouds.Cloud):
|
|
|
243
255
|
memory=resources.memory,
|
|
244
256
|
disk_tier=resources.disk_tier,
|
|
245
257
|
region=resources.region,
|
|
246
|
-
zone=resources.zone
|
|
258
|
+
zone=resources.zone,
|
|
259
|
+
datacenter_only=datacenter_only)
|
|
247
260
|
if default_instance_type is None:
|
|
248
261
|
# TODO: Add hints to all return values in this method to help
|
|
249
262
|
# users understand why the resources are not launchable.
|
|
@@ -255,7 +268,7 @@ class Vast(clouds.Cloud):
|
|
|
255
268
|
assert len(accelerators) == 1, resources
|
|
256
269
|
acc, acc_count = list(accelerators.items())[0]
|
|
257
270
|
(instance_list,
|
|
258
|
-
fuzzy_candidate_list) =
|
|
271
|
+
fuzzy_candidate_list) = vast_catalog.get_instance_type_for_accelerator(
|
|
259
272
|
acc,
|
|
260
273
|
acc_count,
|
|
261
274
|
use_spot=resources.use_spot,
|
|
@@ -263,7 +276,7 @@ class Vast(clouds.Cloud):
|
|
|
263
276
|
region=resources.region,
|
|
264
277
|
zone=resources.zone,
|
|
265
278
|
memory=resources.memory,
|
|
266
|
-
|
|
279
|
+
datacenter_only=datacenter_only)
|
|
267
280
|
if instance_list is None:
|
|
268
281
|
return resources_utils.FeasibleResources([], fuzzy_candidate_list,
|
|
269
282
|
None)
|
sky/core.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""SDK functions for cluster/job management."""
|
|
2
2
|
import typing
|
|
3
|
-
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
3
|
+
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
|
|
4
4
|
|
|
5
5
|
import colorama
|
|
6
6
|
|
|
@@ -279,6 +279,74 @@ all_clusters, unmanaged_clusters, all_jobs, context
|
|
|
279
279
|
return all_clusters, unmanaged_clusters, all_jobs, context
|
|
280
280
|
|
|
281
281
|
|
|
282
|
+
@typing.overload
|
|
283
|
+
def get_cluster_events(
|
|
284
|
+
cluster_name: Optional[str] = ...,
|
|
285
|
+
cluster_hash: Optional[str] = ...,
|
|
286
|
+
event_type: str = ...,
|
|
287
|
+
include_timestamps: Literal[False] = ...,
|
|
288
|
+
limit: Optional[int] = ...,
|
|
289
|
+
) -> List[str]:
|
|
290
|
+
...
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
@typing.overload
|
|
294
|
+
def get_cluster_events(
|
|
295
|
+
cluster_name: Optional[str] = ...,
|
|
296
|
+
cluster_hash: Optional[str] = ...,
|
|
297
|
+
event_type: str = ...,
|
|
298
|
+
include_timestamps: Literal[True] = ...,
|
|
299
|
+
limit: Optional[int] = ...,
|
|
300
|
+
) -> List[Dict[str, Union[str, int]]]:
|
|
301
|
+
...
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
@typing.overload
|
|
305
|
+
def get_cluster_events(
|
|
306
|
+
cluster_name: Optional[str] = ...,
|
|
307
|
+
cluster_hash: Optional[str] = ...,
|
|
308
|
+
event_type: str = ...,
|
|
309
|
+
include_timestamps: bool = ...,
|
|
310
|
+
limit: Optional[int] = ...,
|
|
311
|
+
) -> Union[List[str], List[Dict[str, Union[str, int]]]]:
|
|
312
|
+
...
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def get_cluster_events(
|
|
316
|
+
cluster_name: Optional[str] = None,
|
|
317
|
+
cluster_hash: Optional[str] = None,
|
|
318
|
+
event_type: str = 'STATUS_CHANGE',
|
|
319
|
+
include_timestamps: bool = False,
|
|
320
|
+
limit: Optional[int] = None
|
|
321
|
+
) -> Union[List[str], List[Dict[str, Union[str, int]]]]:
|
|
322
|
+
"""Get events for a cluster.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
cluster_name: Name of the cluster. Cannot be specified if cluster_hash
|
|
326
|
+
is specified.
|
|
327
|
+
cluster_hash: Hash of the cluster. Cannot be specified if cluster_name
|
|
328
|
+
is specified.
|
|
329
|
+
event_type: Type of events to retrieve ('STATUS_CHANGE' or 'DEBUG').
|
|
330
|
+
include_timestamps: If True, returns list of dicts with 'reason' and
|
|
331
|
+
'transitioned_at' fields. If False, returns list of reason strings.
|
|
332
|
+
limit: If specified, returns at most this many events (most recent).
|
|
333
|
+
If None, returns all events.
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
If include_timestamps is False: List of event reason strings.
|
|
337
|
+
If include_timestamps is True: List of dicts with 'reason' and
|
|
338
|
+
'transitioned_at' (unix timestamp) fields.
|
|
339
|
+
Events are ordered from oldest to newest.
|
|
340
|
+
"""
|
|
341
|
+
event_type_enum = global_user_state.ClusterEventType(event_type)
|
|
342
|
+
return global_user_state.get_cluster_events(
|
|
343
|
+
cluster_name=cluster_name,
|
|
344
|
+
cluster_hash=cluster_hash,
|
|
345
|
+
event_type=event_type_enum,
|
|
346
|
+
include_timestamps=include_timestamps,
|
|
347
|
+
limit=limit)
|
|
348
|
+
|
|
349
|
+
|
|
282
350
|
def endpoints(cluster: str,
|
|
283
351
|
port: Optional[Union[int, str]] = None) -> Dict[int, str]:
|
|
284
352
|
"""Gets the endpoint for a given cluster and port number (endpoint).
|
sky/dashboard/out/404.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/
|
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/dashboard/_next/static/css/b0dbca28f027cc19.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/b0dbca28f027cc19.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/dashboard/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js"></script><script src="/dashboard/_next/static/chunks/webpack-cfe59cf684ee13b9.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-cf60a09ccd051a10.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-f15ccb73239a3bf1.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-5a86569acad99764.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_error-c66a4e8afc46f17b.js" defer=""></script><script src="/dashboard/_next/static/3nu-b8raeKRNABZ2d4GAG/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/3nu-b8raeKRNABZ2d4GAG/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"3nu-b8raeKRNABZ2d4GAG","assetPrefix":"/dashboard","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
self.__BUILD_MANIFEST=function(s,c,a,e,t,u,n,f,i,b,j,o,r,k,d,l){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":["static/chunks/pages/index-444f1804401f04ea.js"],"/_error":["static/chunks/pages/_error-c66a4e8afc46f17b.js"],"/clusters":["static/chunks/pages/clusters-57632ff3684a8b5c.js"],"/clusters/[cluster]":[c,s,a,b,u,j,f,e,t,n,o,r,i,k,d,"static/chunks/1871-0565f8975a7dcd10.js","static/chunks/pages/clusters/[cluster]-337c3ba1085f1210.js"],"/clusters/[cluster]/[job]":[c,s,a,e,t,l,"static/chunks/pages/clusters/[cluster]/[job]-8297476714acb4ac.js"],"/config":["static/chunks/pages/config-718cdc365de82689.js"],"/infra":["static/chunks/pages/infra-9f85c02c9c6cae9e.js"],"/infra/[context]":["static/chunks/pages/infra/[context]-5fd3a453c079c2ea.js"],"/jobs":["static/chunks/pages/jobs-ed806aeace26b972.js"],"/jobs/pools/[pool]":[c,s,a,u,f,"static/chunks/8821-93c25df904a8362b.js",e,t,n,i,"static/chunks/pages/jobs/pools/[pool]-2dd42fc37aad427a.js"],"/jobs/[job]":[c,s,a,u,f,e,t,n,l,"static/chunks/pages/jobs/[job]-90f16972cbecf354.js"],"/plugins/[...slug]":[s,"static/chunks/pages/plugins/[...slug]-449a9f5a3bb20fb3.js"],"/users":["static/chunks/pages/users-bec34706b36f3524.js"],"/volumes":["static/chunks/pages/volumes-a83ba9b38dff7ea9.js"],"/workspace/new":["static/chunks/pages/workspace/new-3f88a1c7e86a3f86.js"],"/workspaces":["static/chunks/pages/workspaces-91e0942f47310aae.js"],"/workspaces/[name]":[c,s,a,b,u,j,e,t,n,o,r,i,k,d,"static/chunks/8050-dd8aa107b17dce00.js","static/chunks/pages/workspaces/[name]-c781e9c3e52ef9fc.js"],sortedPages:["/","/_app","/_error","/clusters","/clusters/[cluster]","/clusters/[cluster]/[job]","/config","/infra","/infra/[context]","/jobs","/jobs/pools/[pool]","/jobs/[job]","/plugins/[...slug]","/users","/volumes","/workspace/new","/workspaces","/workspaces/[name]"]}}("static/chunks/5739-d67458fcb1386c92.js","static/chunks/616-3d59f75e2ccf9321.js","static/chunks/6130-2be46d70a38f1e82.js","static/chunks/6989-49cb7dca83a7a62d.js","static/chunks/3850-fd5696f3bbbaddae.js","static/chunks/1272-1ef0bf0237faccdb.js","static/chunks/8969-0662594b69432ade.js","static/chunks/754-cfc5d4ad1b843d29.js","static/chunks/7248-a99800d4db8edabd.js","static/chunks/6082-edabd8f6092300ce.js","static/chunks/2521-099b07cd9e4745bf.js","static/chunks/6990-630bd2a2257275f8.js","static/chunks/8056-d4ae1e0cb81e7368.js","static/chunks/9353-7ad6bd01858556f1.js","static/chunks/2109-55a1546d793574a7.js","static/chunks/4083-0115d67c1fb57d6c.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1871],{39037:function(e,s,t){t.r(s),t.d(s,{ClusterTable:function(){return P},Clusters:function(){return O},Status2Actions:function(){return F},enabledActions:function(){return H},handleVSCodeConnection:function(){return Z}});var r=t(85893),l=t(67294),a=t(11163),n=t(55739),i=t(36989),c=t(41664),o=t.n(c),u=t(30803),d=t(37673),h=t(68764),x=t(23266),p=t(17324),m=t(94545),f=t(13626),j=t(60998);/**
|
|
2
|
+
* @license lucide-react v0.407.0 - ISC
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the ISC license.
|
|
5
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/let v=(0,j.Z)("Terminal",[["polyline",{points:"4 17 10 11 4 5",key:"akl6gq"}],["line",{x1:"12",x2:"20",y1:"19",y2:"19",key:"q2wloq"}]]),g=(0,j.Z)("SquareCode",[["path",{d:"M10 9.5 8 12l2 2.5",key:"3mjy60"}],["path",{d:"m14 9.5 2 2.5-2 2.5",key:"1bir2l"}],["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]]);t(9353);var y=t(92128),b=t(99307),w=t(23001),k=t(55988),N=t(88950),C=t(6378),S=t(36856);t(1272);var L=t(20546),M=t(10546);let E=[{label:"Status",value:"status"},{label:"Cluster",value:"cluster"},{label:"User",value:"user"},{label:"Workspace",value:"workspace"},{label:"Infra",value:"infra"},{label:"Labels",value:"labels"}],R=(e,s)=>{let t="",r="";return e>=0&&(t=e+"m",r=" "),s&&(t+="".concat(r,"(down)")),""===t&&(t="-"),t},I=(e,s)=>{if(e&&e.includes("@")){let t=e.split("@")[0];return s&&s!==t?"".concat(t," (").concat(s,")"):t}let t=e||s||"N/A";return s&&s!==t?"".concat(t," (").concat(s,")"):t},_=e=>{if(!e||0===e)return"-";let s=e=Math.floor(e),t="",r=0;for(let e of[{value:31536e3,label:"y"},{value:2592e3,label:"mo"},{value:86400,label:"d"},{value:3600,label:"h"},{value:60,label:"m"},{value:1,label:"s"}])if(s>=e.value&&r<2){let l=Math.floor(s/e.value);t+="".concat(l).concat(e.label," "),s%=e.value,r++}return t.trim()||"0s"};function O(){let e=(0,a.useRouter)(),[s,t]=(0,l.useState)(!1),c=l.useRef(null),[u,d]=(0,l.useState)(!1),[h,m]=(0,l.useState)(!1),[j,v]=(0,l.useState)(null),[g,b]=(0,l.useState)(()=>!!e.isReady&&"true"===e.query.history),[k,L]=(0,l.useState)(!0),[M,R]=(0,l.useState)(()=>{if(e.isReady){let s=e.query.historyDays;if(s&&"string"==typeof s&&["1","5","10","30"].includes(s))return parseInt(s)}return 1}),_=(0,w.X)(),[O,Z]=(0,l.useState)([]),[q,H]=(0,l.useState)({status:[],cluster:[],user:[],workspace:[],infra:[],labels:[]}),[W,F]=(0,l.useState)(!1),[z,A]=(0,l.useState)(null);(0,l.useEffect)(()=>{if(e.isReady){T();let s="true"===e.query.history;g!==s&&(L(!1),b(s),setTimeout(()=>L(!0),50));let t=e.query.historyDays;if(t&&"string"==typeof t&&["1","5","10","30"].includes(t)){let e=parseInt(t);M!==e&&R(e)}}},[e.isReady,e.query.history,e.query.historyDays]),(0,l.useEffect)(()=>{(async()=>{try{await S.ZP.preloadForPage("clusters");let e=await C.ZP.get(p.getWorkspaces),s=Object.keys(e),t=await C.ZP.get(x.getClusters),r=[...new Set(t.map(e=>e.workspace||"default").filter(e=>e))],l=new Set(s);r.includes("default")&&l.has("default"),r.forEach(e=>l.add(e));let a=[...new Set(t.map(e=>({userId:e.user_hash||e.user,username:e.user})).filter(e=>e.userId)).values()],n=new Map;a.forEach(e=>{n.set(e.userId,{userId:e.userId,username:e.username,display:I(e.username,e.userId)})}),F(!0),A(new Date)}catch(e){console.error("Error fetching data for filters:",e),F(!0),A(new Date)}})()},[]);let B=s=>{let t={...e.query},r=[],l=[],a=[];s.map((e,s)=>{var t;r.push(null!==(t=e.property.toLowerCase())&&void 0!==t?t:""),l.push(e.operator),a.push(e.value)}),t.property=r,t.operator=l,t.value=a,e.replace({pathname:e.pathname,query:t},void 0,{shallow:!0})},U=s=>{let t={...e.query};t.history=s.toString(),e.replace({pathname:e.pathname,query:t},void 0,{shallow:!0})},Q=s=>{let t={...e.query};t.historyDays=s.toString(),e.replace({pathname:e.pathname,query:t},void 0,{shallow:!0})},T=()=>{let s={...e.query},t=s.property,r=s.operator,l=s.value;if(void 0===t)return;let a=[],n=Array.isArray(t)?t.length:1,i=new Map;if(i.set("",""),i.set("status","Status"),i.set("cluster","Cluster"),i.set("user","User"),i.set("workspace","Workspace"),i.set("infra","Infra"),1===n)a.push({property:i.get(t),operator:r,value:l});else for(let e=0;e<n;e++)a.push({property:i.get(t[e]),operator:r[e],value:l[e]});Z(a)};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)("div",{className:"flex flex-wrap items-center gap-2 mb-1 min-h-[20px]",children:[(0,r.jsx)("div",{className:"flex items-center gap-2",children:(0,r.jsx)(o(),{href:"/clusters",className:"text-sky-blue hover:underline leading-none text-base",children:"Sky Clusters"})}),(0,r.jsx)("div",{className:"w-full sm:w-auto",children:(0,r.jsx)(V,{propertyList:E,valueList:q,setFilters:Z,updateURLParams:B,placeholder:"Filter clusters",filters:O})}),(0,r.jsxs)("div",{className:"flex items-center gap-2 ml-auto",children:[(0,r.jsxs)("div",{className:"flex items-center gap-2",children:[(0,r.jsxs)("label",{className:"flex items-center cursor-pointer",children:[(0,r.jsx)("input",{type:"checkbox",checked:g,onChange:e=>{let s=e.target.checked;b(s),U(s)},className:"sr-only"}),(0,r.jsx)("div",{className:"relative inline-flex h-5 w-9 items-center rounded-full ".concat(k?"transition-colors":""," ").concat(g?"bg-sky-600":"bg-gray-300"),children:(0,r.jsx)("span",{className:"inline-block h-3 w-3 transform rounded-full bg-white ".concat(k?"transition-transform":""," ").concat(g?"translate-x-5":"translate-x-1")})}),(0,r.jsx)("span",{className:"ml-2 text-sm text-gray-700",children:"Show history"})]}),g&&(0,r.jsxs)(N.Ph,{value:M.toString(),onValueChange:e=>{let s=parseInt(e);R(s),Q(s)},children:[(0,r.jsx)(N.i4,{className:"w-24 h-8 text-xs",children:(0,r.jsx)(N.ki,{})}),(0,r.jsxs)(N.Bw,{children:[(0,r.jsx)(N.Ql,{value:"1",children:"1 day"}),(0,r.jsx)(N.Ql,{value:"5",children:"5 days"}),(0,r.jsx)(N.Ql,{value:"10",children:"10 days"}),(0,r.jsx)(N.Ql,{value:"30",children:"30 days"})]})]})]}),s&&(0,r.jsxs)("div",{className:"flex items-center",children:[(0,r.jsx)(n.Z,{size:15,className:"mt-0"}),(0,r.jsx)("span",{className:"ml-2 text-gray-500 text-sm",children:"Loading..."})]}),!s&&z&&(0,r.jsx)(i.$3,{timestamp:z}),(0,r.jsxs)("button",{onClick:()=>{C.ZP.invalidate(x.getClusters),C.ZP.invalidate(p.getWorkspaces),g&&C.ZP.invalidate(x.uR),F(!1),S.ZP.preloadForPage("clusters",{force:!0}).then(()=>{F(!0),A(new Date),c.current&&c.current()})},disabled:s,className:"text-sky-blue hover:text-sky-blue-bright flex items-center",children:[(0,r.jsx)(f.Z,{className:"h-4 w-4 mr-1.5"}),!_&&(0,r.jsx)("span",{children:"Refresh"})]})]})]}),(0,r.jsx)(D,{filters:O,setFilters:Z,updateURLParams:B}),(0,r.jsx)(P,{refreshInterval:i.yc,setLoading:t,refreshDataRef:c,filters:O,showHistory:g,historyDays:M,onOpenSSHModal:e=>{v(e),d(!0)},onOpenVSCodeModal:e=>{v(e),m(!0)},setOptionValues:H,preloadingComplete:W}),(0,r.jsx)(y.Oh,{isOpen:u,onClose:()=>d(!1),cluster:j}),(0,r.jsx)(y._R,{isOpen:h,onClose:()=>m(!1),cluster:j})]})}function P(e){let{refreshInterval:s,setLoading:t,refreshDataRef:a,filters:c,showHistory:p,historyDays:f,onOpenSSHModal:j,onOpenVSCodeModal:v,setOptionValues:g,preloadingComplete:y}=e,[w,N]=(0,l.useState)([]),[S,E]=(0,l.useState)({key:null,direction:"ascending"}),[I,O]=(0,l.useState)(!1),[P,Z]=(0,l.useState)(!0),[q,H]=(0,l.useState)(1),[W,V]=(0,l.useState)(10),D=e=>{let s={status:[],cluster:[],user:[],workspace:[],infra:[],labels:[]},t=(e,s)=>{e.includes(s)||e.push(s)};return e.map(e=>{t(s.status,e.status),t(s.cluster,e.cluster),t(s.user,e.user),t(s.workspace,e.workspace),t(s.infra,e.infra);let r=e.labels||{};r&&"object"==typeof r&&Object.entries(r).forEach(e=>{let[r,l]=e;r&&l&&t(s.labels,"".concat(r,":").concat(l))})}),s},z=l.useCallback(async()=>{t(!0),O(!0);try{let e=await C.ZP.get(x.getClusters);if(p){let s=[];try{s=await C.ZP.get(x.uR,[null,f])}catch(e){console.error("Error fetching cluster history:",e)}let t=e.map(e=>({...e,isHistorical:!1})),r=s.map(e=>({...e,isHistorical:!0})),l=[...t];r.forEach(s=>{e.some(e=>e.cluster_hash===s.cluster_hash)||l.push(s)}),g(D(l)),N(l)}else{let s=e.map(e=>({...e,isHistorical:!1}));g(D(s)),N(s)}}catch(e){console.error("Error fetching cluster data:",e),g(D([])),N([])}t(!1),O(!1),Z(!1)},[t,p,f,g]),A=l.useMemo(()=>{let e=0===c.length?w:w.filter(e=>{let s=null;for(let t=0;t<c.length;t++){let r=c[t],l=(0,M.mu)(e,r);s=null===s?l:s&&l}return s});return(0,m.R0)(e,S.key,S.direction)},[w,S,c]);l.useEffect(()=>{a&&(a.current=z)},[a,z]),(0,l.useEffect)(()=>{N([]);let e=!0;if(y){z();let t=setInterval(()=>{e&&"visible"===window.document.visibilityState&&z()},s);return()=>{e=!1,clearInterval(t)}}return()=>{e=!1}},[s,z,y]),(0,l.useEffect)(()=>{H(1)},[w.length]);let B=e=>{let s="ascending";S.key===e&&"ascending"===S.direction&&(s="descending"),E({key:e,direction:s})},U=e=>S.key===e?"ascending"===S.direction?" ↑":" ↓":"",Q=Math.ceil(A.length/W),T=(q-1)*W,X=T+W,$=A.slice(T,X);return(0,r.jsxs)("div",{children:[(0,r.jsx)(d.Zb,{children:(0,r.jsx)("div",{className:"overflow-x-auto rounded-lg",children:(0,r.jsxs)(h.iA,{className:"min-w-full",children:[(0,r.jsx)(h.xD,{children:(0,r.jsxs)(h.SC,{children:[(0,r.jsxs)(h.ss,{className:"sortable whitespace-nowrap",onClick:()=>B("status"),children:["Status",U("status")]}),(0,r.jsxs)(h.ss,{className:"sortable whitespace-nowrap",onClick:()=>B("cluster"),children:["Cluster",U("cluster")]}),(0,r.jsxs)(h.ss,{className:"sortable whitespace-nowrap",onClick:()=>B("user"),children:["User",U("user")]}),(0,r.jsxs)(h.ss,{className:"sortable whitespace-nowrap",onClick:()=>B("workspace"),children:["Workspace",U("workspace")]}),(0,r.jsxs)(h.ss,{className:"sortable whitespace-nowrap",onClick:()=>B("infra"),children:["Infra",U("infra")]}),(0,r.jsxs)(h.ss,{className:"sortable whitespace-nowrap",onClick:()=>B("resources_str"),children:["Resources",U("resources_str")]}),(0,r.jsxs)(h.ss,{className:"sortable whitespace-nowrap",onClick:()=>B("time"),children:["Started",U("time")]}),p&&(0,r.jsxs)(h.ss,{className:"sortable whitespace-nowrap",onClick:()=>B("duration"),children:["Duration",U("duration")]}),(0,r.jsxs)(h.ss,{className:"sortable whitespace-nowrap",onClick:()=>B("autostop"),children:["Autostop",U("autostop")]}),(0,r.jsx)(h.ss,{className:"md:sticky md:right-0 md:bg-white",children:"Actions"})]})}),(0,r.jsx)(h.RM,{children:I||!y?(0,r.jsx)(h.SC,{children:(0,r.jsx)(h.pj,{colSpan:9,className:"text-center py-6 text-gray-500",children:(0,r.jsxs)("div",{className:"flex justify-center items-center",children:[(0,r.jsx)(n.Z,{size:20,className:"mr-2"}),(0,r.jsx)("span",{children:"Loading..."})]})})}):$.length>0?$.map((e,s)=>(0,r.jsxs)(h.SC,{children:[(0,r.jsx)(h.pj,{children:(0,r.jsx)(k.j,{name:"clusters.table.status.badge",context:e,fallback:(0,r.jsx)(b.OE,{status:e.status,statusTooltip:e.statusTooltip})})}),(0,r.jsx)(h.pj,{children:(0,r.jsx)(o(),{href:"/clusters/".concat(e.isHistorical?e.cluster_hash:e.cluster||e.name),className:"text-blue-600",children:e.cluster||e.name})}),(0,r.jsx)(h.pj,{children:(0,r.jsx)(L.H,{username:e.user,userHash:e.user_hash})}),(0,r.jsx)(h.pj,{children:(0,r.jsx)(o(),{href:"/workspaces",className:"text-gray-700 hover:text-blue-600 hover:underline",children:e.workspace||"default"})}),(0,r.jsx)(h.pj,{children:(0,r.jsx)(i.Md,{content:e.full_infra||e.infra,className:"text-sm text-muted-foreground",children:(0,r.jsxs)("span",{children:[(0,r.jsx)(o(),{href:"/infra",className:"text-blue-600 hover:underline",children:e.cloud}),e.infra.includes("(")&&(0,r.jsx)("span",{children:" "+e.infra.substring(e.infra.indexOf("("))})]})})}),(0,r.jsx)(h.pj,{children:(0,r.jsx)(i.Md,{content:e.resources_str_full||e.resources_str,className:"text-sm text-muted-foreground",children:(0,r.jsx)("span",{children:e.resources_str})})}),(0,r.jsx)(h.pj,{children:(0,r.jsx)(i.Zg,{date:e.time})}),p&&(0,r.jsx)(h.pj,{children:_(e.duration)}),(0,r.jsx)(h.pj,{children:e.isHistorical?"-":R(e.autostop,e.to_down)}),(0,r.jsx)(h.pj,{className:"text-left md:sticky md:right-0 md:bg-white",children:!e.isHistorical&&(0,r.jsx)(F,{cluster:e.cluster,status:e.status,onOpenSSHModal:j,onOpenVSCodeModal:v})})]},s)):(0,r.jsx)(h.SC,{children:(0,r.jsx)(h.pj,{colSpan:9,className:"text-center py-6 text-gray-500",children:p?"No clusters found":"No active clusters"})})})]})})}),w.length>0&&(0,r.jsx)("div",{className:"flex justify-end items-center py-2 px-4 text-sm text-gray-700",children:(0,r.jsxs)("div",{className:"flex items-center space-x-4",children:[(0,r.jsxs)("div",{className:"flex items-center",children:[(0,r.jsx)("span",{className:"mr-2",children:"Rows per page:"}),(0,r.jsxs)("div",{className:"relative inline-block",children:[(0,r.jsxs)("select",{value:W,onChange:e=>{V(parseInt(e.target.value,10)),H(1)},className:"py-1 pl-2 pr-6 appearance-none outline-none cursor-pointer border-none bg-transparent",style:{minWidth:"40px"},children:[(0,r.jsx)("option",{value:10,children:"10"}),(0,r.jsx)("option",{value:30,children:"30"}),(0,r.jsx)("option",{value:50,children:"50"}),(0,r.jsx)("option",{value:100,children:"100"}),(0,r.jsx)("option",{value:200,children:"200"})]}),(0,r.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",className:"h-4 w-4 text-gray-500 absolute right-0 top-1/2 transform -translate-y-1/2 pointer-events-none",fill:"none",viewBox:"0 0 24 24",stroke:"currentColor",children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M19 9l-7 7-7-7"})})]})]}),(0,r.jsx)("div",{children:"".concat(T+1," - ").concat(Math.min(X,A.length)," of ").concat(A.length)}),(0,r.jsxs)("div",{className:"flex items-center space-x-2",children:[(0,r.jsx)(u.z,{variant:"ghost",size:"icon",onClick:()=>{H(e=>Math.max(e-1,1))},disabled:1===q,className:"text-gray-500 h-8 w-8 p-0",children:(0,r.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"chevron-left",children:(0,r.jsx)("path",{d:"M15 18l-6-6 6-6"})})}),(0,r.jsx)(u.z,{variant:"ghost",size:"icon",onClick:()=>{H(e=>Math.min(e+1,Q))},disabled:q===Q||0===Q,className:"text-gray-500 h-8 w-8 p-0",children:(0,r.jsx)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"chevron-right",children:(0,r.jsx)("path",{d:"M9 18l6-6-6-6"})})})]})]})})]})}let Z=(e,s)=>{s&&s(e)},q=(e,s)=>{s?s(e):window.open("ssh://".concat(e))},H=e=>"RUNNING"===e?["connect","VSCode"]:[],W={connect:(0,r.jsx)(v,{className:"w-4 h-4 text-gray-500 inline-block"}),VSCode:(0,r.jsx)(g,{className:"w-4 h-4 text-gray-500 inline-block"})};function F(e){let{withLabel:s=!1,cluster:t,status:l,onOpenSSHModal:a,onOpenVSCodeModal:n}=e,c=H(l),o=(0,w.X)(),u=e=>{switch(e){case"connect":q(t,a);break;case"VSCode":Z(t,n);break;default:return}};return(0,r.jsx)(r.Fragment,{children:(0,r.jsx)("div",{className:"flex items-center space-x-4",children:Object.entries(W).map(e=>{let t,l,[a,n]=e;switch(a){case"connect":t="Connect",l="Connect with SSH";break;case"VSCode":t="VSCode",l="Open in VS Code"}return(s||(t=""),c.includes(a))?(0,r.jsx)(i.WH,{content:l,className:"capitalize text-sm text-muted-foreground",children:(0,r.jsxs)("button",{onClick:()=>u(a),className:"text-sky-blue hover:text-sky-blue-bright font-medium inline-flex items-center",children:[n,!o&&(0,r.jsx)("span",{className:"ml-1.5",children:t})]})},a):(0,r.jsx)(i.WH,{content:l,className:"capitalize text-sm text-muted-foreground",children:(0,r.jsxs)("span",{className:"opacity-30 flex items-center cursor-not-allowed text-sm",title:a,children:[n,!o&&(0,r.jsx)("span",{className:"ml-1.5",children:t})]})},a)})})})}let V=e=>{let{propertyList:s=[],valueList:t,setFilters:a,updateURLParams:n,placeholder:i="Filter clusters",filters:c=[]}=e,o=(0,l.useRef)(null),u=(0,l.useRef)(null),[d,h]=(0,l.useState)(!1),[x,p]=(0,l.useState)(""),[m,f]=(0,l.useState)("status"),[j,v]=(0,l.useState)([]);(0,l.useEffect)(()=>{let e=e=>{u.current&&!u.current.contains(e.target)&&o.current&&!o.current.contains(e.target)&&h(!1)};return document.addEventListener("mousedown",e),()=>{document.removeEventListener("mousedown",e)}},[]),(0,l.useEffect)(()=>{let e=[],s=m||"";if(s.length>1){s=m[0].toUpperCase();for(let e=1;e<m.length;e++)s+=m[e]}let r=c.filter(e=>e.property===s).map(e=>e.value);if(t&&"object"==typeof t)switch(m){case"status":e=t.status.filter(e=>!r.find(s=>s===e))||[];break;case"user":e=t.user.filter(e=>!r.find(s=>s===e))||[];break;case"cluster":e=t.cluster.filter(e=>!r.find(s=>s===e))||[];break;case"workspace":e=t.workspace.filter(e=>!r.find(s=>s===e))||[];break;case"infra":e=t.infra.filter(e=>!r.find(s=>s===e))||[];break;case"labels":e=t.labels.filter(e=>!r.find(s=>s===e))||[]}""!==x.trim()&&(e=e.filter(e=>e&&e.toString().toLowerCase().includes(x.toLowerCase()))),v(e)},[m,t,x,c]);let g=e=>{let t=s.find(s=>s.value===e);return t?t.label:e},y=e=>{a(s=>{let t=[...s,{property:g(m),operator:":",value:e}];return n(t),t}),h(!1),p(""),o.current.focus()};return(0,r.jsxs)("div",{className:"flex flex-row border border-gray-300 rounded-md overflow-visible",children:[(0,r.jsx)("div",{className:"border-r border-gray-300 flex-shrink-0",children:(0,r.jsxs)(N.Ph,{onValueChange:f,value:m,children:[(0,r.jsx)(N.i4,{"aria-label":"Filter Property",className:"focus:ring-0 focus:ring-offset-0 border-none rounded-l-md rounded-r-none w-20 sm:w-24 md:w-32 h-8 text-xs sm:text-sm",children:(0,r.jsx)(N.ki,{placeholder:"Status"})}),(0,r.jsx)(N.Bw,{children:s.map((e,s)=>(0,r.jsx)(N.Ql,{value:e.value,children:e.label},"property-item-".concat(s)))})]})}),(0,r.jsxs)("div",{className:"relative flex-1",children:[(0,r.jsx)("input",{type:"text",ref:o,placeholder:i,value:x,onChange:e=>{p(e.target.value),d||h(!0)},onFocus:()=>{h(!0)},onKeyDown:e=>{"Enter"===e.key&&""!==x.trim()?(a(e=>{let s=[...e,{property:g(m),operator:":",value:x}];return n(s),s}),p(""),h(!1)):"Escape"===e.key&&(h(!1),o.current.blur())},className:"h-8 w-full sm:w-96 px-3 pr-8 text-sm border-none rounded-l-none rounded-r-md focus:ring-0 focus:outline-none",autoComplete:"off"}),x&&(0,r.jsx)("button",{onClick:()=>{p(""),h(!1)},className:"absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600",title:"Clear filter",tabIndex:-1,children:(0,r.jsx)("svg",{className:"h-4 w-4",fill:"none",stroke:"currentColor",viewBox:"0 0 24 24",children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:2,d:"M6 18L18 6M6 6l12 12"})})}),d&&j.length>0&&(0,r.jsx)("div",{ref:u,className:"absolute z-50 mt-1 w-full bg-white border border-gray-200 rounded-md shadow-lg max-h-60 overflow-y-auto",style:{zIndex:9999},children:j.map((e,s)=>(0,r.jsx)("div",{className:"px-3 py-2 cursor-pointer hover:bg-gray-50 text-sm ".concat(s!==j.length-1?"border-b border-gray-100":""),onClick:()=>y(e),children:(0,r.jsx)("span",{className:"text-sm text-gray-700",children:e})},"".concat(e,"-").concat(s)))})]})]})},D=e=>{let{filters:s=[],setFilters:t,updateURLParams:l}=e,a=e=>{t(s=>{let t=s.filter((s,t)=>t!==e);return l(t),t})};return(0,r.jsx)(r.Fragment,{children:(0,r.jsx)("div",{className:"flex items-center gap-4 py-2 px-2",children:(0,r.jsxs)("div",{className:"flex flex-wrap items-content gap-2",children:[s.map((e,s)=>(0,r.jsx)(z,{filter:e,onRemove:()=>a(s)},"filteritem-".concat(s))),s.length>0&&(0,r.jsx)(r.Fragment,{children:(0,r.jsx)("button",{onClick:()=>{l([]),t([])},className:"rounded-full px-4 py-1 text-sm text-gray-700 bg-gray-200 hover:bg-gray-300",children:"Clear filters"})})]})})})},z=e=>{let{filter:s,onRemove:t}=e;return(0,r.jsx)(r.Fragment,{children:(0,r.jsxs)("div",{className:"flex items-center text-blue-600 bg-blue-100 px-1 py-1 rounded-full text-sm",children:[(0,r.jsxs)("div",{className:"flex items-center gap-1 px-2",children:[(0,r.jsx)("span",{children:"".concat(s.property," ")}),(0,r.jsx)("span",{children:"".concat(s.operator," ")}),(0,r.jsx)("span",{children:" ".concat(s.value)})]}),(0,r.jsx)("button",{onClick:()=>t(),className:"p-0.5 ml-1 transform text-gray-400 hover:text-gray-600 bg-blue-500 hover:bg-blue-600 rounded-full flex flex-col items-center",title:"Clear filter",children:(0,r.jsx)("svg",{className:"h-3 w-3",fill:"none",stroke:"white",viewBox:"0 0 24 24",children:(0,r.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",strokeWidth:5,d:"M6 18L18 6M6 6l12 12"})})})]})})}},12003:function(e,s,t){t.d(s,{j:function(){return n}});var r=t(90512);let l=e=>"boolean"==typeof e?`${e}`:0===e?"0":e,a=r.W,n=(e,s)=>t=>{var r;if((null==s?void 0:s.variants)==null)return a(e,null==t?void 0:t.class,null==t?void 0:t.className);let{variants:n,defaultVariants:i}=s,c=Object.keys(n).map(e=>{let s=null==t?void 0:t[e],r=null==i?void 0:i[e];if(null===s)return null;let a=l(s)||l(r);return n[e][a]}),o=t&&Object.entries(t).reduce((e,s)=>{let[t,r]=s;return void 0===r||(e[t]=r),e},{});return a(e,c,null==s?void 0:null===(r=s.compoundVariants)||void 0===r?void 0:r.reduce((e,s)=>{let{class:t,className:r,...l}=s;return Object.entries(l).every(e=>{let[s,t]=e;return Array.isArray(t)?t.includes({...i,...o}[s]):({...i,...o})[s]===t})?[...e,t,r]:e},[]),null==t?void 0:t.class,null==t?void 0:t.className)}}}]);
|