skypilot-nightly 1.0.0.dev20250527__py3-none-any.whl → 1.0.0.dev20250529__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 +2 -2
- sky/adaptors/kubernetes.py +13 -1
- sky/backends/cloud_vm_ray_backend.py +2 -2
- sky/check.py +4 -1
- sky/cli.py +13 -3
- sky/client/cli.py +13 -3
- sky/client/oauth.py +82 -0
- sky/client/sdk.py +60 -10
- sky/clouds/kubernetes.py +2 -2
- sky/clouds/service_catalog/data_fetchers/fetch_gcp.py +3 -3
- sky/dashboard/out/404.html +1 -1
- sky/dashboard/out/_next/static/HvNkg7hqKM1p0ptAcdDcF/_buildManifest.js +1 -0
- sky/dashboard/out/_next/static/chunks/121-8f55ee3fa6301784.js +20 -0
- sky/dashboard/out/_next/static/chunks/{573-82bd40a37af834f1.js → 173-7db8607cefc20f70.js} +5 -5
- sky/dashboard/out/_next/static/chunks/236-90e5498a5b00ec29.js +6 -0
- sky/dashboard/out/_next/static/chunks/293-351268365226d251.js +1 -0
- sky/dashboard/out/_next/static/chunks/303-2c7b0f7af571710b.js +6 -0
- sky/dashboard/out/_next/static/chunks/470-4d003c441839094d.js +1 -0
- sky/dashboard/out/_next/static/chunks/578-9146658cead92981.js +6 -0
- sky/dashboard/out/_next/static/chunks/843-256ec920f6d5f41f.js +11 -0
- sky/dashboard/out/_next/static/chunks/856-59a1760784c9e770.js +1 -0
- sky/dashboard/out/_next/static/chunks/973-1a09cac61cfcc1e1.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-159bffb2fa34ed54.js +6 -0
- sky/dashboard/out/_next/static/chunks/pages/clusters/{[cluster]-e23fcddf60578a0d.js → [cluster]-9506c00257d10dbd.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/{clusters-8afda8efa5b74997.js → clusters-943992b84fd6f4ee.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/config-7c48919fe030bc43.js +6 -0
- sky/dashboard/out/_next/static/chunks/pages/infra/[context]-909f1ceb0fcf1b99.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/infra-d4c6875c88771e17.js +1 -0
- sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-6b80e9e0c6aa16a1.js +6 -0
- sky/dashboard/out/_next/static/chunks/pages/{jobs-ff7e8e377d02b651.js → jobs-a4efc09e61988f8d.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/users-b2634885d67c49a6.js +6 -0
- sky/dashboard/out/_next/static/chunks/pages/workspace/{new-63763ffa3edb4508.js → new-579b3203c7c19d84.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-3ede7a13caf23375.js → [name]-9388e38fac73ee8f.js} +1 -1
- sky/dashboard/out/_next/static/chunks/pages/workspaces-610c49ae3619ee85.js +1 -0
- sky/dashboard/out/_next/static/css/ffd1cd601648c303.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 -0
- sky/dashboard/out/infra.html +1 -1
- sky/dashboard/out/jobs/[job].html +1 -1
- sky/dashboard/out/jobs.html +1 -1
- sky/dashboard/out/users.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/exceptions.py +1 -1
- sky/global_user_state.py +181 -134
- sky/jobs/client/sdk.py +1 -0
- sky/jobs/constants.py +2 -0
- sky/jobs/controller.py +3 -5
- sky/jobs/recovery_strategy.py +148 -102
- sky/jobs/scheduler.py +23 -8
- sky/jobs/server/core.py +16 -0
- sky/jobs/state.py +130 -35
- sky/jobs/utils.py +30 -4
- sky/provision/kubernetes/utils.py +4 -4
- sky/resources.py +16 -1
- sky/server/common.py +6 -2
- sky/server/html/token_page.html +32 -6
- sky/server/server.py +9 -6
- sky/setup_files/dependencies.py +8 -1
- sky/skylet/constants.py +5 -1
- sky/task.py +26 -0
- sky/templates/jobs-controller.yaml.j2 +2 -1
- sky/utils/db_utils.py +34 -46
- sky/utils/schemas.py +12 -0
- sky/utils/subprocess_utils.py +2 -3
- {skypilot_nightly-1.0.0.dev20250527.dist-info → skypilot_nightly-1.0.0.dev20250529.dist-info}/METADATA +4 -1
- {skypilot_nightly-1.0.0.dev20250527.dist-info → skypilot_nightly-1.0.0.dev20250529.dist-info}/RECORD +78 -73
- sky/dashboard/out/_next/static/D5bjIfl4Ob3SV3LJz3CO0/_buildManifest.js +0 -1
- sky/dashboard/out/_next/static/chunks/236-e220ba0c35bf089e.js +0 -6
- sky/dashboard/out/_next/static/chunks/470-1d784f5c8750744a.js +0 -1
- sky/dashboard/out/_next/static/chunks/488-50d843fdb5396d32.js +0 -15
- sky/dashboard/out/_next/static/chunks/578-24f35aa98d38d638.js +0 -6
- sky/dashboard/out/_next/static/chunks/627-31b701e69f52db0c.js +0 -1
- sky/dashboard/out/_next/static/chunks/843-e35d71cf1c7f706e.js +0 -11
- sky/dashboard/out/_next/static/chunks/990-f85643b521f7ca65.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-339b59921ccfe266.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/config-72b8c6c2edfd0e39.js +0 -6
- sky/dashboard/out/_next/static/chunks/pages/infra-1521baab6992916b.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/jobs/[job]-4d913940b4fa6f5a.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/users-9900af52acf8648d.js +0 -1
- sky/dashboard/out/_next/static/chunks/pages/workspaces-72330c4d0fc9a4a2.js +0 -1
- sky/dashboard/out/_next/static/css/6a1c0d711a4bdaf1.css +0 -3
- /sky/dashboard/out/_next/static/{D5bjIfl4Ob3SV3LJz3CO0 → HvNkg7hqKM1p0ptAcdDcF}/_ssgManifest.js +0 -0
- /sky/dashboard/out/_next/static/chunks/pages/{_app-3985f074c163a856.js → _app-a631df412d8172de.js} +0 -0
- {skypilot_nightly-1.0.0.dev20250527.dist-info → skypilot_nightly-1.0.0.dev20250529.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20250527.dist-info → skypilot_nightly-1.0.0.dev20250529.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250527.dist-info → skypilot_nightly-1.0.0.dev20250529.dist-info}/licenses/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250527.dist-info → skypilot_nightly-1.0.0.dev20250529.dist-info}/top_level.txt +0 -0
sky/__init__.py
CHANGED
@@ -5,7 +5,7 @@ from typing import Optional
|
|
5
5
|
import urllib.request
|
6
6
|
|
7
7
|
# Replaced with the current commit when building the wheels.
|
8
|
-
_SKYPILOT_COMMIT_SHA = '
|
8
|
+
_SKYPILOT_COMMIT_SHA = 'f3edb2141cf7bfea30c552e2812c14f56d7149ab'
|
9
9
|
|
10
10
|
|
11
11
|
def _get_git_commit():
|
@@ -35,7 +35,7 @@ def _get_git_commit():
|
|
35
35
|
|
36
36
|
|
37
37
|
__commit__ = _get_git_commit()
|
38
|
-
__version__ = '1.0.0.
|
38
|
+
__version__ = '1.0.0.dev20250529'
|
39
39
|
__root_dir__ = os.path.dirname(os.path.abspath(__file__))
|
40
40
|
|
41
41
|
|
sky/adaptors/kubernetes.py
CHANGED
@@ -66,12 +66,20 @@ def _api_logging_decorator(logger_src: str, level: int):
|
|
66
66
|
return decorated_api
|
67
67
|
|
68
68
|
|
69
|
+
def _get_config_file() -> str:
|
70
|
+
# Kubernetes load the kubeconfig from the KUBECONFIG env var on
|
71
|
+
# package initialization. So we have to reload the KUBECOFNIG env var
|
72
|
+
# everytime in case the KUBECONFIG env var is changed.
|
73
|
+
return os.environ.get('KUBECONFIG', '~/.kube/config')
|
74
|
+
|
75
|
+
|
69
76
|
def _load_config(context: Optional[str] = None):
|
70
77
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
71
78
|
|
72
79
|
def _load_config_from_kubeconfig(context: Optional[str] = None):
|
73
80
|
try:
|
74
|
-
kubernetes.config.load_kube_config(
|
81
|
+
kubernetes.config.load_kube_config(config_file=_get_config_file(),
|
82
|
+
context=context)
|
75
83
|
except kubernetes.config.config_exception.ConfigException as e:
|
76
84
|
suffix = common_utils.format_exception(e, use_bracket=True)
|
77
85
|
context_name = '(current-context)' if context is None else context
|
@@ -139,6 +147,10 @@ def _load_config(context: Optional[str] = None):
|
|
139
147
|
_load_config_from_kubeconfig(context)
|
140
148
|
|
141
149
|
|
150
|
+
def list_kube_config_contexts():
|
151
|
+
return kubernetes.config.list_kube_config_contexts(_get_config_file())
|
152
|
+
|
153
|
+
|
142
154
|
@_api_logging_decorator('urllib3', logging.ERROR)
|
143
155
|
@annotations.lru_cache(scope='request')
|
144
156
|
def core_api(context: Optional[str] = None):
|
@@ -1727,12 +1727,12 @@ class RetryingVmProvisioner(object):
|
|
1727
1727
|
f'{requested_resources}. ')
|
1728
1728
|
elif to_provision.region is not None:
|
1729
1729
|
# For public clouds, provision.region is always set.
|
1730
|
-
if
|
1730
|
+
if clouds.SSH().is_same_cloud(to_provision.cloud):
|
1731
1731
|
message = ('Failed to acquire resources in SSH Node Pool '
|
1732
1732
|
f'({to_provision.region.lstrip("ssh-")}) for '
|
1733
1733
|
f'{requested_resources}. The SSH Node Pool may not '
|
1734
1734
|
'have enough resources.')
|
1735
|
-
elif
|
1735
|
+
elif clouds.Kubernetes().is_same_cloud(to_provision.cloud):
|
1736
1736
|
message = ('Failed to acquire resources in context '
|
1737
1737
|
f'{to_provision.region} for {requested_resources}. ')
|
1738
1738
|
else:
|
sky/check.py
CHANGED
@@ -143,12 +143,15 @@ def check_capabilities(
|
|
143
143
|
combinations = list(itertools.product(clouds_to_check, capabilities))
|
144
144
|
|
145
145
|
cloud2ctx2text: Dict[str, Dict[str, str]] = {}
|
146
|
+
if not config_allowed_cloud_names:
|
147
|
+
for capability in capabilities:
|
148
|
+
global_user_state.set_enabled_clouds([], capability,
|
149
|
+
current_workspace_name)
|
146
150
|
if not combinations:
|
147
151
|
echo(
|
148
152
|
_summary_message(enabled_clouds, cloud2ctx2text,
|
149
153
|
current_workspace_name, hide_workspace_str,
|
150
154
|
disallowed_cloud_names))
|
151
|
-
|
152
155
|
return {}
|
153
156
|
|
154
157
|
workspace_str = f' for workspace: {current_workspace_name!r}'
|
sky/cli.py
CHANGED
@@ -862,6 +862,7 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
|
|
862
862
|
field_to_ignore: Optional[List[str]] = None,
|
863
863
|
# job launch specific
|
864
864
|
job_recovery: Optional[str] = None,
|
865
|
+
priority: Optional[int] = None,
|
865
866
|
config_override: Optional[Dict[str, Any]] = None,
|
866
867
|
) -> Union[sky.Task, sky.Dag]:
|
867
868
|
"""Creates a task or a dag from an entrypoint with overrides.
|
@@ -939,6 +940,9 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
|
|
939
940
|
task.num_nodes = num_nodes
|
940
941
|
if name is not None:
|
941
942
|
task.name = name
|
943
|
+
# job launch specific.
|
944
|
+
if priority is not None:
|
945
|
+
task.set_job_priority(priority)
|
942
946
|
return task
|
943
947
|
|
944
948
|
|
@@ -4170,6 +4174,12 @@ def jobs():
|
|
4170
4174
|
default=None,
|
4171
4175
|
type=str,
|
4172
4176
|
help='Recovery strategy to use for managed jobs.')
|
4177
|
+
@click.option('--priority',
|
4178
|
+
type=click.IntRange(0, 1000),
|
4179
|
+
default=None,
|
4180
|
+
show_default=True,
|
4181
|
+
help=('Job priority from 0 to 1000. A lower number is higher '
|
4182
|
+
'priority. Default is 500.'))
|
4173
4183
|
@click.option(
|
4174
4184
|
'--detach-run',
|
4175
4185
|
'-d',
|
@@ -4207,6 +4217,7 @@ def jobs_launch(
|
|
4207
4217
|
disk_size: Optional[int],
|
4208
4218
|
disk_tier: Optional[str],
|
4209
4219
|
ports: Tuple[str],
|
4220
|
+
priority: Optional[int],
|
4210
4221
|
detach_run: bool,
|
4211
4222
|
yes: bool,
|
4212
4223
|
async_call: bool,
|
@@ -4253,6 +4264,7 @@ def jobs_launch(
|
|
4253
4264
|
disk_tier=disk_tier,
|
4254
4265
|
ports=ports,
|
4255
4266
|
job_recovery=job_recovery,
|
4267
|
+
priority=priority,
|
4256
4268
|
config_override=config_override,
|
4257
4269
|
)
|
4258
4270
|
|
@@ -4335,8 +4347,6 @@ def jobs_queue(verbose: bool, refresh: bool, skip_finished: bool,
|
|
4335
4347
|
- ``PENDING``: Job is waiting for a free slot on the jobs controller to be
|
4336
4348
|
accepted.
|
4337
4349
|
|
4338
|
-
- ``SUBMITTED``: Job is submitted to and accepted by the jobs controller.
|
4339
|
-
|
4340
4350
|
- ``STARTING``: Job is starting (provisioning a cluster for the job).
|
4341
4351
|
|
4342
4352
|
- ``RUNNING``: Job is running.
|
@@ -4553,7 +4563,7 @@ def jobs_logs(name: Optional[str], job_id: Optional[int], follow: bool,
|
|
4553
4563
|
@usage_lib.entrypoint
|
4554
4564
|
def jobs_dashboard():
|
4555
4565
|
"""Opens a dashboard for managed jobs."""
|
4556
|
-
|
4566
|
+
sdk.dashboard(starting_page='jobs')
|
4557
4567
|
|
4558
4568
|
|
4559
4569
|
@cli.command(cls=_DocumentedCodeCommand)
|
sky/client/cli.py
CHANGED
@@ -862,6 +862,7 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
|
|
862
862
|
field_to_ignore: Optional[List[str]] = None,
|
863
863
|
# job launch specific
|
864
864
|
job_recovery: Optional[str] = None,
|
865
|
+
priority: Optional[int] = None,
|
865
866
|
config_override: Optional[Dict[str, Any]] = None,
|
866
867
|
) -> Union[sky.Task, sky.Dag]:
|
867
868
|
"""Creates a task or a dag from an entrypoint with overrides.
|
@@ -939,6 +940,9 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
|
|
939
940
|
task.num_nodes = num_nodes
|
940
941
|
if name is not None:
|
941
942
|
task.name = name
|
943
|
+
# job launch specific.
|
944
|
+
if priority is not None:
|
945
|
+
task.set_job_priority(priority)
|
942
946
|
return task
|
943
947
|
|
944
948
|
|
@@ -4170,6 +4174,12 @@ def jobs():
|
|
4170
4174
|
default=None,
|
4171
4175
|
type=str,
|
4172
4176
|
help='Recovery strategy to use for managed jobs.')
|
4177
|
+
@click.option('--priority',
|
4178
|
+
type=click.IntRange(0, 1000),
|
4179
|
+
default=None,
|
4180
|
+
show_default=True,
|
4181
|
+
help=('Job priority from 0 to 1000. A lower number is higher '
|
4182
|
+
'priority. Default is 500.'))
|
4173
4183
|
@click.option(
|
4174
4184
|
'--detach-run',
|
4175
4185
|
'-d',
|
@@ -4207,6 +4217,7 @@ def jobs_launch(
|
|
4207
4217
|
disk_size: Optional[int],
|
4208
4218
|
disk_tier: Optional[str],
|
4209
4219
|
ports: Tuple[str],
|
4220
|
+
priority: Optional[int],
|
4210
4221
|
detach_run: bool,
|
4211
4222
|
yes: bool,
|
4212
4223
|
async_call: bool,
|
@@ -4253,6 +4264,7 @@ def jobs_launch(
|
|
4253
4264
|
disk_tier=disk_tier,
|
4254
4265
|
ports=ports,
|
4255
4266
|
job_recovery=job_recovery,
|
4267
|
+
priority=priority,
|
4256
4268
|
config_override=config_override,
|
4257
4269
|
)
|
4258
4270
|
|
@@ -4335,8 +4347,6 @@ def jobs_queue(verbose: bool, refresh: bool, skip_finished: bool,
|
|
4335
4347
|
- ``PENDING``: Job is waiting for a free slot on the jobs controller to be
|
4336
4348
|
accepted.
|
4337
4349
|
|
4338
|
-
- ``SUBMITTED``: Job is submitted to and accepted by the jobs controller.
|
4339
|
-
|
4340
4350
|
- ``STARTING``: Job is starting (provisioning a cluster for the job).
|
4341
4351
|
|
4342
4352
|
- ``RUNNING``: Job is running.
|
@@ -4553,7 +4563,7 @@ def jobs_logs(name: Optional[str], job_id: Optional[int], follow: bool,
|
|
4553
4563
|
@usage_lib.entrypoint
|
4554
4564
|
def jobs_dashboard():
|
4555
4565
|
"""Opens a dashboard for managed jobs."""
|
4556
|
-
|
4566
|
+
sdk.dashboard(starting_page='jobs')
|
4557
4567
|
|
4558
4568
|
|
4559
4569
|
@cli.command(cls=_DocumentedCodeCommand)
|
sky/client/oauth.py
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
"""Client-side OAuth module."""
|
2
|
+
from http.server import BaseHTTPRequestHandler
|
3
|
+
from http.server import HTTPServer
|
4
|
+
import threading
|
5
|
+
import time
|
6
|
+
from typing import Dict, Optional
|
7
|
+
|
8
|
+
AUTH_TIMEOUT = 300 # 5 minutes
|
9
|
+
|
10
|
+
|
11
|
+
class _AuthCallbackHandler(BaseHTTPRequestHandler):
|
12
|
+
"""HTTP request handler for OAuth callback."""
|
13
|
+
|
14
|
+
def __init__(self, token_container: Dict[str, Optional[str]],
|
15
|
+
remote_endpoint: str, *args, **kwargs):
|
16
|
+
self.token_container = token_container
|
17
|
+
self.remote_endpoint = remote_endpoint
|
18
|
+
super().__init__(*args, **kwargs)
|
19
|
+
|
20
|
+
def do_POST(self): # pylint: disable=invalid-name
|
21
|
+
"""Handle POST request for OAuth callback."""
|
22
|
+
data = self.rfile.read(int(self.headers['Content-Length']))
|
23
|
+
|
24
|
+
if data:
|
25
|
+
token = data.decode('utf-8')
|
26
|
+
self.token_container['token'] = token
|
27
|
+
|
28
|
+
# Send success response
|
29
|
+
self.send_response(200)
|
30
|
+
self.send_header('Content-type', 'text/html')
|
31
|
+
self.send_header('Access-Control-Allow-Origin',
|
32
|
+
self.remote_endpoint)
|
33
|
+
self.end_headers()
|
34
|
+
else:
|
35
|
+
# Send error response
|
36
|
+
self.send_response(400)
|
37
|
+
self.send_header('Content-type', 'text/html')
|
38
|
+
self.send_header('Access-Control-Allow-Origin',
|
39
|
+
self.remote_endpoint)
|
40
|
+
self.end_headers()
|
41
|
+
|
42
|
+
def log_message(self, *args): # pylint: disable=unused-argument
|
43
|
+
"""Suppress default HTTP server logging."""
|
44
|
+
pass
|
45
|
+
|
46
|
+
|
47
|
+
def start_local_auth_server(port: int,
|
48
|
+
token_store: Dict[str, Optional[str]],
|
49
|
+
remote_endpoint: str,
|
50
|
+
timeout: int = AUTH_TIMEOUT) -> HTTPServer:
|
51
|
+
"""Start a local HTTP server to handle OAuth callback.
|
52
|
+
|
53
|
+
Args:
|
54
|
+
port: Port to bind the server to.
|
55
|
+
token_container: Dict to store the received token.
|
56
|
+
remote_endpoint: The endpoint of the SkyPilot API server that will send
|
57
|
+
the token, needed for CORS.
|
58
|
+
timeout: Timeout in seconds to wait for the callback.
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
The HTTP server instance.
|
62
|
+
"""
|
63
|
+
|
64
|
+
def handler_factory(*args, **kwargs):
|
65
|
+
return _AuthCallbackHandler(token_store, remote_endpoint, *args,
|
66
|
+
**kwargs)
|
67
|
+
|
68
|
+
server = HTTPServer(('localhost', port), handler_factory)
|
69
|
+
server.timeout = timeout
|
70
|
+
|
71
|
+
def serve_until_token():
|
72
|
+
"""Serve requests until token is received or timeout."""
|
73
|
+
start_time = time.time()
|
74
|
+
while (token_store['token'] is None and
|
75
|
+
time.time() - start_time < timeout):
|
76
|
+
server.handle_request()
|
77
|
+
|
78
|
+
# Start server in a separate thread
|
79
|
+
server_thread = threading.Thread(target=serve_until_token, daemon=True)
|
80
|
+
server_thread.start()
|
81
|
+
|
82
|
+
return server
|
sky/client/sdk.py
CHANGED
@@ -36,6 +36,7 @@ from sky import sky_logging
|
|
36
36
|
from sky import skypilot_config
|
37
37
|
from sky.adaptors import common as adaptors_common
|
38
38
|
from sky.client import common as client_common
|
39
|
+
from sky.client import oauth as oauth_lib
|
39
40
|
from sky.server import common as server_common
|
40
41
|
from sky.server.requests import payloads
|
41
42
|
from sky.server.requests import requests as requests_lib
|
@@ -341,10 +342,11 @@ def validate(
|
|
341
342
|
@usage_lib.entrypoint
|
342
343
|
@server_common.check_server_healthy_or_start
|
343
344
|
@annotations.client_api
|
344
|
-
def dashboard() -> None:
|
345
|
+
def dashboard(starting_page: Optional[str] = None) -> None:
|
345
346
|
"""Starts the dashboard for SkyPilot."""
|
346
347
|
api_server_url = server_common.get_server_url()
|
347
|
-
url = server_common.get_dashboard_url(api_server_url
|
348
|
+
url = server_common.get_dashboard_url(api_server_url,
|
349
|
+
starting_page=starting_page)
|
348
350
|
logger.info(f'Opening dashboard in browser: {url}')
|
349
351
|
webbrowser.open(url)
|
350
352
|
|
@@ -1908,6 +1910,7 @@ def api_login(endpoint: Optional[str] = None, get_token: bool = False) -> None:
|
|
1908
1910
|
Args:
|
1909
1911
|
endpoint: The endpoint of the SkyPilot API server, e.g.,
|
1910
1912
|
http://1.2.3.4:46580 or https://skypilot.mydomain.com.
|
1913
|
+
get_token: Whether to force getting a new token even if not needed.
|
1911
1914
|
|
1912
1915
|
Returns:
|
1913
1916
|
None
|
@@ -1926,14 +1929,60 @@ def api_login(endpoint: Optional[str] = None, get_token: bool = False) -> None:
|
|
1926
1929
|
server_status = server_common.check_server_healthy(endpoint)
|
1927
1930
|
if server_status == server_common.ApiServerStatus.NEEDS_AUTH or get_token:
|
1928
1931
|
# We detected an auth proxy, so go through the auth proxy cookie flow.
|
1929
|
-
|
1930
|
-
|
1931
|
-
|
1932
|
-
|
1933
|
-
|
1934
|
-
|
1935
|
-
|
1936
|
-
|
1932
|
+
token: Optional[str] = None
|
1933
|
+
server: Optional[oauth_lib.HTTPServer] = None
|
1934
|
+
try:
|
1935
|
+
callback_port = common_utils.find_free_port(8000)
|
1936
|
+
|
1937
|
+
token_container: Dict[str, Optional[str]] = {'token': None}
|
1938
|
+
logger.debug('Starting local authentication server...')
|
1939
|
+
server = oauth_lib.start_local_auth_server(callback_port,
|
1940
|
+
token_container,
|
1941
|
+
endpoint)
|
1942
|
+
|
1943
|
+
token_url = (f'{endpoint}/token?local_port={callback_port}')
|
1944
|
+
if webbrowser.open(token_url):
|
1945
|
+
click.echo(f'{colorama.Fore.GREEN}A web browser has been '
|
1946
|
+
f'opened at {token_url}. Please continue the login '
|
1947
|
+
f'in the web browser.{colorama.Style.RESET_ALL}\n'
|
1948
|
+
f'{colorama.Style.DIM}To manually copy the token, '
|
1949
|
+
f'press ctrl+c.{colorama.Style.RESET_ALL}')
|
1950
|
+
else:
|
1951
|
+
raise ValueError('Failed to open browser.')
|
1952
|
+
|
1953
|
+
start_time = time.time()
|
1954
|
+
|
1955
|
+
while (token_container['token'] is None and
|
1956
|
+
time.time() - start_time < oauth_lib.AUTH_TIMEOUT):
|
1957
|
+
time.sleep(1)
|
1958
|
+
|
1959
|
+
if token_container['token'] is None:
|
1960
|
+
click.echo(f'{colorama.Fore.YELLOW}Authentication timed out '
|
1961
|
+
f'after {oauth_lib.AUTH_TIMEOUT} seconds.')
|
1962
|
+
else:
|
1963
|
+
token = token_container['token']
|
1964
|
+
|
1965
|
+
except (Exception, KeyboardInterrupt) as e: # pylint: disable=broad-except
|
1966
|
+
logger.debug(f'Automatic authentication failed: {e}, '
|
1967
|
+
'falling back to manual token entry.')
|
1968
|
+
if isinstance(e, KeyboardInterrupt):
|
1969
|
+
click.echo(f'\n{colorama.Style.DIM}Interrupted. Press ctrl+c '
|
1970
|
+
f'again to exit.{colorama.Style.RESET_ALL}')
|
1971
|
+
# Fall back to manual token entry
|
1972
|
+
token_url = f'{endpoint}/token'
|
1973
|
+
click.echo('Authentication is needed. Please visit this URL '
|
1974
|
+
f'to set up the token:{colorama.Style.BRIGHT}\n\n'
|
1975
|
+
f'{token_url}\n{colorama.Style.RESET_ALL}')
|
1976
|
+
token = click.prompt('Paste the token')
|
1977
|
+
finally:
|
1978
|
+
if server is not None:
|
1979
|
+
try:
|
1980
|
+
server.server_close()
|
1981
|
+
except Exception: # pylint: disable=broad-except
|
1982
|
+
pass
|
1983
|
+
if not token:
|
1984
|
+
with ux_utils.print_exception_no_traceback():
|
1985
|
+
raise ValueError('Authentication failed.')
|
1937
1986
|
|
1938
1987
|
# Parse the token.
|
1939
1988
|
# b64decode will ignore invalid characters, but does some length and
|
@@ -1959,6 +2008,7 @@ def api_login(endpoint: Optional[str] = None, get_token: bool = False) -> None:
|
|
1959
2008
|
else:
|
1960
2009
|
raise ValueError(f'Unsupported token version: {json_data.get("v")}')
|
1961
2010
|
|
2011
|
+
parsed_url = urlparse.urlparse(endpoint)
|
1962
2012
|
cookie_jar = cookiejar.MozillaCookieJar()
|
1963
2013
|
for (name, value) in cookie_dict.items():
|
1964
2014
|
# dict keys in JSON must be strings
|
sky/clouds/kubernetes.py
CHANGED
@@ -853,11 +853,11 @@ class Kubernetes(clouds.Cloud):
|
|
853
853
|
|
854
854
|
@classmethod
|
855
855
|
def get_user_identities(cls) -> Optional[List[List[str]]]:
|
856
|
-
k8s = kubernetes.kubernetes
|
857
856
|
identities = []
|
857
|
+
k8s = kubernetes.kubernetes
|
858
858
|
try:
|
859
859
|
all_contexts, current_context = (
|
860
|
-
|
860
|
+
kubernetes.list_kube_config_contexts())
|
861
861
|
except k8s.config.config_exception.ConfigException:
|
862
862
|
return None
|
863
863
|
# Add current context at the head of the list
|
@@ -179,7 +179,7 @@ TPU_V4_HOST_DF = pd.read_csv(
|
|
179
179
|
# TODO(woosuk): Make this more robust.
|
180
180
|
# Refer to: https://github.com/skypilot-org/skypilot/issues/1006
|
181
181
|
# Unsupported Series: 'f1', 'm2'
|
182
|
-
|
182
|
+
SERIES_TO_DESCRIPTION = {
|
183
183
|
'a2': 'A2 Instance',
|
184
184
|
'a3': 'A3 Instance',
|
185
185
|
# TODO(zhwu): GCP does not have A4 instance in SKUs API yet. We keep it here
|
@@ -338,7 +338,7 @@ def get_vm_df(skus: List[Dict[str, Any]], region_prefix: str) -> 'pd.DataFrame':
|
|
338
338
|
|
339
339
|
# Drop the unsupported series.
|
340
340
|
df = df[df['InstanceType'].str.startswith(
|
341
|
-
tuple(f'{series}-' for series in
|
341
|
+
tuple(f'{series}-' for series in SERIES_TO_DESCRIPTION))]
|
342
342
|
df = df[~df['AvailabilityZone'].str.startswith(tuple(TPU_V4_ZONES))]
|
343
343
|
|
344
344
|
# TODO(woosuk): Make this more efficient.
|
@@ -356,7 +356,7 @@ def get_vm_df(skus: List[Dict[str, Any]], region_prefix: str) -> 'pd.DataFrame':
|
|
356
356
|
|
357
357
|
# Check if the SKU is for the correct series.
|
358
358
|
description = sku['description']
|
359
|
-
if
|
359
|
+
if SERIES_TO_DESCRIPTION[series].lower() not in description.lower():
|
360
360
|
continue
|
361
361
|
# Special check for M1 instances.
|
362
362
|
if series == 'm1' and 'M3' in description:
|
sky/dashboard/out/404.html
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link rel="preload" href="/dashboard/_next/static/css/
|
1
|
+
<!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>404: This page could not be found</title><meta name="next-head-count" content="3"/><link rel="preload" href="/dashboard/_next/static/css/ffd1cd601648c303.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/ffd1cd601648c303.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-deda68c926e8d0bc.js" defer=""></script><script src="/dashboard/_next/static/chunks/framework-87d061ee6ed71b28.js" defer=""></script><script src="/dashboard/_next/static/chunks/main-e0e2335212e72357.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_app-a631df412d8172de.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_error-1be831200e60c5c0.js" defer=""></script><script src="/dashboard/_next/static/HvNkg7hqKM1p0ptAcdDcF/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/HvNkg7hqKM1p0ptAcdDcF/_ssgManifest.js" defer=""></script></head><body><div id="__next"><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">This page could not be found<!-- -->.</h2></div></div></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"HvNkg7hqKM1p0ptAcdDcF","assetPrefix":"/dashboard","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
|
@@ -0,0 +1 @@
|
|
1
|
+
self.__BUILD_MANIFEST=function(s,c,e,a,t,r,n,u,f,i,j,k){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},"/":["static/chunks/pages/index-6b0d9e5031b70c58.js"],"/_error":["static/chunks/pages/_error-1be831200e60c5c0.js"],"/clusters":[s,t,c,e,a,r,i,"static/chunks/pages/clusters-943992b84fd6f4ee.js"],"/clusters/[cluster]":[s,t,c,e,a,r,n,i,"static/chunks/pages/clusters/[cluster]-9506c00257d10dbd.js"],"/clusters/[cluster]/[job]":[s,c,"static/chunks/pages/clusters/[cluster]/[job]-159bffb2fa34ed54.js"],"/config":[u,s,f,c,e,"static/chunks/pages/config-7c48919fe030bc43.js"],"/infra":[s,c,e,a,j,"static/chunks/pages/infra-d4c6875c88771e17.js"],"/infra/[context]":[s,c,e,a,j,"static/chunks/pages/infra/[context]-909f1ceb0fcf1b99.js"],"/jobs":[s,t,c,e,a,r,n,"static/chunks/pages/jobs-a4efc09e61988f8d.js"],"/jobs/[job]":[s,c,"static/chunks/pages/jobs/[job]-6b80e9e0c6aa16a1.js"],"/users":[s,c,e,a,"static/chunks/pages/users-b2634885d67c49a6.js"],"/workspace/new":[u,s,t,f,c,e,a,r,n,k,"static/chunks/pages/workspace/new-579b3203c7c19d84.js"],"/workspaces":[u,s,t,f,c,e,a,r,n,"static/chunks/pages/workspaces-610c49ae3619ee85.js"],"/workspaces/[name]":[u,s,t,f,c,e,a,r,n,k,"static/chunks/pages/workspaces/[name]-9388e38fac73ee8f.js"],sortedPages:["/","/_app","/_error","/clusters","/clusters/[cluster]","/clusters/[cluster]/[job]","/config","/infra","/infra/[context]","/jobs","/jobs/[job]","/users","/workspace/new","/workspaces","/workspaces/[name]"]}}("static/chunks/173-7db8607cefc20f70.js","static/chunks/470-4d003c441839094d.js","static/chunks/293-351268365226d251.js","static/chunks/856-59a1760784c9e770.js","static/chunks/121-8f55ee3fa6301784.js","static/chunks/973-1a09cac61cfcc1e1.js","static/chunks/236-90e5498a5b00ec29.js","static/chunks/9f96d65d-5a3e4af68c26849e.js","static/chunks/320-afea3ddcc5bd1c6c.js","static/chunks/578-9146658cead92981.js","static/chunks/303-2c7b0f7af571710b.js","static/chunks/843-256ec920f6d5f41f.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[121],{8671:function(e,t,n){n.d(t,{Z:function(){return r}});/**
|
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 r=(0,n(998).Z)("Copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]])},3626:function(e,t,n){n.d(t,{Z:function(){return r}});/**
|
7
|
+
* @license lucide-react v0.407.0 - ISC
|
8
|
+
*
|
9
|
+
* This source code is licensed under the ISC license.
|
10
|
+
* See the LICENSE file in the root directory of this source tree.
|
11
|
+
*/let r=(0,n(998).Z)("RotateCw",[["path",{d:"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8",key:"1p45f6"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}]])},3767:function(e,t,n){n.d(t,{Z:function(){return r}});/**
|
12
|
+
* @license lucide-react v0.407.0 - ISC
|
13
|
+
*
|
14
|
+
* This source code is licensed under the ISC license.
|
15
|
+
* See the LICENSE file in the root directory of this source tree.
|
16
|
+
*/let r=(0,n(998).Z)("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]])},6327:function(e,t,n){n.d(t,{x8:function(){return el},VY:function(){return eo},dk:function(){return ea},aV:function(){return er},h_:function(){return en},fC:function(){return ee},Dx:function(){return ei},xz:function(){return et}});var r=n(7294),o=n(6206),i=n(8771),a=n(5360),l=n(1276),u=n(7342),s=n(6063),d=n(5420),c=n(2651),f=n(9981),p=e=>{let t,n;let{present:o,children:a}=e,l=function(e){var t,n;let[o,i]=r.useState(),a=r.useRef(null),l=r.useRef(e),u=r.useRef("none"),[s,d]=(t=e?"mounted":"unmounted",n={mounted:{UNMOUNT:"unmounted",ANIMATION_OUT:"unmountSuspended"},unmountSuspended:{MOUNT:"mounted",ANIMATION_END:"unmounted"},unmounted:{MOUNT:"mounted"}},r.useReducer((e,t)=>n[e][t]??e,t));return r.useEffect(()=>{let e=m(a.current);u.current="mounted"===s?e:"none"},[s]),(0,f.b)(()=>{let t=a.current,n=l.current;if(n!==e){let r=u.current,o=m(t);e?d("MOUNT"):"none"===o||t?.display==="none"?d("UNMOUNT"):n&&r!==o?d("ANIMATION_OUT"):d("UNMOUNT"),l.current=e}},[e,d]),(0,f.b)(()=>{if(o){let e;let t=o.ownerDocument.defaultView??window,n=n=>{let r=m(a.current).includes(n.animationName);if(n.target===o&&r&&(d("ANIMATION_END"),!l.current)){let n=o.style.animationFillMode;o.style.animationFillMode="forwards",e=t.setTimeout(()=>{"forwards"===o.style.animationFillMode&&(o.style.animationFillMode=n)})}},r=e=>{e.target===o&&(u.current=m(a.current))};return o.addEventListener("animationstart",r),o.addEventListener("animationcancel",n),o.addEventListener("animationend",n),()=>{t.clearTimeout(e),o.removeEventListener("animationstart",r),o.removeEventListener("animationcancel",n),o.removeEventListener("animationend",n)}}d("ANIMATION_END")},[o,d]),{isPresent:["mounted","unmountSuspended"].includes(s),ref:r.useCallback(e=>{a.current=e?getComputedStyle(e):null,i(e)},[])}}(o),u="function"==typeof a?a({present:l.isPresent}):r.Children.only(a),s=(0,i.e)(l.ref,(t=Object.getOwnPropertyDescriptor(u.props,"ref")?.get)&&"isReactWarning"in t&&t.isReactWarning?u.ref:(t=Object.getOwnPropertyDescriptor(u,"ref")?.get)&&"isReactWarning"in t&&t.isReactWarning?u.props.ref:u.props.ref||u.ref);return"function"==typeof a||l.isPresent?r.cloneElement(u,{ref:s}):null};function m(e){return e?.animationName||"none"}p.displayName="Presence";var g=n(5320),v=n(7552),y=n(6223),N=n(3541),h=n(8426),D=n(5893),O="Dialog",[b,M]=(0,a.b)(O),[R,x]=b(O),j=e=>{let{__scopeDialog:t,children:n,open:o,defaultOpen:i,onOpenChange:a,modal:s=!0}=e,d=r.useRef(null),c=r.useRef(null),[f,p]=(0,u.T)({prop:o,defaultProp:i??!1,onChange:a,caller:O});return(0,D.jsx)(R,{scope:t,triggerRef:d,contentRef:c,contentId:(0,l.M)(),titleId:(0,l.M)(),descriptionId:(0,l.M)(),open:f,onOpenChange:p,onOpenToggle:r.useCallback(()=>p(e=>!e),[p]),modal:s,children:n})};j.displayName=O;var w="DialogTrigger",I=r.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,a=x(w,n),l=(0,i.e)(t,a.triggerRef);return(0,D.jsx)(g.WV.button,{type:"button","aria-haspopup":"dialog","aria-expanded":a.open,"aria-controls":a.contentId,"data-state":H(a.open),...r,ref:l,onClick:(0,o.M)(e.onClick,a.onOpenToggle)})});I.displayName=w;var C="DialogPortal",[E,_]=b(C,{forceMount:void 0}),T=e=>{let{__scopeDialog:t,forceMount:n,children:o,container:i}=e,a=x(C,t);return(0,D.jsx)(E,{scope:t,forceMount:n,children:r.Children.map(o,e=>(0,D.jsx)(p,{present:n||a.open,children:(0,D.jsx)(c.h,{asChild:!0,container:i,children:e})}))})};T.displayName=C;var k="DialogOverlay",A=r.forwardRef((e,t)=>{let n=_(k,e.__scopeDialog),{forceMount:r=n.forceMount,...o}=e,i=x(k,e.__scopeDialog);return i.modal?(0,D.jsx)(p,{present:r||i.open,children:(0,D.jsx)(P,{...o,ref:t})}):null});A.displayName=k;var F=(0,h.Z8)("DialogOverlay.RemoveScroll"),P=r.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,o=x(k,n);return(0,D.jsx)(y.Z,{as:F,allowPinchZoom:!0,shards:[o.contentRef],children:(0,D.jsx)(g.WV.div,{"data-state":H(o.open),...r,ref:t,style:{pointerEvents:"auto",...r.style}})})}),W="DialogContent",U=r.forwardRef((e,t)=>{let n=_(W,e.__scopeDialog),{forceMount:r=n.forceMount,...o}=e,i=x(W,e.__scopeDialog);return(0,D.jsx)(p,{present:r||i.open,children:i.modal?(0,D.jsx)(V,{...o,ref:t}):(0,D.jsx)(Z,{...o,ref:t})})});U.displayName=W;var V=r.forwardRef((e,t)=>{let n=x(W,e.__scopeDialog),a=r.useRef(null),l=(0,i.e)(t,n.contentRef,a);return r.useEffect(()=>{let e=a.current;if(e)return(0,N.Ry)(e)},[]),(0,D.jsx)(S,{...e,ref:l,trapFocus:n.open,disableOutsidePointerEvents:!0,onCloseAutoFocus:(0,o.M)(e.onCloseAutoFocus,e=>{e.preventDefault(),n.triggerRef.current?.focus()}),onPointerDownOutside:(0,o.M)(e.onPointerDownOutside,e=>{let t=e.detail.originalEvent,n=0===t.button&&!0===t.ctrlKey;(2===t.button||n)&&e.preventDefault()}),onFocusOutside:(0,o.M)(e.onFocusOutside,e=>e.preventDefault())})}),Z=r.forwardRef((e,t)=>{let n=x(W,e.__scopeDialog),o=r.useRef(!1),i=r.useRef(!1);return(0,D.jsx)(S,{...e,ref:t,trapFocus:!1,disableOutsidePointerEvents:!1,onCloseAutoFocus:t=>{e.onCloseAutoFocus?.(t),t.defaultPrevented||(o.current||n.triggerRef.current?.focus(),t.preventDefault()),o.current=!1,i.current=!1},onInteractOutside:t=>{e.onInteractOutside?.(t),t.defaultPrevented||(o.current=!0,"pointerdown"!==t.detail.originalEvent.type||(i.current=!0));let r=t.target;n.triggerRef.current?.contains(r)&&t.preventDefault(),"focusin"===t.detail.originalEvent.type&&i.current&&t.preventDefault()}})}),S=r.forwardRef((e,t)=>{let{__scopeDialog:n,trapFocus:o,onOpenAutoFocus:a,onCloseAutoFocus:l,...u}=e,c=x(W,n),f=r.useRef(null),p=(0,i.e)(t,f);return(0,v.EW)(),(0,D.jsxs)(D.Fragment,{children:[(0,D.jsx)(d.M,{asChild:!0,loop:!0,trapped:o,onMountAutoFocus:a,onUnmountAutoFocus:l,children:(0,D.jsx)(s.XB,{role:"dialog",id:c.contentId,"aria-describedby":c.descriptionId,"aria-labelledby":c.titleId,"data-state":H(c.open),...u,ref:p,onDismiss:()=>c.onOpenChange(!1)})}),(0,D.jsxs)(D.Fragment,{children:[(0,D.jsx)(J,{titleId:c.titleId}),(0,D.jsx)(Q,{contentRef:f,descriptionId:c.descriptionId})]})]})}),L="DialogTitle",$=r.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,o=x(L,n);return(0,D.jsx)(g.WV.h2,{id:o.titleId,...r,ref:t})});$.displayName=L;var B="DialogDescription",q=r.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,o=x(B,n);return(0,D.jsx)(g.WV.p,{id:o.descriptionId,...r,ref:t})});q.displayName=B;var z="DialogClose",X=r.forwardRef((e,t)=>{let{__scopeDialog:n,...r}=e,i=x(z,n);return(0,D.jsx)(g.WV.button,{type:"button",...r,ref:t,onClick:(0,o.M)(e.onClick,()=>i.onOpenChange(!1))})});function H(e){return e?"open":"closed"}X.displayName=z;var K="DialogTitleWarning",[Y,G]=(0,a.k)(K,{contentName:W,titleName:L,docsSlug:"dialog"}),J=({titleId:e})=>{let t=G(K),n=`\`${t.contentName}\` requires a \`${t.titleName}\` for the component to be accessible for screen reader users.
|
17
|
+
|
18
|
+
If you want to hide the \`${t.titleName}\`, you can wrap it with our VisuallyHidden component.
|
19
|
+
|
20
|
+
For more information, see https://radix-ui.com/primitives/docs/components/${t.docsSlug}`;return r.useEffect(()=>{e&&!document.getElementById(e)&&console.error(n)},[n,e]),null},Q=({contentRef:e,descriptionId:t})=>{let n=G("DialogDescriptionWarning"),o=`Warning: Missing \`Description\` or \`aria-describedby={undefined}\` for {${n.contentName}}.`;return r.useEffect(()=>{let n=e.current?.getAttribute("aria-describedby");t&&n&&!document.getElementById(t)&&console.warn(o)},[o,e,t]),null},ee=j,et=I,en=T,er=A,eo=U,ei=$,ea=q,el=X},2003:function(e,t,n){n.d(t,{j:function(){return a}});var r=n(512);let o=e=>"boolean"==typeof e?`${e}`:0===e?"0":e,i=r.W,a=(e,t)=>n=>{var r;if((null==t?void 0:t.variants)==null)return i(e,null==n?void 0:n.class,null==n?void 0:n.className);let{variants:a,defaultVariants:l}=t,u=Object.keys(a).map(e=>{let t=null==n?void 0:n[e],r=null==l?void 0:l[e];if(null===t)return null;let i=o(t)||o(r);return a[e][i]}),s=n&&Object.entries(n).reduce((e,t)=>{let[n,r]=t;return void 0===r||(e[n]=r),e},{});return i(e,u,null==t?void 0:null===(r=t.compoundVariants)||void 0===r?void 0:r.reduce((e,t)=>{let{class:n,className:r,...o}=t;return Object.entries(o).every(e=>{let[t,n]=e;return Array.isArray(n)?n.includes({...l,...s}[t]):({...l,...s})[t]===n})?[...e,n,r]:e},[]),null==n?void 0:n.class,null==n?void 0:n.className)}}}]);
|