Spaces:
Runtime error
Runtime error
Charlie
commited on
Commit
·
2fc767f
1
Parent(s):
53475ee
update files
Browse files- dist/main.js +81 -9
- index.html +3 -0
- src/main.ts +106 -8
- styles/main.css +4 -0
dist/main.js
CHANGED
@@ -299,7 +299,46 @@ async function getOrganizationInfo(accessToken) {
|
|
299 |
}
|
300 |
return response.json();
|
301 |
}
|
302 |
-
async function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
const response = await fetch("https://huggingface.co/api/repos/create", {
|
304 |
method: "POST",
|
305 |
headers: {
|
@@ -316,6 +355,15 @@ async function createRepository(accessToken, name, organization) {
|
|
316 |
if (!response.ok) {
|
317 |
throw new Error(`Failed to create repository: ${response.statusText}`);
|
318 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
}
|
320 |
var init = async () => {
|
321 |
await oauthManager.handleRedirect();
|
@@ -332,19 +380,34 @@ var init = async () => {
|
|
332 |
const repoNameInput = document.getElementById(
|
333 |
"repo-name"
|
334 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
if (createRepoButton && repoNameInput) {
|
336 |
createRepoButton.onclick = async () => {
|
337 |
const repoName = repoNameInput.value.trim();
|
338 |
-
const
|
339 |
"org-select"
|
340 |
);
|
341 |
if (repoName) {
|
342 |
try {
|
343 |
-
const selectedOrg =
|
344 |
-
|
345 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
346 |
repoNameInput.value = "";
|
347 |
-
|
|
|
|
|
|
|
348 |
} catch (error) {
|
349 |
console.error("Failed to create repository:", error);
|
350 |
alert("Failed to create repository. Please try again.");
|
@@ -352,11 +415,20 @@ var init = async () => {
|
|
352 |
}
|
353 |
};
|
354 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
355 |
try {
|
356 |
const orgInfo = await getOrganizationInfo(accessToken);
|
357 |
-
const orgSelect = document.getElementById(
|
358 |
-
"org-select"
|
359 |
-
);
|
360 |
if (orgSelect && orgInfo.orgs) {
|
361 |
orgInfo.orgs.forEach((org) => {
|
362 |
const option = document.createElement("option");
|
|
|
299 |
}
|
300 |
return response.json();
|
301 |
}
|
302 |
+
async function getOrganizationMembers(accessToken, organization) {
|
303 |
+
const response = await fetch(
|
304 |
+
`https://huggingface.co/api/organizations/${organization}/members`,
|
305 |
+
{
|
306 |
+
headers: {
|
307 |
+
Authorization: `Bearer ${accessToken}`
|
308 |
+
}
|
309 |
+
}
|
310 |
+
);
|
311 |
+
if (!response.ok) {
|
312 |
+
throw new Error(
|
313 |
+
`Failed to fetch organization members: ${response.statusText}`
|
314 |
+
);
|
315 |
+
}
|
316 |
+
return response.json();
|
317 |
+
}
|
318 |
+
async function createResourceGroup(accessToken, organization, name, members) {
|
319 |
+
const response = await fetch(
|
320 |
+
`https://huggingface.co/api/organizations/${organization}/resource-groups`,
|
321 |
+
{
|
322 |
+
method: "POST",
|
323 |
+
headers: {
|
324 |
+
"Content-Type": "application/json",
|
325 |
+
Authorization: `Bearer ${accessToken}`
|
326 |
+
},
|
327 |
+
body: JSON.stringify({
|
328 |
+
name,
|
329 |
+
description: `Resource group for repository ${name}`,
|
330 |
+
users: members.map((member) => ({
|
331 |
+
user: member.user,
|
332 |
+
role: "admin"
|
333 |
+
}))
|
334 |
+
})
|
335 |
+
}
|
336 |
+
);
|
337 |
+
if (!response.ok) {
|
338 |
+
throw new Error(`Failed to create resource group: ${response.statusText}`);
|
339 |
+
}
|
340 |
+
}
|
341 |
+
async function createRepository(accessToken, name, organization, resourceGroupName) {
|
342 |
const response = await fetch("https://huggingface.co/api/repos/create", {
|
343 |
method: "POST",
|
344 |
headers: {
|
|
|
355 |
if (!response.ok) {
|
356 |
throw new Error(`Failed to create repository: ${response.statusText}`);
|
357 |
}
|
358 |
+
if (organization && resourceGroupName) {
|
359 |
+
const members = await getOrganizationMembers(accessToken, organization);
|
360 |
+
await createResourceGroup(
|
361 |
+
accessToken,
|
362 |
+
organization,
|
363 |
+
resourceGroupName,
|
364 |
+
members
|
365 |
+
);
|
366 |
+
}
|
367 |
}
|
368 |
var init = async () => {
|
369 |
await oauthManager.handleRedirect();
|
|
|
380 |
const repoNameInput = document.getElementById(
|
381 |
"repo-name"
|
382 |
);
|
383 |
+
const resourceGroupInput = document.getElementById(
|
384 |
+
"resource-group-name"
|
385 |
+
);
|
386 |
+
const resourceGroupContainer = document.getElementById(
|
387 |
+
"resource-group-container"
|
388 |
+
);
|
389 |
if (createRepoButton && repoNameInput) {
|
390 |
createRepoButton.onclick = async () => {
|
391 |
const repoName = repoNameInput.value.trim();
|
392 |
+
const orgSelect2 = document.getElementById(
|
393 |
"org-select"
|
394 |
);
|
395 |
if (repoName) {
|
396 |
try {
|
397 |
+
const selectedOrg = orgSelect2?.value || void 0;
|
398 |
+
const resourceGroupName = selectedOrg ? resourceGroupInput?.value.trim() : void 0;
|
399 |
+
console.log({ selectedOrg, resourceGroupName });
|
400 |
+
await createRepository(
|
401 |
+
accessToken,
|
402 |
+
repoName,
|
403 |
+
selectedOrg,
|
404 |
+
resourceGroupName
|
405 |
+
);
|
406 |
repoNameInput.value = "";
|
407 |
+
if (resourceGroupInput) {
|
408 |
+
resourceGroupInput.value = "";
|
409 |
+
}
|
410 |
+
alert("Repository and resource group created successfully!");
|
411 |
} catch (error) {
|
412 |
console.error("Failed to create repository:", error);
|
413 |
alert("Failed to create repository. Please try again.");
|
|
|
415 |
}
|
416 |
};
|
417 |
}
|
418 |
+
const orgSelect = document.getElementById(
|
419 |
+
"org-select"
|
420 |
+
);
|
421 |
+
if (orgSelect && resourceGroupContainer) {
|
422 |
+
orgSelect.onchange = () => {
|
423 |
+
if (orgSelect.value) {
|
424 |
+
resourceGroupContainer.style.removeProperty("display");
|
425 |
+
} else {
|
426 |
+
resourceGroupContainer.style.display = "none";
|
427 |
+
}
|
428 |
+
};
|
429 |
+
}
|
430 |
try {
|
431 |
const orgInfo = await getOrganizationInfo(accessToken);
|
|
|
|
|
|
|
432 |
if (orgSelect && orgInfo.orgs) {
|
433 |
orgInfo.orgs.forEach((org) => {
|
434 |
const option = document.createElement("option");
|
index.html
CHANGED
@@ -20,6 +20,9 @@
|
|
20 |
<option value="">Personal Account</option>
|
21 |
</select>
|
22 |
<input type="text" id="repo-name" placeholder="Enter repository name" class="repo-input">
|
|
|
|
|
|
|
23 |
<button id="create-repo" class="repo-button">Create Repository</button>
|
24 |
</div>
|
25 |
<div id="content">
|
|
|
20 |
<option value="">Personal Account</option>
|
21 |
</select>
|
22 |
<input type="text" id="repo-name" placeholder="Enter repository name" class="repo-input">
|
23 |
+
<div id="resource-group-container" style="display: none;">
|
24 |
+
<input type="text" id="resource-group-name" placeholder="Enter resource group name" class="repo-input">
|
25 |
+
</div>
|
26 |
<button id="create-repo" class="repo-button">Create Repository</button>
|
27 |
</div>
|
28 |
<div id="content">
|
src/main.ts
CHANGED
@@ -17,6 +17,11 @@ interface WhoAmIResponse {
|
|
17 |
orgs: OrganizationInfo[];
|
18 |
}
|
19 |
|
|
|
|
|
|
|
|
|
|
|
20 |
declare const window: HuggingFaceWindow;
|
21 |
|
22 |
console.log("huggingface env", window.huggingface);
|
@@ -39,10 +44,63 @@ async function getOrganizationInfo(
|
|
39 |
return response.json();
|
40 |
}
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
async function createRepository(
|
43 |
accessToken: string,
|
44 |
name: string,
|
45 |
-
organization?: string
|
|
|
46 |
): Promise<void> {
|
47 |
const response = await fetch("https://huggingface.co/api/repos/create", {
|
48 |
method: "POST",
|
@@ -61,6 +119,17 @@ async function createRepository(
|
|
61 |
if (!response.ok) {
|
62 |
throw new Error(`Failed to create repository: ${response.statusText}`);
|
63 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
}
|
65 |
|
66 |
const init = async (): Promise<void> => {
|
@@ -83,6 +152,13 @@ const init = async (): Promise<void> => {
|
|
83 |
const repoNameInput = document.getElementById(
|
84 |
"repo-name"
|
85 |
) as HTMLInputElement;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
if (createRepoButton && repoNameInput) {
|
87 |
createRepoButton.onclick = async () => {
|
88 |
const repoName = repoNameInput.value.trim();
|
@@ -92,11 +168,22 @@ const init = async (): Promise<void> => {
|
|
92 |
if (repoName) {
|
93 |
try {
|
94 |
const selectedOrg = orgSelect?.value || undefined;
|
95 |
-
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
repoNameInput.value = ""; // Clear input after success
|
99 |
-
|
|
|
|
|
|
|
100 |
} catch (error) {
|
101 |
console.error("Failed to create repository:", error);
|
102 |
alert("Failed to create repository. Please try again.");
|
@@ -105,14 +192,25 @@ const init = async (): Promise<void> => {
|
|
105 |
};
|
106 |
}
|
107 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
// Get organization info and populate org select after successful authentication
|
109 |
try {
|
110 |
const orgInfo = await getOrganizationInfo(accessToken);
|
111 |
|
112 |
// Populate org select
|
113 |
-
const orgSelect = document.getElementById(
|
114 |
-
"org-select"
|
115 |
-
) as HTMLSelectElement;
|
116 |
if (orgSelect && orgInfo.orgs) {
|
117 |
orgInfo.orgs.forEach((org) => {
|
118 |
const option = document.createElement("option");
|
|
|
17 |
orgs: OrganizationInfo[];
|
18 |
}
|
19 |
|
20 |
+
interface OrganizationMember {
|
21 |
+
user: string;
|
22 |
+
role: string;
|
23 |
+
}
|
24 |
+
|
25 |
declare const window: HuggingFaceWindow;
|
26 |
|
27 |
console.log("huggingface env", window.huggingface);
|
|
|
44 |
return response.json();
|
45 |
}
|
46 |
|
47 |
+
async function getOrganizationMembers(
|
48 |
+
accessToken: string,
|
49 |
+
organization: string
|
50 |
+
): Promise<OrganizationMember[]> {
|
51 |
+
const response = await fetch(
|
52 |
+
`https://huggingface.co/api/organizations/${organization}/members`,
|
53 |
+
{
|
54 |
+
headers: {
|
55 |
+
Authorization: `Bearer ${accessToken}`,
|
56 |
+
},
|
57 |
+
}
|
58 |
+
);
|
59 |
+
|
60 |
+
if (!response.ok) {
|
61 |
+
throw new Error(
|
62 |
+
`Failed to fetch organization members: ${response.statusText}`
|
63 |
+
);
|
64 |
+
}
|
65 |
+
|
66 |
+
return response.json();
|
67 |
+
}
|
68 |
+
|
69 |
+
async function createResourceGroup(
|
70 |
+
accessToken: string,
|
71 |
+
organization: string,
|
72 |
+
name: string,
|
73 |
+
members: OrganizationMember[]
|
74 |
+
): Promise<void> {
|
75 |
+
const response = await fetch(
|
76 |
+
`https://huggingface.co/api/organizations/${organization}/resource-groups`,
|
77 |
+
{
|
78 |
+
method: "POST",
|
79 |
+
headers: {
|
80 |
+
"Content-Type": "application/json",
|
81 |
+
Authorization: `Bearer ${accessToken}`,
|
82 |
+
},
|
83 |
+
body: JSON.stringify({
|
84 |
+
name: name,
|
85 |
+
description: `Resource group for repository ${name}`,
|
86 |
+
users: members.map((member) => ({
|
87 |
+
user: member.user,
|
88 |
+
role: "admin",
|
89 |
+
})),
|
90 |
+
}),
|
91 |
+
}
|
92 |
+
);
|
93 |
+
|
94 |
+
if (!response.ok) {
|
95 |
+
throw new Error(`Failed to create resource group: ${response.statusText}`);
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
async function createRepository(
|
100 |
accessToken: string,
|
101 |
name: string,
|
102 |
+
organization?: string,
|
103 |
+
resourceGroupName?: string
|
104 |
): Promise<void> {
|
105 |
const response = await fetch("https://huggingface.co/api/repos/create", {
|
106 |
method: "POST",
|
|
|
119 |
if (!response.ok) {
|
120 |
throw new Error(`Failed to create repository: ${response.statusText}`);
|
121 |
}
|
122 |
+
|
123 |
+
// If organization and resource group name are provided, create a resource group
|
124 |
+
if (organization && resourceGroupName) {
|
125 |
+
const members = await getOrganizationMembers(accessToken, organization);
|
126 |
+
await createResourceGroup(
|
127 |
+
accessToken,
|
128 |
+
organization,
|
129 |
+
resourceGroupName,
|
130 |
+
members
|
131 |
+
);
|
132 |
+
}
|
133 |
}
|
134 |
|
135 |
const init = async (): Promise<void> => {
|
|
|
152 |
const repoNameInput = document.getElementById(
|
153 |
"repo-name"
|
154 |
) as HTMLInputElement;
|
155 |
+
const resourceGroupInput = document.getElementById(
|
156 |
+
"resource-group-name"
|
157 |
+
) as HTMLInputElement;
|
158 |
+
const resourceGroupContainer = document.getElementById(
|
159 |
+
"resource-group-container"
|
160 |
+
);
|
161 |
+
|
162 |
if (createRepoButton && repoNameInput) {
|
163 |
createRepoButton.onclick = async () => {
|
164 |
const repoName = repoNameInput.value.trim();
|
|
|
168 |
if (repoName) {
|
169 |
try {
|
170 |
const selectedOrg = orgSelect?.value || undefined;
|
171 |
+
const resourceGroupName = selectedOrg
|
172 |
+
? resourceGroupInput?.value.trim()
|
173 |
+
: undefined;
|
174 |
+
|
175 |
+
console.log({ selectedOrg, resourceGroupName });
|
176 |
+
await createRepository(
|
177 |
+
accessToken,
|
178 |
+
repoName,
|
179 |
+
selectedOrg,
|
180 |
+
resourceGroupName
|
181 |
+
);
|
182 |
repoNameInput.value = ""; // Clear input after success
|
183 |
+
if (resourceGroupInput) {
|
184 |
+
resourceGroupInput.value = ""; // Clear resource group input
|
185 |
+
}
|
186 |
+
alert("Repository and resource group created successfully!");
|
187 |
} catch (error) {
|
188 |
console.error("Failed to create repository:", error);
|
189 |
alert("Failed to create repository. Please try again.");
|
|
|
192 |
};
|
193 |
}
|
194 |
|
195 |
+
// Handle org select change to show/hide resource group input
|
196 |
+
const orgSelect = document.getElementById(
|
197 |
+
"org-select"
|
198 |
+
) as HTMLSelectElement;
|
199 |
+
if (orgSelect && resourceGroupContainer) {
|
200 |
+
orgSelect.onchange = () => {
|
201 |
+
if (orgSelect.value) {
|
202 |
+
resourceGroupContainer.style.removeProperty("display");
|
203 |
+
} else {
|
204 |
+
resourceGroupContainer.style.display = "none";
|
205 |
+
}
|
206 |
+
};
|
207 |
+
}
|
208 |
+
|
209 |
// Get organization info and populate org select after successful authentication
|
210 |
try {
|
211 |
const orgInfo = await getOrganizationInfo(accessToken);
|
212 |
|
213 |
// Populate org select
|
|
|
|
|
|
|
214 |
if (orgSelect && orgInfo.orgs) {
|
215 |
orgInfo.orgs.forEach((org) => {
|
216 |
const option = document.createElement("option");
|
styles/main.css
CHANGED
@@ -61,6 +61,10 @@ h2 {
|
|
61 |
min-width: 200px;
|
62 |
}
|
63 |
|
|
|
|
|
|
|
|
|
64 |
.repo-input {
|
65 |
flex: 1;
|
66 |
padding: 0.8rem;
|
|
|
61 |
min-width: 200px;
|
62 |
}
|
63 |
|
64 |
+
#resource-group-container {
|
65 |
+
width: 100%;
|
66 |
+
}
|
67 |
+
|
68 |
.repo-input {
|
69 |
flex: 1;
|
70 |
padding: 0.8rem;
|