skypilot-nightly 1.0.0.dev20250617__py3-none-any.whl → 1.0.0.dev20250619__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/backends/backend_utils.py +7 -0
- sky/backends/cloud_vm_ray_backend.py +48 -36
- sky/cli.py +5 -5729
- sky/client/cli/__init__.py +0 -0
- sky/client/{cli.py → cli/command.py} +108 -632
- sky/client/cli/deprecation_utils.py +99 -0
- sky/client/cli/flags.py +342 -0
- sky/client/sdk.py +22 -2
- sky/clouds/kubernetes.py +5 -0
- sky/dashboard/out/404.html +1 -1
- sky/dashboard/out/_next/static/chunks/641.c8e452bc5070a630.js +1 -0
- sky/dashboard/out/_next/static/chunks/984.ae8c08791d274ca0.js +50 -0
- sky/dashboard/out/_next/static/chunks/pages/users-928edf039219e47b.js +1 -0
- sky/dashboard/out/_next/static/chunks/webpack-0263b00d6a10e64a.js +1 -0
- sky/dashboard/out/_next/static/css/6c12ecc3bd2239b6.css +3 -0
- sky/dashboard/out/_next/static/{vA3PPpkBwpRTRNBHFYAw_ → whetcrnbXtqQcMRbXUbhW}/_buildManifest.js +1 -1
- 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.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/global_user_state.py +50 -11
- sky/jobs/constants.py +0 -2
- sky/jobs/scheduler.py +7 -4
- sky/jobs/server/core.py +6 -3
- sky/jobs/state.py +9 -8
- sky/jobs/utils.py +1 -1
- sky/logs/__init__.py +17 -0
- sky/logs/agent.py +73 -0
- sky/logs/gcp.py +91 -0
- sky/models.py +1 -0
- sky/provision/common.py +10 -0
- sky/provision/instance_setup.py +35 -0
- sky/provision/provisioner.py +11 -0
- sky/resources.py +7 -6
- sky/serve/server/core.py +5 -0
- sky/server/common.py +21 -9
- sky/server/requests/payloads.py +19 -1
- sky/server/server.py +121 -29
- sky/setup_files/dependencies.py +11 -1
- sky/skylet/constants.py +13 -1
- sky/skylet/job_lib.py +75 -19
- sky/templates/kubernetes-ray.yml.j2 +9 -0
- sky/users/permission.py +49 -19
- sky/users/rbac.py +10 -1
- sky/users/server.py +274 -9
- sky/utils/env_options.py +6 -0
- sky/utils/schemas.py +42 -2
- {skypilot_nightly-1.0.0.dev20250617.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/METADATA +9 -1
- {skypilot_nightly-1.0.0.dev20250617.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/RECORD +70 -63
- sky/dashboard/out/_next/static/chunks/600.bd2ed8c076b720ec.js +0 -16
- sky/dashboard/out/_next/static/chunks/pages/users-c69ffcab9d6e5269.js +0 -1
- sky/dashboard/out/_next/static/chunks/webpack-1b69b196a4dbffef.js +0 -1
- sky/dashboard/out/_next/static/css/8e97adcaacc15293.css +0 -3
- /sky/dashboard/out/_next/static/chunks/{37-824c707421f6f003.js → 37-3a4d77ad62932eaf.js} +0 -0
- /sky/dashboard/out/_next/static/chunks/{843-ab9c4f609239155f.js → 843-b3040e493f6e7947.js} +0 -0
- /sky/dashboard/out/_next/static/chunks/{938-385d190b95815e11.js → 938-1493ac755eadeb35.js} +0 -0
- /sky/dashboard/out/_next/static/chunks/{973-c807fc34f09c7df3.js → 973-db3c97c2bfbceb65.js} +0 -0
- /sky/dashboard/out/_next/static/chunks/pages/{_app-32b2caae3445bf3b.js → _app-c416e87d5c2715cf.js} +0 -0
- /sky/dashboard/out/_next/static/chunks/pages/workspaces/{[name]-c8c2191328532b7d.js → [name]-c4ff1ec05e2f3daf.js} +0 -0
- /sky/dashboard/out/_next/static/{vA3PPpkBwpRTRNBHFYAw_ → whetcrnbXtqQcMRbXUbhW}/_ssgManifest.js +0 -0
- {skypilot_nightly-1.0.0.dev20250617.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/WHEEL +0 -0
- {skypilot_nightly-1.0.0.dev20250617.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/entry_points.txt +0 -0
- {skypilot_nightly-1.0.0.dev20250617.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/licenses/LICENSE +0 -0
- {skypilot_nightly-1.0.0.dev20250617.dist-info → skypilot_nightly-1.0.0.dev20250619.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
"""Utilities for deprecating commands."""
|
2
|
+
|
3
|
+
import copy
|
4
|
+
import functools
|
5
|
+
from typing import Any, Dict, Optional
|
6
|
+
|
7
|
+
import click
|
8
|
+
|
9
|
+
from sky import sky_logging
|
10
|
+
|
11
|
+
logger = sky_logging.init_logger(__name__)
|
12
|
+
|
13
|
+
|
14
|
+
def _with_deprecation_warning(
|
15
|
+
f,
|
16
|
+
original_name: str,
|
17
|
+
alias_name: str,
|
18
|
+
override_command_argument: Optional[Dict[str, Any]] = None):
|
19
|
+
|
20
|
+
@functools.wraps(f)
|
21
|
+
def wrapper(self, *args, **kwargs):
|
22
|
+
override_str = ''
|
23
|
+
if override_command_argument is not None:
|
24
|
+
overrides = []
|
25
|
+
for k, v in override_command_argument.items():
|
26
|
+
if isinstance(v, bool):
|
27
|
+
if v:
|
28
|
+
overrides.append(f'--{k}')
|
29
|
+
else:
|
30
|
+
overrides.append(f'--no-{k}')
|
31
|
+
else:
|
32
|
+
overrides.append(f'--{k.replace("_", "-")}={v}')
|
33
|
+
override_str = ' with additional arguments ' + ' '.join(overrides)
|
34
|
+
click.secho(
|
35
|
+
f'WARNING: `{alias_name}` has been renamed to `{original_name}` '
|
36
|
+
f'and will be removed in a future release. Please use the '
|
37
|
+
f'latter{override_str} instead.\n',
|
38
|
+
err=True,
|
39
|
+
fg='yellow')
|
40
|
+
return f(self, *args, **kwargs)
|
41
|
+
|
42
|
+
return wrapper
|
43
|
+
|
44
|
+
|
45
|
+
def _override_arguments(callback, override_command_argument: Dict[str, Any]):
|
46
|
+
|
47
|
+
def wrapper(*args, **kwargs):
|
48
|
+
logger.info(f'Overriding arguments: {override_command_argument}')
|
49
|
+
kwargs.update(override_command_argument)
|
50
|
+
return callback(*args, **kwargs)
|
51
|
+
|
52
|
+
return wrapper
|
53
|
+
|
54
|
+
|
55
|
+
def _add_command_alias(
|
56
|
+
group: click.Group,
|
57
|
+
command: click.Command,
|
58
|
+
hidden: bool = False,
|
59
|
+
new_group: Optional[click.Group] = None,
|
60
|
+
new_command_name: Optional[str] = None,
|
61
|
+
override_command_argument: Optional[Dict[str, Any]] = None,
|
62
|
+
with_warning: bool = True,
|
63
|
+
) -> None:
|
64
|
+
"""Add a alias of a command to a group."""
|
65
|
+
if new_group is None:
|
66
|
+
new_group = group
|
67
|
+
if new_command_name is None:
|
68
|
+
new_command_name = command.name
|
69
|
+
if new_group == group and new_command_name == command.name:
|
70
|
+
raise ValueError('Cannot add an alias to the same command.')
|
71
|
+
new_command = copy.deepcopy(command)
|
72
|
+
new_command.hidden = hidden
|
73
|
+
new_command.name = new_command_name
|
74
|
+
|
75
|
+
if override_command_argument:
|
76
|
+
new_command.callback = _override_arguments(new_command.callback,
|
77
|
+
override_command_argument)
|
78
|
+
|
79
|
+
orig = f'sky {group.name} {command.name}'
|
80
|
+
alias = f'sky {new_group.name} {new_command_name}'
|
81
|
+
if with_warning:
|
82
|
+
new_command.invoke = _with_deprecation_warning(
|
83
|
+
new_command.invoke,
|
84
|
+
orig,
|
85
|
+
alias,
|
86
|
+
override_command_argument=override_command_argument)
|
87
|
+
new_group.add_command(new_command, name=new_command_name)
|
88
|
+
|
89
|
+
|
90
|
+
def _deprecate_and_hide_command(group, command_to_deprecate,
|
91
|
+
alternative_command):
|
92
|
+
"""Hide a command and show a deprecation note, hinting the alternative."""
|
93
|
+
command_to_deprecate.hidden = True
|
94
|
+
if group is not None:
|
95
|
+
orig = f'sky {group.name} {command_to_deprecate.name}'
|
96
|
+
else:
|
97
|
+
orig = f'sky {command_to_deprecate.name}'
|
98
|
+
command_to_deprecate.invoke = _with_deprecation_warning(
|
99
|
+
command_to_deprecate.invoke, alternative_command, orig)
|
sky/client/cli/flags.py
ADDED
@@ -0,0 +1,342 @@
|
|
1
|
+
"""Flags for the CLI."""
|
2
|
+
|
3
|
+
import os
|
4
|
+
from typing import Optional, Tuple
|
5
|
+
|
6
|
+
import click
|
7
|
+
import dotenv
|
8
|
+
|
9
|
+
from sky import skypilot_config
|
10
|
+
from sky.utils import resources_utils
|
11
|
+
|
12
|
+
|
13
|
+
def _parse_env_var(env_var: str) -> Tuple[str, str]:
|
14
|
+
"""Parse env vars into a (KEY, VAL) pair."""
|
15
|
+
if '=' not in env_var:
|
16
|
+
value = os.environ.get(env_var)
|
17
|
+
if value is None:
|
18
|
+
raise click.UsageError(
|
19
|
+
f'{env_var} is not set in local environment.')
|
20
|
+
return (env_var, value)
|
21
|
+
ret = tuple(env_var.split('=', 1))
|
22
|
+
if len(ret) != 2:
|
23
|
+
raise click.UsageError(
|
24
|
+
f'Invalid env var: {env_var}. Must be in the form of KEY=VAL '
|
25
|
+
'or KEY.')
|
26
|
+
return ret[0], ret[1]
|
27
|
+
|
28
|
+
|
29
|
+
def _parse_secret_var(secret_var: str) -> Tuple[str, str]:
|
30
|
+
"""Parse secret vars into a (KEY, VAL) pair."""
|
31
|
+
if '=' not in secret_var:
|
32
|
+
value = os.environ.get(secret_var)
|
33
|
+
if value is None:
|
34
|
+
raise click.UsageError(
|
35
|
+
f'{secret_var} is not set in local environment.')
|
36
|
+
return (secret_var, value)
|
37
|
+
ret = tuple(secret_var.split('=', 1))
|
38
|
+
if len(ret) != 2:
|
39
|
+
raise click.UsageError(
|
40
|
+
f'Invalid secret var: {secret_var}. Must be in the form of KEY=VAL '
|
41
|
+
'or KEY.')
|
42
|
+
return ret[0], ret[1]
|
43
|
+
|
44
|
+
|
45
|
+
COMMON_OPTIONS = [
|
46
|
+
click.option('--async/--no-async',
|
47
|
+
'async_call',
|
48
|
+
required=False,
|
49
|
+
is_flag=True,
|
50
|
+
default=False,
|
51
|
+
help=('Run the command asynchronously.'))
|
52
|
+
]
|
53
|
+
|
54
|
+
TASK_OPTIONS = [
|
55
|
+
click.option(
|
56
|
+
'--workdir',
|
57
|
+
required=False,
|
58
|
+
type=click.Path(exists=True, file_okay=False),
|
59
|
+
help=('If specified, sync this dir to the remote working directory, '
|
60
|
+
'where the task will be invoked. '
|
61
|
+
'Overrides the "workdir" config in the YAML if both are supplied.'
|
62
|
+
)),
|
63
|
+
click.option(
|
64
|
+
'--infra',
|
65
|
+
required=False,
|
66
|
+
type=str,
|
67
|
+
help='Infrastructure to use. '
|
68
|
+
'Format: cloud, cloud/region, cloud/region/zone, '
|
69
|
+
'k8s/context-name, or ssh/node-pool-name. '
|
70
|
+
'Examples: aws, aws/us-east-1, aws/us-east-1/us-east-1a, '
|
71
|
+
# TODO(zhwu): we have to use `\*` to make sure the docs build
|
72
|
+
# not complaining about the `*`, but this will cause `--help`
|
73
|
+
# to show `\*` instead of `*`.
|
74
|
+
'aws/\\*/us-east-1a, k8s/my-context, ssh/my-nodes.'),
|
75
|
+
click.option(
|
76
|
+
'--cloud',
|
77
|
+
required=False,
|
78
|
+
type=str,
|
79
|
+
help=('The cloud to use. If specified, overrides the "resources.cloud" '
|
80
|
+
'config. Passing "none" resets the config.'),
|
81
|
+
hidden=True),
|
82
|
+
click.option(
|
83
|
+
'--region',
|
84
|
+
required=False,
|
85
|
+
type=str,
|
86
|
+
help=('The region to use. If specified, overrides the '
|
87
|
+
'"resources.region" config. Passing "none" resets the config.'),
|
88
|
+
hidden=True),
|
89
|
+
click.option(
|
90
|
+
'--zone',
|
91
|
+
required=False,
|
92
|
+
type=str,
|
93
|
+
help=('The zone to use. If specified, overrides the '
|
94
|
+
'"resources.zone" config. Passing "none" resets the config.'),
|
95
|
+
hidden=True),
|
96
|
+
click.option(
|
97
|
+
'--num-nodes',
|
98
|
+
required=False,
|
99
|
+
type=int,
|
100
|
+
help=('Number of nodes to execute the task on. '
|
101
|
+
'Overrides the "num_nodes" config in the YAML if both are '
|
102
|
+
'supplied.')),
|
103
|
+
click.option(
|
104
|
+
'--cpus',
|
105
|
+
default=None,
|
106
|
+
type=str,
|
107
|
+
required=False,
|
108
|
+
help=('Number of vCPUs each instance must have (e.g., '
|
109
|
+
'``--cpus=4`` (exactly 4) or ``--cpus=4+`` (at least 4)). '
|
110
|
+
'This is used to automatically select the instance type.')),
|
111
|
+
click.option(
|
112
|
+
'--memory',
|
113
|
+
default=None,
|
114
|
+
type=str,
|
115
|
+
required=False,
|
116
|
+
help=(
|
117
|
+
'Amount of memory each instance must have in GB (e.g., '
|
118
|
+
'``--memory=16`` (exactly 16GB), ``--memory=16+`` (at least 16GB))'
|
119
|
+
)),
|
120
|
+
click.option('--disk-size',
|
121
|
+
default=None,
|
122
|
+
type=int,
|
123
|
+
required=False,
|
124
|
+
help=('OS disk size in GBs.')),
|
125
|
+
click.option('--disk-tier',
|
126
|
+
default=None,
|
127
|
+
type=click.Choice(resources_utils.DiskTier.supported_tiers(),
|
128
|
+
case_sensitive=False),
|
129
|
+
required=False,
|
130
|
+
help=resources_utils.DiskTier.cli_help_message()),
|
131
|
+
click.option('--network-tier',
|
132
|
+
default=None,
|
133
|
+
type=click.Choice(
|
134
|
+
resources_utils.NetworkTier.supported_tiers(),
|
135
|
+
case_sensitive=False),
|
136
|
+
required=False,
|
137
|
+
help=resources_utils.NetworkTier.cli_help_message()),
|
138
|
+
click.option(
|
139
|
+
'--use-spot/--no-use-spot',
|
140
|
+
required=False,
|
141
|
+
default=None,
|
142
|
+
help=('Whether to request spot instances. If specified, overrides the '
|
143
|
+
'"resources.use_spot" config.')),
|
144
|
+
click.option('--image-id',
|
145
|
+
required=False,
|
146
|
+
default=None,
|
147
|
+
help=('Custom image id for launching the instances. '
|
148
|
+
'Passing "none" resets the config.')),
|
149
|
+
click.option('--env-file',
|
150
|
+
required=False,
|
151
|
+
type=dotenv.dotenv_values,
|
152
|
+
help="""\
|
153
|
+
Path to a dotenv file with environment variables to set on the remote
|
154
|
+
node.
|
155
|
+
|
156
|
+
If any values from ``--env-file`` conflict with values set by
|
157
|
+
``--env``, the ``--env`` value will be preferred."""),
|
158
|
+
click.option(
|
159
|
+
'--env',
|
160
|
+
required=False,
|
161
|
+
type=_parse_env_var,
|
162
|
+
multiple=True,
|
163
|
+
help="""\
|
164
|
+
Environment variable to set on the remote node.
|
165
|
+
It can be specified multiple times.
|
166
|
+
Examples:
|
167
|
+
|
168
|
+
\b
|
169
|
+
1. ``--env MY_ENV=1``: set ``$MY_ENV`` on the cluster to be 1.
|
170
|
+
|
171
|
+
2. ``--env MY_ENV2=$HOME``: set ``$MY_ENV2`` on the cluster to be the
|
172
|
+
same value of ``$HOME`` in the local environment where the CLI command
|
173
|
+
is run.
|
174
|
+
|
175
|
+
3. ``--env MY_ENV3``: set ``$MY_ENV3`` on the cluster to be the
|
176
|
+
same value of ``$MY_ENV3`` in the local environment.""",
|
177
|
+
),
|
178
|
+
click.option(
|
179
|
+
'--secret',
|
180
|
+
required=False,
|
181
|
+
type=_parse_secret_var,
|
182
|
+
multiple=True,
|
183
|
+
help="""\
|
184
|
+
Secret variable to set on the remote node. These variables will be
|
185
|
+
redacted in logs and YAML outputs for security. It can be specified
|
186
|
+
multiple times. Examples:
|
187
|
+
|
188
|
+
\b
|
189
|
+
1. ``--secret API_KEY=secret123``: set ``$API_KEY`` on the cluster to
|
190
|
+
be secret123.
|
191
|
+
|
192
|
+
2. ``--secret JWT_SECRET``: set ``$JWT_SECRET`` on the cluster to be
|
193
|
+
the same value of ``$JWT_SECRET`` in the local environment.""",
|
194
|
+
)
|
195
|
+
]
|
196
|
+
|
197
|
+
TASK_OPTIONS_WITH_NAME = [
|
198
|
+
click.option('--name',
|
199
|
+
'-n',
|
200
|
+
required=False,
|
201
|
+
type=str,
|
202
|
+
help=('Task name. Overrides the "name" '
|
203
|
+
'config in the YAML if both are supplied.')),
|
204
|
+
] + TASK_OPTIONS
|
205
|
+
|
206
|
+
EXTRA_RESOURCES_OPTIONS = [
|
207
|
+
click.option(
|
208
|
+
'--gpus',
|
209
|
+
required=False,
|
210
|
+
type=str,
|
211
|
+
help=
|
212
|
+
('Type and number of GPUs to use. Example values: '
|
213
|
+
'"V100:8", "V100" (short for a count of 1), or "V100:0.5" '
|
214
|
+
'(fractional counts are supported by the scheduling framework). '
|
215
|
+
'If a new cluster is being launched by this command, this is the '
|
216
|
+
'resources to provision. If an existing cluster is being reused, this'
|
217
|
+
' is seen as the task demand, which must fit the cluster\'s total '
|
218
|
+
'resources and is used for scheduling the task. '
|
219
|
+
'Overrides the "accelerators" '
|
220
|
+
'config in the YAML if both are supplied. '
|
221
|
+
'Passing "none" resets the config.')),
|
222
|
+
click.option(
|
223
|
+
'--instance-type',
|
224
|
+
'-t',
|
225
|
+
required=False,
|
226
|
+
type=str,
|
227
|
+
help=('The instance type to use. If specified, overrides the '
|
228
|
+
'"resources.instance_type" config. Passing "none" resets the '
|
229
|
+
'config.'),
|
230
|
+
),
|
231
|
+
click.option(
|
232
|
+
'--ports',
|
233
|
+
required=False,
|
234
|
+
type=str,
|
235
|
+
multiple=True,
|
236
|
+
help=('Ports to open on the cluster. '
|
237
|
+
'If specified, overrides the "ports" config in the YAML. '),
|
238
|
+
),
|
239
|
+
]
|
240
|
+
|
241
|
+
|
242
|
+
def config_option(expose_value: bool):
|
243
|
+
"""A decorator for the --config option.
|
244
|
+
|
245
|
+
This decorator is used to parse the --config option.
|
246
|
+
|
247
|
+
Any overrides specified in the command line will be applied to the skypilot
|
248
|
+
config before the decorated function is called.
|
249
|
+
|
250
|
+
If expose_value is True, the decorated function will receive the parsed
|
251
|
+
config overrides as 'config_override' parameter.
|
252
|
+
|
253
|
+
Args:
|
254
|
+
expose_value: Whether to expose the value of the option to the decorated
|
255
|
+
function.
|
256
|
+
"""
|
257
|
+
|
258
|
+
def preprocess_config_options(ctx, param, value):
|
259
|
+
del ctx # Unused.
|
260
|
+
param.name = 'config_override'
|
261
|
+
try:
|
262
|
+
if len(value) == 0:
|
263
|
+
return None
|
264
|
+
else:
|
265
|
+
# Apply the config overrides to the skypilot config.
|
266
|
+
return skypilot_config.apply_cli_config(value)
|
267
|
+
except ValueError as e:
|
268
|
+
raise click.BadParameter(f'{str(e)}') from e
|
269
|
+
|
270
|
+
def return_option_decorator(func):
|
271
|
+
return click.option(
|
272
|
+
'--config',
|
273
|
+
required=False,
|
274
|
+
type=str,
|
275
|
+
multiple=True,
|
276
|
+
expose_value=expose_value,
|
277
|
+
callback=preprocess_config_options,
|
278
|
+
help=('Path to a config file or a comma-separated '
|
279
|
+
'list of key-value pairs '
|
280
|
+
'(e.g. "nested.key1=val1,another.key2=val2").'),
|
281
|
+
)(func)
|
282
|
+
|
283
|
+
return return_option_decorator
|
284
|
+
|
285
|
+
|
286
|
+
def yes_option():
|
287
|
+
"""A decorator for the --yes/-y option."""
|
288
|
+
|
289
|
+
def return_option_decorator(func):
|
290
|
+
return click.option('--yes',
|
291
|
+
'-y',
|
292
|
+
is_flag=True,
|
293
|
+
default=False,
|
294
|
+
required=False,
|
295
|
+
help='Skip confirmation prompt.')(func)
|
296
|
+
|
297
|
+
return return_option_decorator
|
298
|
+
|
299
|
+
|
300
|
+
def verbose_option(helptext: Optional[str] = None):
|
301
|
+
"""A decorator for the --verbose/-v option."""
|
302
|
+
|
303
|
+
if helptext is None:
|
304
|
+
helptext = 'Show all information in full.'
|
305
|
+
|
306
|
+
def return_option_decorator(func):
|
307
|
+
return click.option('--verbose',
|
308
|
+
'-v',
|
309
|
+
default=False,
|
310
|
+
is_flag=True,
|
311
|
+
required=False,
|
312
|
+
help=helptext)(func)
|
313
|
+
|
314
|
+
return return_option_decorator
|
315
|
+
|
316
|
+
|
317
|
+
def all_option(helptext: Optional[str] = None):
|
318
|
+
"""A decorator for the --all option."""
|
319
|
+
|
320
|
+
def return_option_decorator(func):
|
321
|
+
return click.option('--all',
|
322
|
+
'-a',
|
323
|
+
is_flag=True,
|
324
|
+
default=False,
|
325
|
+
required=False,
|
326
|
+
help=helptext)(func)
|
327
|
+
|
328
|
+
return return_option_decorator
|
329
|
+
|
330
|
+
|
331
|
+
def all_users_option(helptext: Optional[str] = None):
|
332
|
+
"""A decorator for the --all-users option."""
|
333
|
+
|
334
|
+
def return_option_decorator(func):
|
335
|
+
return click.option('--all-users',
|
336
|
+
'-u',
|
337
|
+
is_flag=True,
|
338
|
+
default=False,
|
339
|
+
required=False,
|
340
|
+
help=helptext)(func)
|
341
|
+
|
342
|
+
return return_option_decorator
|
sky/client/sdk.py
CHANGED
@@ -1856,6 +1856,7 @@ def api_start(
|
|
1856
1856
|
deploy: bool = False,
|
1857
1857
|
host: str = '127.0.0.1',
|
1858
1858
|
foreground: bool = False,
|
1859
|
+
enable_basic_auth: bool = False,
|
1859
1860
|
) -> None:
|
1860
1861
|
"""Starts the API server.
|
1861
1862
|
|
@@ -1869,6 +1870,8 @@ def api_start(
|
|
1869
1870
|
if deploy is True, to allow remote access.
|
1870
1871
|
foreground: Whether to run the API server in the foreground (run in
|
1871
1872
|
the current process).
|
1873
|
+
enable_basic_auth: Whether to enable basic authentication
|
1874
|
+
in the API server.
|
1872
1875
|
Returns:
|
1873
1876
|
None
|
1874
1877
|
"""
|
@@ -1887,7 +1890,8 @@ def api_start(
|
|
1887
1890
|
'from the config file and/or unset the '
|
1888
1891
|
'SKYPILOT_API_SERVER_ENDPOINT environment '
|
1889
1892
|
'variable.')
|
1890
|
-
server_common.check_server_healthy_or_start_fn(deploy, host, foreground
|
1893
|
+
server_common.check_server_healthy_or_start_fn(deploy, host, foreground,
|
1894
|
+
enable_basic_auth)
|
1891
1895
|
if foreground:
|
1892
1896
|
# Explain why current process exited
|
1893
1897
|
logger.info('API server is already running:')
|
@@ -1990,7 +1994,8 @@ def api_login(endpoint: Optional[str] = None, get_token: bool = False) -> None:
|
|
1990
1994
|
raise click.BadParameter('Endpoint must be a valid URL.')
|
1991
1995
|
endpoint = endpoint.rstrip('/')
|
1992
1996
|
|
1993
|
-
server_status = server_common.check_server_healthy(
|
1997
|
+
server_status, api_server_info = server_common.check_server_healthy(
|
1998
|
+
endpoint)
|
1994
1999
|
if server_status == server_common.ApiServerStatus.NEEDS_AUTH or get_token:
|
1995
2000
|
# We detected an auth proxy, so go through the auth proxy cookie flow.
|
1996
2001
|
token: Optional[str] = None
|
@@ -2121,6 +2126,21 @@ def api_login(endpoint: Optional[str] = None, get_token: bool = False) -> None:
|
|
2121
2126
|
'w',
|
2122
2127
|
encoding='utf-8') as f:
|
2123
2128
|
f.write(user_hash)
|
2129
|
+
else:
|
2130
|
+
# Check if basic auth is enabled
|
2131
|
+
if api_server_info.basic_auth_enabled:
|
2132
|
+
if api_server_info.user is None:
|
2133
|
+
with ux_utils.print_exception_no_traceback():
|
2134
|
+
raise ValueError(
|
2135
|
+
'Basic auth is enabled but no valid user is found')
|
2136
|
+
# Set the user hash in the local file
|
2137
|
+
user_hash = api_server_info.user.get('id')
|
2138
|
+
if not user_hash or not common_utils.is_valid_user_hash(user_hash):
|
2139
|
+
raise ValueError(f'Invalid user hash: {user_hash}')
|
2140
|
+
with open(os.path.expanduser('~/.sky/user_hash'),
|
2141
|
+
'w',
|
2142
|
+
encoding='utf-8') as f:
|
2143
|
+
f.write(user_hash)
|
2124
2144
|
|
2125
2145
|
# Set the endpoint in the config file
|
2126
2146
|
config_path = pathlib.Path(
|
sky/clouds/kubernetes.py
CHANGED
@@ -602,6 +602,10 @@ class Kubernetes(clouds.Cloud):
|
|
602
602
|
None,
|
603
603
|
override_configs=resources.cluster_config_overrides)
|
604
604
|
|
605
|
+
k8s_kueue_local_queue_name = skypilot_config.get_nested(
|
606
|
+
('kubernetes', 'kueue', 'local_queue_name'),
|
607
|
+
None,
|
608
|
+
override_configs=resources.cluster_config_overrides)
|
605
609
|
deploy_vars = {
|
606
610
|
'instance_type': resources.instance_type,
|
607
611
|
'custom_resources': custom_resources,
|
@@ -619,6 +623,7 @@ class Kubernetes(clouds.Cloud):
|
|
619
623
|
'k8s_service_account_name': k8s_service_account_name,
|
620
624
|
'k8s_automount_sa_token': 'true',
|
621
625
|
'k8s_fuse_device_required': fuse_device_required,
|
626
|
+
'k8s_kueue_local_queue_name': k8s_kueue_local_queue_name,
|
622
627
|
# Namespace to run the fusermount-server daemonset in
|
623
628
|
'k8s_skypilot_system_namespace': _SKYPILOT_SYSTEM_NAMESPACE,
|
624
629
|
'k8s_fusermount_shared_dir': _FUSERMOUNT_SHARED_DIR,
|
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/6c12ecc3bd2239b6.css" as="style"/><link rel="stylesheet" href="/dashboard/_next/static/css/6c12ecc3bd2239b6.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-0263b00d6a10e64a.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-c416e87d5c2715cf.js" defer=""></script><script src="/dashboard/_next/static/chunks/pages/_error-1be831200e60c5c0.js" defer=""></script><script src="/dashboard/_next/static/whetcrnbXtqQcMRbXUbhW/_buildManifest.js" defer=""></script><script src="/dashboard/_next/static/whetcrnbXtqQcMRbXUbhW/_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":"whetcrnbXtqQcMRbXUbhW","assetPrefix":"/dashboard","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
|
@@ -0,0 +1 @@
|
|
1
|
+
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[641],{1812:function(e,s,r){r.d(s,{X:function(){return l}});var t=r(5893),a=r(7294);let n=e=>{if(!(null==e?void 0:e.message))return"An unexpected error occurred.";let s=e.message;return s.includes("failed:")&&(s=s.split("failed:")[1].trim()),s},l=e=>{let{error:s,title:r="Error",onDismiss:l}=e,[i,o]=(0,a.useState)(!1);if((0,a.useEffect)(()=>{s&&o(!1)},[s]),!s||i)return null;let c="string"==typeof s?s:n(s);return(0,t.jsx)("div",{className:"bg-red-50 border border-red-200 rounded-md p-3 mb-4",children:(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{className:"flex",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:(0,t.jsx)("svg",{className:"h-5 w-5 text-red-400",viewBox:"0 0 20 20",fill:"currentColor",children:(0,t.jsx)("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z",clipRule:"evenodd"})})}),(0,t.jsx)("div",{className:"ml-3",children:(0,t.jsxs)("div",{className:"text-sm text-red-800",children:[(0,t.jsxs)("strong",{children:[r,":"]})," ",c]})})]}),(0,t.jsx)("button",{onClick:()=>{o(!0),l&&l()},className:"flex-shrink-0 ml-4 text-red-400 hover:text-red-600 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 focus:ring-offset-red-50 rounded","aria-label":"Dismiss error",children:(0,t.jsx)("svg",{className:"h-4 w-4",viewBox:"0 0 20 20",fill:"currentColor",children:(0,t.jsx)("path",{fillRule:"evenodd",d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",clipRule:"evenodd"})})})]})})}},803:function(e,s,r){r.d(s,{z:function(){return c}});var t=r(5893),a=r(7294),n=r(8426),l=r(2003),i=r(2350);let o=(0,l.j)("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",{variants:{variant:{default:"bg-primary text-primary-foreground hover:bg-primary/90",destructive:"bg-destructive text-destructive-foreground hover:bg-destructive/90",outline:"border border-input bg-background hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80",ghost:"hover:bg-accent hover:text-accent-foreground",link:"text-primary underline-offset-4 hover:underline"},size:{default:"h-10 px-4 py-2",sm:"h-9 rounded-md px-3",lg:"h-11 rounded-md px-8",icon:"h-10 w-10"}},defaultVariants:{variant:"default",size:"default"}}),c=a.forwardRef((e,s)=>{let{className:r,variant:a,size:l,asChild:c=!1,...d}=e,u=c?n.g7:"button";return(0,t.jsx)(u,{className:(0,i.cn)(o({variant:a,size:l,className:r})),ref:s,...d})});c.displayName="Button"},7673:function(e,s,r){r.d(s,{Ol:function(){return c},Zb:function(){return o},aY:function(){return m},eW:function(){return x},ll:function(){return d}});var t=r(5893),a=r(7294),n=r(5697),l=r.n(n),i=r(2350);let o=a.forwardRef((e,s)=>{let{className:r,children:a,...n}=e;return(0,t.jsx)("div",{ref:s,className:(0,i.cn)("rounded-lg border bg-card text-card-foreground shadow-sm",r),...n,children:a})});o.displayName="Card",o.propTypes={className:l().string,children:l().node};let c=a.forwardRef((e,s)=>{let{className:r,children:a,...n}=e;return(0,t.jsx)("div",{ref:s,className:(0,i.cn)("flex flex-col space-y-1.5 p-6",r),...n,children:a})});c.displayName="CardHeader",c.propTypes={className:l().string,children:l().node};let d=a.forwardRef((e,s)=>{let{className:r,children:a,...n}=e;return(0,t.jsx)("h3",{ref:s,className:(0,i.cn)("text-2xl font-semibold leading-none tracking-tight",r),...n,children:a})});d.displayName="CardTitle",d.propTypes={className:l().string,children:l().node};let u=a.forwardRef((e,s)=>{let{className:r,children:a,...n}=e;return(0,t.jsx)("p",{ref:s,className:(0,i.cn)("text-sm text-muted-foreground",r),...n,children:a})});u.displayName="CardDescription",u.propTypes={className:l().string,children:l().node};let m=a.forwardRef((e,s)=>{let{className:r,children:a,...n}=e;return(0,t.jsx)("div",{ref:s,className:(0,i.cn)("p-6 pt-0",r),...n,children:a})});m.displayName="CardContent",m.propTypes={className:l().string,children:l().node};let x=a.forwardRef((e,s)=>{let{className:r,children:a,...n}=e;return(0,t.jsx)("div",{ref:s,className:(0,i.cn)("flex items-center p-6 pt-0",r),...n,children:a})});x.displayName="CardFooter",x.propTypes={className:l().string,children:l().node}},326:function(e,s,r){r.d(s,{$N:function(){return f},Be:function(){return h},Vq:function(){return o},cN:function(){return x},cZ:function(){return u},fK:function(){return m}});var t=r(5893),a=r(7294),n=r(6327),l=r(2350),i=r(3767);let o=n.fC;n.xz;let c=n.h_;n.x8;let d=a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)(n.aV,{ref:s,className:(0,l.cn)("fixed inset-0 z-50 bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",r),...a})});d.displayName=n.aV.displayName;let u=a.forwardRef((e,s)=>{let{className:r,children:a,...o}=e;return(0,t.jsxs)(c,{children:[(0,t.jsx)(d,{}),(0,t.jsxs)(n.VY,{ref:s,className:(0,l.cn)("fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-gray-200 bg-white p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",r),...o,children:[a,(0,t.jsxs)(n.x8,{className:"absolute right-4 top-4 rounded-sm opacity-70 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 data-[state=open]:text-gray-500",children:[(0,t.jsx)(i.Z,{className:"h-4 w-4"}),(0,t.jsx)("span",{className:"sr-only",children:"Close"})]})]})]})});u.displayName=n.VY.displayName;let m=e=>{let{className:s,...r}=e;return(0,t.jsx)("div",{className:(0,l.cn)("flex flex-col space-y-1.5 text-center sm:text-left",s),...r})};m.displayName="DialogHeader";let x=e=>{let{className:s,...r}=e;return(0,t.jsx)("div",{className:(0,l.cn)("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",s),...r})};x.displayName="DialogFooter";let f=a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)(n.Dx,{ref:s,className:(0,l.cn)("text-lg font-semibold leading-none tracking-tight",r),...a})});f.displayName=n.Dx.displayName;let h=a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)(n.dk,{ref:s,className:(0,l.cn)("text-sm text-gray-500",r),...a})});h.displayName=n.dk.displayName},8764:function(e,s,r){r.d(s,{RM:function(){return o},SC:function(){return c},iA:function(){return l},pj:function(){return u},ss:function(){return d},xD:function(){return i}});var t=r(5893),a=r(7294),n=r(2350);let l=a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)("div",{className:"relative w-full overflow-auto",children:(0,t.jsx)("table",{ref:s,className:(0,n.cn)("w-full caption-bottom text-base",r),...a})})});l.displayName="Table";let i=a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)("thead",{ref:s,className:(0,n.cn)("[&_tr]:border-b",r),...a})});i.displayName="TableHeader";let o=a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)("tbody",{ref:s,className:(0,n.cn)("[&_tr:last-child]:border-0",r),...a})});o.displayName="TableBody",a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)("tfoot",{ref:s,className:(0,n.cn)("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",r),...a})}).displayName="TableFooter";let c=a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)("tr",{ref:s,className:(0,n.cn)("border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",r),...a})});c.displayName="TableRow";let d=a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)("th",{ref:s,className:(0,n.cn)("h-12 px-4 text-left align-middle font-medium text-[hsl(var(--text-strong))] [&:has([role=checkbox])]:pr-0",r),...a})});d.displayName="TableHead";let u=a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)("td",{ref:s,className:(0,n.cn)("p-4 align-middle [&:has([role=checkbox])]:pr-0",r),...a})});u.displayName="TableCell",a.forwardRef((e,s)=>{let{className:r,...a}=e;return(0,t.jsx)("caption",{ref:s,className:(0,n.cn)("mt-4 text-base text-muted-foreground",r),...a})}).displayName="TableCaption"},2641:function(e,s,r){r.r(s),r.d(s,{Users:function(){return V}});var t=r(5893),a=r(7294),n=r(5697),l=r.n(n),i=r(8799),o=r(1664),c=r.n(o),d=r(803),u=r(8764),m=r(3081),x=r(3266),f=r(8969),h=r(6378),p=r(6856),g=r(1214),b=r(4545),j=r(1109),y=r(3626),v=r(3685),N=r(6741),w=r(6826),k=r(282),C=r(3767),R=r(5274),D=r(3936),S=r(7603);r(9470);var E=r(3001),I=r(7673),U=r(7145),F=r(326),_=r(1812);let L=(e,s)=>e&&e.includes("@")?e.split("@")[0]:e||"N/A",Z=(e,s)=>e&&e.includes("@")?e:s||"-",z=g.nb.REFRESH_INTERVAL,T=e=>{let{message:s,onDismiss:r}=e;return s?(0,t.jsx)("div",{className:"bg-green-50 border border-green-200 rounded p-4 mb-6",children:(0,t.jsxs)("div",{className:"flex items-center justify-between",children:[(0,t.jsxs)("div",{className:"flex items-center",children:[(0,t.jsx)("div",{className:"flex-shrink-0",children:(0,t.jsx)("svg",{className:"h-5 w-5 text-green-400",viewBox:"0 0 20 20",fill:"currentColor",children:(0,t.jsx)("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z",clipRule:"evenodd"})})}),(0,t.jsx)("div",{className:"ml-3",children:(0,t.jsx)("p",{className:"text-sm font-medium text-green-800",children:s})})]}),r&&(0,t.jsx)("div",{className:"ml-auto pl-3",children:(0,t.jsx)("div",{className:"-mx-1.5 -my-1.5",children:(0,t.jsxs)("button",{type:"button",onClick:r,className:"inline-flex rounded-md bg-green-50 p-1.5 text-green-500 hover:bg-green-100 focus:outline-none focus:ring-2 focus:ring-green-600 focus:ring-offset-2 focus:ring-offset-green-50",children:[(0,t.jsx)("span",{className:"sr-only",children:"Dismiss"}),(0,t.jsx)("svg",{className:"h-5 w-5",viewBox:"0 0 20 20",fill:"currentColor",children:(0,t.jsx)("path",{fillRule:"evenodd",d:"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z",clipRule:"evenodd"})})]})})})]})}):null};function V(){let[e,s]=(0,a.useState)(!1),r=(0,a.useRef)(null),n=(0,E.X)(),[l,o]=(0,a.useState)(!1),[u,p]=(0,a.useState)({username:"",password:"",role:"user"}),[g,b]=(0,a.useState)(!1),[k,C]=(0,a.useState)({open:!1,message:"",userName:""}),[R,D]=(0,a.useState)(null),[S,I]=(0,a.useState)(!1),[L,Z]=(0,a.useState)(!1),[V,A]=(0,a.useState)(!1),[q,M]=(0,a.useState)(null),[B,O]=(0,a.useState)(!1),[K,H]=(0,a.useState)(null),[Y,$]=(0,a.useState)("import"),[X,J]=(0,a.useState)(!1),[W,G]=(0,a.useState)(null),[Q,ee]=(0,a.useState)(""),[es,er]=(0,a.useState)(!1),[et,ea]=(0,a.useState)(null),[en,el]=(0,a.useState)(!1),[ei,eo]=(0,a.useState)(null),[ec,ed]=(0,a.useState)(null),[eu,em]=(0,a.useState)(!1),[ex,ef]=(0,a.useState)(null),[eh,ep]=(0,a.useState)(null),[eg,eb]=(0,a.useState)(void 0);(0,a.useEffect)(()=>{(async function(){try{let e=await U.x.get("/api/health");if(e.ok){let s=await e.json();eb(!!s.basic_auth_enabled)}else eb(!1)}catch(e){eb(!1)}})()},[]),(0,a.useEffect)(()=>{ej().catch(()=>{console.error("Failed to get user role")})},[]);let ej=async()=>{if(R&&Date.now()-R.timestamp<3e5)return R;I(!0);try{let e=await U.x.get("/users/role");if(!e.ok){let s=await e.json();throw Error(s.detail||"Failed to get user role")}let s=await e.json(),r={role:s.role,name:s.name,id:s.id,timestamp:Date.now()};return D(r),I(!1),r}catch(e){throw I(!1),e}},ey=async(e,s)=>{try{let r=await ej();if("admin"!==r.role)return C({open:!0,message:e,userName:r.name.toLowerCase()}),!1;return s(),!0}catch(e){return console.error("Failed to check user role:",e),C({open:!0,message:"Error: ".concat(e.message),userName:""}),!1}},ev=()=>{h.default.invalidate(m.R),h.default.invalidate(x.getClusters),h.default.invalidate(f.getManagedJobs,[{allUsers:!0}]),r.current&&r.current()},eN=async()=>{if(!u.username||!u.password){ep(Error("Username and password are required.")),o(!1);return}b(!0),ep(null),ef(null);try{let e=await U.x.post("/users/create",u);if(!e.ok){let s=await e.json();throw Error(s.detail||"Failed to create user")}ef('User "'.concat(u.username,'" created successfully!')),o(!1),p({username:"",password:"",role:"user"}),ev()}catch(e){ep(e),o(!1),p({username:"",password:"",role:"user"})}finally{b(!1)}},ew=async e=>{let s=e.target.files[0];s&&(M(s),H(null))},ek=async()=>{if(!q){alert("Please select a CSV file first.");return}O(!0);try{let e=new FileReader;e.onload=async e=>{try{let s=e.target.result,r=await U.x.post("/users/import",{csv_content:s});if(!r.ok){let e=await r.json();throw Error(e.detail||"Failed to import users")}let t=await r.json(),a="Import completed. ".concat(t.success_count," users created successfully.");t.error_count>0&&(a+="\n".concat(t.error_count," failed."),t.creation_errors.length>0&&(a+="\nErrors: ".concat(t.creation_errors.slice(0,3).join(", ")),t.creation_errors.length>3&&(a+=" and ".concat(t.creation_errors.length-3," more...")))),H({message:a}),t.success_count>0&&ev()}catch(e){alert("Error importing users: ".concat(e.message))}finally{O(!1)}},e.readAsText(q)}catch(e){alert("Error reading file: ".concat(e.message)),O(!1)}},eC=async e=>{G(e),ee(""),J(!0)},eR=async()=>{if(!Q){ea(Error("Please enter a new password."));return}er(!0),ea(null);try{let e=await U.x.post("/users/update",{user_id:W.userId,password:Q});if(!e.ok){let s=await e.json();throw Error(s.detail||"Failed to reset password")}ef('Password reset successfully for user "'.concat(W.usernameDisplay,'"!')),J(!1),G(null),ee("")}catch(e){ea(e)}finally{er(!1)}},eD=async()=>{if(ei){em(!0),ed(null);try{let e=await U.x.post("/users/delete",{user_id:ei.userId});if(!e.ok){let s=await e.json();throw Error(s.detail||"Failed to delete user")}ef('User "'.concat(ei.usernameDisplay,'" deleted successfully!')),el(!1),eo(null),ev()}catch(e){ed(e)}finally{em(!1)}}},eS=()=>{el(!1),eo(null),ed(null)},eE=()=>{J(!1),G(null),ee(""),ea(null)};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between mb-4 h-5",children:[(0,t.jsx)("div",{className:"text-base",children:(0,t.jsx)(c(),{href:"/users",className:"text-sky-blue hover:underline leading-none",children:"Users"})}),(0,t.jsxs)("div",{className:"flex items-center",children:[e&&(0,t.jsxs)("div",{className:"flex items-center mr-2",children:[(0,t.jsx)(i.Z,{size:15,className:"mt-0"}),(0,t.jsx)("span",{className:"ml-2 text-gray-500 text-sm",children:"Loading..."})]}),eg&&(null==R?void 0:R.role)==="admin"&&(0,t.jsx)("button",{onClick:async()=>{await ey("cannot create users",()=>{o(!0)})},className:"text-sky-blue hover:text-sky-blue-bright flex items-center border-sky-blue rounded px-2 py-1 mr-2",title:"Create New User",children:"+ New User"}),eg&&(null==R?void 0:R.role)==="admin"&&(0,t.jsxs)("button",{onClick:async()=>{await ey("cannot import users",()=>{A(!0)})},className:"text-sky-blue hover:text-sky-blue-bright flex items-center rounded px-2 py-1 mr-2",title:"Import/Export Users",children:[(0,t.jsx)(j.Z,{className:"h-4 w-4 mr-1"}),"Import/Export"]}),(0,t.jsxs)("button",{onClick:ev,disabled:e,className:"text-sky-blue hover:text-sky-blue-bright flex items-center",children:[(0,t.jsx)(y.Z,{className:"h-4 w-4 mr-1.5"}),!n&&(0,t.jsx)("span",{children:"Refresh"})]})]})]}),(0,t.jsx)(T,{message:ex,onDismiss:()=>ef(null)}),(0,t.jsx)(_.X,{error:eh,title:"Error",onDismiss:()=>ep(null)}),(0,t.jsx)(P,{refreshInterval:z,setLoading:s,refreshDataRef:r,checkPermissionAndAct:ey,roleLoading:S,onResetPassword:eC,onDeleteUser:e=>{ey("cannot delete users",()=>{eo(e),el(!0)})},basicAuthEnabled:eg,currentUserRole:null==R?void 0:R.role,currentUserId:null==R?void 0:R.id}),(0,t.jsx)(F.Vq,{open:l,onOpenChange:o,children:(0,t.jsxs)(F.cZ,{className:"sm:max-w-md",children:[(0,t.jsx)(F.fK,{children:(0,t.jsx)(F.$N,{children:"Create User"})}),(0,t.jsxs)("div",{className:"flex flex-col gap-4 py-4",children:[(0,t.jsxs)("div",{className:"grid gap-2",children:[(0,t.jsx)("label",{className:"text-sm font-medium text-gray-700",children:"Username"}),(0,t.jsx)("input",{className:"border rounded px-3 py-2 w-full",placeholder:"Username",value:u.username,onChange:e=>p({...u,username:e.target.value})})]}),(0,t.jsxs)("div",{className:"grid gap-2",children:[(0,t.jsx)("label",{className:"text-sm font-medium text-gray-700",children:"Password"}),(0,t.jsxs)("div",{className:"relative",children:[(0,t.jsx)("input",{className:"border rounded px-3 py-2 w-full pr-10",placeholder:"Password",type:L?"text":"password",value:u.password,onChange:e=>p({...u,password:e.target.value})}),(0,t.jsx)("button",{type:"button",className:"absolute inset-y-0 right-0 pr-3 flex items-center text-gray-400 hover:text-gray-600",onClick:()=>Z(!L),children:L?(0,t.jsx)(v.Z,{className:"h-4 w-4"}):(0,t.jsx)(N.Z,{className:"h-4 w-4"})})]})]}),(0,t.jsxs)("div",{className:"grid gap-2",children:[(0,t.jsx)("label",{className:"text-sm font-medium text-gray-700",children:"Role"}),(0,t.jsxs)("select",{className:"border rounded px-3 py-2 w-full",value:u.role,onChange:e=>p({...u,role:e.target.value}),children:[(0,t.jsx)("option",{value:"user",children:"User"}),(0,t.jsx)("option",{value:"admin",children:"Admin"})]})]})]}),(0,t.jsxs)(F.cN,{children:[(0,t.jsx)("button",{className:"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2",onClick:()=>o(!1),disabled:g,children:"Cancel"}),(0,t.jsx)("button",{className:"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-sky-600 text-white hover:bg-sky-700 h-10 px-4 py-2",onClick:eN,disabled:g,children:g?"Creating...":"Create"})]})]})}),(0,t.jsx)(F.Vq,{open:k.open,onOpenChange:e=>C(s=>({...s,open:e})),children:(0,t.jsxs)(F.cZ,{className:"sm:max-w-md transition-all duration-200 ease-in-out",children:[(0,t.jsxs)(F.fK,{children:[(0,t.jsx)(F.$N,{children:"Permission Denied"}),(0,t.jsx)(F.Be,{children:S?(0,t.jsxs)("div",{className:"flex items-center py-2",children:[(0,t.jsx)(i.Z,{size:16,className:"mr-2"}),(0,t.jsx)("span",{children:"Checking permissions..."})]}):(0,t.jsx)(t.Fragment,{children:k.userName?(0,t.jsxs)(t.Fragment,{children:[k.userName," is logged in as non-admin and ",k.message,"."]}):k.message})})]}),(0,t.jsx)(F.cN,{children:(0,t.jsx)(d.z,{variant:"outline",onClick:()=>C(e=>({...e,open:!1})),disabled:S,children:"OK"})})]})}),(0,t.jsx)(F.Vq,{open:V,onOpenChange:A,children:(0,t.jsxs)(F.cZ,{className:"sm:max-w-lg",children:[(0,t.jsx)(F.fK,{children:(0,t.jsx)(F.$N,{children:"Import/Export Users"})}),(0,t.jsxs)("div",{className:"flex border-b border-gray-200 mb-4",children:[(0,t.jsx)("button",{className:"px-4 py-2 text-sm font-medium ".concat("import"===Y?"border-b-2 border-sky-500 text-sky-600":"text-gray-500 hover:text-gray-700"),onClick:()=>$("import"),children:"Import"}),(0,t.jsx)("button",{className:"px-4 py-2 text-sm font-medium ".concat("export"===Y?"border-b-2 border-sky-500 text-sky-600":"text-gray-500 hover:text-gray-700"),onClick:()=>$("export"),children:"Export"})]}),(0,t.jsx)("div",{className:"flex flex-col gap-4 py-4",children:"import"===Y?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("div",{className:"grid gap-2",children:[(0,t.jsx)("label",{className:"text-sm font-medium text-gray-700",children:"CSV File"}),(0,t.jsx)("input",{type:"file",accept:".csv",onChange:ew,className:"border rounded px-3 py-2 w-full"}),(0,t.jsxs)("p",{className:"text-xs text-gray-500",children:["CSV should have columns: username, password, role",(0,t.jsx)("br",{}),"Supports both plain text passwords and exported password hashes."]})]}),K&&(0,t.jsx)("div",{className:"p-3 bg-green-50 border border-green-200 rounded text-green-700 text-sm",children:K.message})]}):(0,t.jsx)(t.Fragment,{children:(0,t.jsxs)("div",{className:"grid gap-2",children:[(0,t.jsx)("label",{className:"text-sm font-medium text-gray-700",children:"Export Users to CSV"}),(0,t.jsx)("p",{className:"text-xs text-gray-500",children:"Download all users as a CSV file with password hashes."}),(0,t.jsxs)("div",{className:"p-3 bg-amber-50 border border-amber-200 rounded",children:[(0,t.jsx)("p",{className:"text-sm text-amber-700",children:"⚠️ This will export all users with columns: username, password (hashed), role"}),(0,t.jsx)("p",{className:"text-xs text-amber-600 mt-1",children:"Password hashes can be imported directly for system backups."})]})]})})}),(0,t.jsxs)(F.cN,{children:[(0,t.jsx)("button",{className:"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2",onClick:()=>A(!1),disabled:B,children:"Cancel"}),"import"===Y?(0,t.jsx)("button",{className:"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-sky-600 text-white hover:bg-sky-700 h-10 px-4 py-2",onClick:ek,disabled:B||!q,children:B?"Importing...":"Import"}):(0,t.jsxs)("button",{className:"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-sky-600 text-white hover:bg-sky-700 h-10 px-4 py-2",onClick:async()=>{try{let e=await U.x.get("/users/export");if(!e.ok){let s=await e.json();throw Error(s.detail||"Failed to export users")}let s=await e.json(),r=s.csv_content,t=new Blob([r],{type:"text/csv;charset=utf-8;"}),a=URL.createObjectURL(t),n=document.createElement("a");n.href=a;let l=new Date,i=e=>String(e).padStart(2,"0"),o=l.getFullYear(),c=i(l.getMonth()+1),d=i(l.getDate()),u=i(l.getHours()),m=i(l.getMinutes()),x=i(l.getSeconds());n.download="users_export_".concat(o,"-").concat(c,"-").concat(d,"-").concat(u,"-").concat(m,"-").concat(x,".csv"),n.click(),URL.revokeObjectURL(a),alert("Successfully exported ".concat(s.user_count," users to CSV file."))}catch(e){alert("Error exporting users: ".concat(e.message))}},children:[(0,t.jsx)(w.Z,{className:"h-4 w-4 mr-1"}),"Export"]})]})]})}),(0,t.jsx)(F.Vq,{open:X,onOpenChange:eE,children:(0,t.jsxs)(F.cZ,{className:"sm:max-w-md",children:[(0,t.jsxs)(F.fK,{children:[(0,t.jsx)(F.$N,{children:"Reset Password"}),(0,t.jsxs)(F.Be,{children:["Enter a new password for"," ",(null==W?void 0:W.usernameDisplay)||"this user","."]})]}),(0,t.jsx)("div",{className:"flex flex-col gap-4 py-4",children:(0,t.jsxs)("div",{className:"grid gap-2",children:[(0,t.jsx)("label",{className:"text-sm font-medium text-gray-700",children:"New Password"}),(0,t.jsx)("input",{type:"password",className:"border rounded px-3 py-2 w-full",placeholder:"Enter new password",value:Q,onChange:e=>ee(e.target.value),autoFocus:!0})]})}),(0,t.jsx)(_.X,{error:et,title:"Reset Failed",onDismiss:()=>ea(null)}),(0,t.jsxs)(F.cN,{children:[(0,t.jsx)(d.z,{variant:"outline",onClick:eE,disabled:es,children:"Cancel"}),(0,t.jsx)(d.z,{variant:"default",onClick:eR,disabled:es||!Q,className:"bg-sky-600 text-white hover:bg-sky-700",children:es?"Resetting...":"Reset Password"})]})]})}),(0,t.jsx)(F.Vq,{open:en,onOpenChange:eS,children:(0,t.jsxs)(F.cZ,{className:"sm:max-w-md",children:[(0,t.jsxs)(F.fK,{children:[(0,t.jsx)(F.$N,{children:"Delete User"}),(0,t.jsxs)(F.Be,{children:['Are you sure you want to delete user "',(null==ei?void 0:ei.usernameDisplay)||"this user",'"? This action cannot be undone.']})]}),(0,t.jsx)(_.X,{error:ec,title:"Deletion Failed",onDismiss:()=>ed(null)}),(0,t.jsxs)(F.cN,{children:[(0,t.jsx)(d.z,{variant:"outline",onClick:eS,disabled:eu,children:"Cancel"}),(0,t.jsx)(d.z,{variant:"destructive",onClick:eD,disabled:eu,children:eu?"Deleting...":"Delete"})]})]})})]})}function P(e){let{refreshInterval:s,setLoading:r,refreshDataRef:n,checkPermissionAndAct:l,roleLoading:o,onResetPassword:d,onDeleteUser:g,basicAuthEnabled:j,currentUserRole:y,currentUserId:v}=e,[N,w]=(0,a.useState)([]),[E,F]=(0,a.useState)(!0),[_,z]=(0,a.useState)(!1),[T,V]=(0,a.useState)({key:"username",direction:"ascending"}),[P,A]=(0,a.useState)(null),[q,M]=(0,a.useState)(""),B=(0,a.useCallback)(async function(){let e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];r&&e&&r(!0),e&&F(!0);try{let s=await h.default.get(m.R),t=(s||[]).map(e=>({...e,usernameDisplay:L(e.username,e.userId),fullEmailID:Z(e.username,e.userId),clusterCount:-1,jobCount:-1}));w(t),z(!0),r&&e&&r(!1),e&&F(!1);let[a,n]=await Promise.all([h.default.get(x.getClusters),h.default.get(f.getManagedJobs,[{allUsers:!0}])]),l=n.jobs||[],i=(s||[]).map(e=>{let s=(a||[]).filter(s=>s.user_hash===e.userId),r=(l||[]).filter(s=>s.user_hash===e.userId);return{...e,usernameDisplay:L(e.username,e.userId),fullEmailID:Z(e.username,e.userId),clusterCount:s.length,jobCount:r.length}});w(i)}catch(s){console.error("Failed to fetch or process user data:",s),w([]),z(!0),r&&e&&r(!1),e&&F(!1)}},[r]);(0,a.useEffect)(()=>{n&&(n.current=()=>B(!0))},[n,B]),(0,a.useEffect)(()=>{(async()=>{z(!1),F(!0),await p.ZP.preloadForPage("users"),B(!0)})();let e=setInterval(()=>{B(!1)},s);return()=>clearInterval(e)},[B,s]);let O=(0,a.useMemo)(()=>(0,b.R0)(N,T.key,T.direction),[N,T]),K=e=>{let s="ascending";T.key===e&&"ascending"===T.direction&&(s="descending"),V({key:e,direction:s})},H=e=>T.key===e?"ascending"===T.direction?" ↑":" ↓":"",Y=async(e,s)=>{await l("cannot edit user role",()=>{A(e),M(s)})},$=()=>{A(null),M("")},X=async e=>{if(!e||!q){console.error("User ID or role is missing."),alert("Error: User ID or role is missing.");return}F(!0);try{let s=await U.x.post("/users/update",{user_id:e,role:q});if(!s.ok){let e=await s.json();throw Error(e.detail||"Failed to update role")}h.default.invalidate(m.R),await B(!0),$()}catch(e){console.error("Failed to update user role:",e),alert("Error updating role: ".concat(e.message))}finally{F(!1)}};return E&&0===N.length&&!_?(0,t.jsx)("div",{className:"flex justify-center items-center h-64",children:(0,t.jsx)(i.Z,{})}):_?O&&0!==O.length?(0,t.jsx)(I.Zb,{children:(0,t.jsxs)(u.iA,{children:[(0,t.jsx)(u.xD,{children:(0,t.jsxs)(u.SC,{children:[(0,t.jsxs)(u.ss,{onClick:()=>K("usernameDisplay"),className:"sortable whitespace-nowrap cursor-pointer hover:bg-gray-50 w-1/5",children:["Name",H("usernameDisplay")]}),(0,t.jsxs)(u.ss,{onClick:()=>K("fullEmailID"),className:"sortable whitespace-nowrap cursor-pointer hover:bg-gray-50 w-1/5",children:["User ID",H("fullEmailID")]}),(0,t.jsxs)(u.ss,{onClick:()=>K("role"),className:"sortable whitespace-nowrap cursor-pointer hover:bg-gray-50 w-1/5",children:["Role",H("role")]}),(0,t.jsxs)(u.ss,{onClick:()=>K("clusterCount"),className:"sortable whitespace-nowrap cursor-pointer hover:bg-gray-50 w-1/5",children:["Clusters",H("clusterCount")]}),(0,t.jsxs)(u.ss,{onClick:()=>K("jobCount"),className:"sortable whitespace-nowrap cursor-pointer hover:bg-gray-50 w-1/5",children:["Jobs",H("jobCount")]}),j&&(0,t.jsx)(u.ss,{className:"whitespace-nowrap w-1/6",children:"Actions"})]})}),(0,t.jsx)(u.RM,{children:O.map(e=>(0,t.jsxs)(u.SC,{children:[(0,t.jsx)(u.pj,{className:"truncate",title:e.username,children:e.usernameDisplay}),(0,t.jsx)(u.pj,{className:"truncate",title:e.fullEmailID,children:e.fullEmailID}),(0,t.jsx)(u.pj,{className:"truncate",title:e.role,children:(0,t.jsx)("div",{className:"flex items-center gap-2",children:P===e.userId?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("select",{value:q,onChange:e=>M(e.target.value),className:"block w-auto p-1 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-sky-blue focus:border-sky-blue sm:text-sm",children:[(0,t.jsx)("option",{value:"admin",children:"Admin"}),(0,t.jsx)("option",{value:"user",children:"User"})]}),(0,t.jsx)("button",{onClick:()=>X(e.userId),className:"text-green-600 hover:text-green-800 p-1",title:"Save",children:(0,t.jsx)(k.Z,{className:"h-4 w-4"})}),(0,t.jsx)("button",{onClick:$,className:"text-gray-500 hover:text-gray-700 p-1",title:"Cancel",children:(0,t.jsx)(C.Z,{className:"h-4 w-4"})})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"capitalize",children:e.role}),"admin"===y&&(0,t.jsx)("button",{onClick:()=>Y(e.userId,e.role),className:"text-sky-blue hover:text-sky-blue-bright p-1",title:"Edit role",children:(0,t.jsx)(R.Z,{className:"h-3 w-3"})})]})})}),(0,t.jsx)(u.pj,{children:-1===e.clusterCount?(0,t.jsxs)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-400 rounded text-xs font-medium flex items-center",children:[(0,t.jsx)(i.Z,{size:10,className:"mr-1"}),"Loading..."]}):(0,t.jsx)(c(),{href:"/clusters?user=".concat(encodeURIComponent(e.userId)),className:"px-2 py-0.5 rounded text-xs font-medium transition-colors duration-200 cursor-pointer inline-block ".concat(e.clusterCount>0?"bg-blue-100 text-blue-800 hover:bg-blue-200 hover:text-blue-900":"bg-gray-100 text-gray-500 hover:bg-gray-200 hover:text-gray-700"),title:"View ".concat(e.clusterCount," cluster").concat(1!==e.clusterCount?"s":""," for ").concat(e.usernameDisplay),children:e.clusterCount})}),(0,t.jsx)(u.pj,{children:-1===e.jobCount?(0,t.jsxs)("span",{className:"px-2 py-0.5 bg-gray-100 text-gray-400 rounded text-xs font-medium flex items-center",children:[(0,t.jsx)(i.Z,{size:10,className:"mr-1"}),"Loading..."]}):(0,t.jsx)(c(),{href:"/jobs?user=".concat(encodeURIComponent(e.userId)),className:"px-2 py-0.5 rounded text-xs font-medium transition-colors duration-200 cursor-pointer inline-block ".concat(e.jobCount>0?"bg-green-100 text-green-800 hover:bg-green-200 hover:text-green-900":"bg-gray-100 text-gray-500 hover:bg-gray-200 hover:text-gray-700"),title:"View ".concat(e.jobCount," job").concat(1!==e.jobCount?"s":""," for ").concat(e.usernameDisplay),children:e.jobCount})}),j&&(0,t.jsx)(u.pj,{className:"relative",children:(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("button",{onClick:"admin"===y||e.userId===v?async()=>{d(e)}:void 0,className:"admin"===y||e.userId===v?"text-sky-blue hover:text-sky-blue-bright p-1":"text-gray-300 cursor-not-allowed p-1",title:"admin"===y||e.userId===v?"Reset Password":"You can only reset your own password",disabled:"admin"!==y&&e.userId!==v,children:(0,t.jsx)(D.Z,{className:"h-4 w-4"})}),"admin"===y&&(0,t.jsx)("button",{onClick:()=>g(e),className:"text-sky-blue hover:text-red-500 p-1",title:"Delete User",children:(0,t.jsx)(S.Z,{className:"h-4 w-4"})})]})})]},e.userId))})]})}):(0,t.jsxs)("div",{className:"text-center py-12",children:[(0,t.jsx)("p",{className:"text-lg font-semibold text-gray-500",children:"No users found."}),(0,t.jsx)("p",{className:"text-sm text-gray-400 mt-1",children:"There are currently no users to display."})]}):(0,t.jsxs)("div",{className:"flex justify-center items-center h-64",children:[(0,t.jsx)(i.Z,{}),(0,t.jsx)("span",{className:"ml-2 text-gray-500",children:"Loading users..."})]})}P.propTypes={refreshInterval:l().number.isRequired,setLoading:l().func.isRequired,refreshDataRef:l().shape({current:l().func}).isRequired,checkPermissionAndAct:l().func.isRequired,roleLoading:l().bool.isRequired,onResetPassword:l().func.isRequired,onDeleteUser:l().func.isRequired,basicAuthEnabled:l().bool,currentUserRole:l().string,currentUserId:l().string}},4545:function(e,s,r){function t(e){return e.startsWith("sky-jobs-controller-")}function a(e,s,r){return null===s?e:[...e].sort((e,t)=>e[s]<t[s]?"ascending"===r?-1:1:e[s]>t[s]?"ascending"===r?1:-1:0)}r.d(s,{R0:function(){return a},Ym:function(){return t}})}}]);
|