@interware/content-generator 0.7.2 → 0.8.1
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.
- package/dist/_chunks/{App-CTh6owSM.mjs → App-2eX-mcfo.mjs} +2 -2
- package/dist/_chunks/{App-ugsCmlsC.js → App-CvZirjX_.js} +2 -2
- package/dist/_chunks/{ImageStudioTabs-Umf3GODW.mjs → ImageStudioTabs-B6fkCK-o.mjs} +353 -21
- package/dist/_chunks/{ImageStudioTabs-BFEF9ggK.js → ImageStudioTabs-CNktoRax.js} +351 -19
- package/dist/_chunks/{Settings-Sk78JUBS.js → Settings-B-QPodCh.js} +169 -1
- package/dist/_chunks/{Settings-CdGW2O8h.mjs → Settings-CaGruvIm.mjs} +170 -2
- package/dist/_chunks/{StudioApp-DoC0z4eh.js → StudioApp-BDoB31L0.js} +2 -2
- package/dist/_chunks/{StudioApp-CrGn-9Gg.mjs → StudioApp-CF03znuL.mjs} +2 -2
- package/dist/_chunks/{index-D6UAvh53.mjs → index-DlemRDzs.mjs} +3 -3
- package/dist/_chunks/{index-C2s9Jhcc.js → index-DwHGS-BJ.js} +3 -3
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/components/settings/DriveSettings.d.ts +77 -0
- package/dist/admin/src/features/drive/DriveTab.d.ts +42 -0
- package/dist/admin/src/features/image-studio/ImageStudioTabs.d.ts +3 -0
- package/dist/admin/src/features/library/FileCard.d.ts +5 -2
- package/dist/admin/src/features/library/LibraryTab.d.ts +5 -0
- package/dist/admin/src/features/library/driveSync.d.ts +41 -0
- package/dist/admin/src/features/templates/export/templateOrigin.d.ts +10 -0
- package/dist/admin/src/lib/use-cases/drive/index.d.ts +3 -0
- package/dist/server/index.js +1411 -49
- package/dist/server/index.mjs +1409 -47
- package/dist/server/src/bootstrap.d.ts +2 -0
- package/dist/server/src/content-types/drive-link/index.d.ts +62 -0
- package/dist/server/src/content-types/drive-link/schema.d.ts +68 -0
- package/dist/server/src/content-types/drive-op/index.d.ts +46 -0
- package/dist/server/src/content-types/drive-op/schema.d.ts +49 -0
- package/dist/server/src/content-types/index.d.ts +106 -0
- package/dist/server/src/controllers/drive.d.ts +30 -0
- package/dist/server/src/controllers/index.d.ts +130 -0
- package/dist/server/src/drive/client.d.ts +32 -0
- package/dist/server/src/drive/clientConfig.d.ts +27 -0
- package/dist/server/src/drive/common.d.ts +6 -0
- package/dist/server/src/drive/fakes.d.ts +104 -0
- package/dist/server/src/drive/files.d.ts +136 -0
- package/dist/server/src/drive/lifecycles.d.ts +7 -0
- package/dist/server/src/drive/links.d.ts +23 -0
- package/dist/server/src/drive/model.d.ts +99 -0
- package/dist/server/src/drive/oauth.d.ts +47 -0
- package/dist/server/src/drive/pull.d.ts +23 -0
- package/dist/server/src/drive/strapiPorts.d.ts +10 -0
- package/dist/server/src/drive/sync.d.ts +40 -0
- package/dist/server/src/index.d.ts +294 -0
- package/dist/server/src/services/drive.d.ts +141 -0
- package/dist/server/src/services/index.d.ts +55 -0
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const jsxRuntime = require("react/jsx-runtime");
|
|
3
3
|
const designSystem = require("@strapi/design-system");
|
|
4
4
|
const reactRouterDom = require("react-router-dom");
|
|
5
|
-
const index = require("./index-
|
|
5
|
+
const index = require("./index-DwHGS-BJ.js");
|
|
6
6
|
const react = require("react");
|
|
7
7
|
const icons = require("@strapi/icons");
|
|
8
8
|
const styledComponents = require("styled-components");
|
|
@@ -1174,7 +1174,7 @@ const closestRatio = (width, height, ratios) => {
|
|
|
1174
1174
|
};
|
|
1175
1175
|
return ratios.reduce((best, r) => Math.abs(value(r) - target) < Math.abs(value(best) - target) ? r : best);
|
|
1176
1176
|
};
|
|
1177
|
-
const BASE = "/strapi-content-generator-gemini/image-studio";
|
|
1177
|
+
const BASE$2 = "/strapi-content-generator-gemini/image-studio";
|
|
1178
1178
|
const toResult = ({ image, mimeType, model, grounding }) => ({
|
|
1179
1179
|
src: `data:${mimeType};base64,${image}`,
|
|
1180
1180
|
model,
|
|
@@ -1186,7 +1186,7 @@ const errorMessage = (err, fallback) => {
|
|
|
1186
1186
|
};
|
|
1187
1187
|
const createGeneratorApi = (client) => ({
|
|
1188
1188
|
async models() {
|
|
1189
|
-
const { data } = await client.get(`${BASE}/models`);
|
|
1189
|
+
const { data } = await client.get(`${BASE$2}/models`);
|
|
1190
1190
|
return data;
|
|
1191
1191
|
},
|
|
1192
1192
|
async generate(p) {
|
|
@@ -1199,7 +1199,7 @@ const createGeneratorApi = (client) => ({
|
|
|
1199
1199
|
form.append("allowPeople", String(p.allowPeople));
|
|
1200
1200
|
form.append("grounding", String(p.grounding));
|
|
1201
1201
|
p.references.forEach((f) => form.append("references", f, f.name));
|
|
1202
|
-
const { data } = await client.post(`${BASE}/generate`, form);
|
|
1202
|
+
const { data } = await client.post(`${BASE$2}/generate`, form);
|
|
1203
1203
|
return toResult(data);
|
|
1204
1204
|
},
|
|
1205
1205
|
async edit(p) {
|
|
@@ -1212,11 +1212,11 @@ const createGeneratorApi = (client) => ({
|
|
|
1212
1212
|
p.references.forEach((f) => form.append("references", f, f.name));
|
|
1213
1213
|
if (p.aspectRatio) form.append("aspectRatio", p.aspectRatio);
|
|
1214
1214
|
form.append("image", new File([blob], `base.${blob.type.split("/")[1] ?? "png"}`, { type: blob.type }));
|
|
1215
|
-
const { data } = await client.post(`${BASE}/edit`, form);
|
|
1215
|
+
const { data } = await client.post(`${BASE$2}/edit`, form);
|
|
1216
1216
|
return toResult(data);
|
|
1217
1217
|
},
|
|
1218
1218
|
async expand(prompt) {
|
|
1219
|
-
const { data } = await client.post(`${BASE}/expand`, { prompt });
|
|
1219
|
+
const { data } = await client.post(`${BASE$2}/expand`, { prompt });
|
|
1220
1220
|
return data.prompt;
|
|
1221
1221
|
}
|
|
1222
1222
|
});
|
|
@@ -1838,7 +1838,7 @@ const isImage = (f) => (f.mime ?? "").startsWith("image/");
|
|
|
1838
1838
|
const canRemoveBackground = (f) => isImage(f) && f.mime !== "image/svg+xml";
|
|
1839
1839
|
const isGenerated = (f) => (f.caption ?? "").startsWith("AI generated content");
|
|
1840
1840
|
const formatSize = (kb = 0) => kb >= 1024 ? `${(kb / 1024).toFixed(1)} MB` : `${Math.round(kb)} KB`;
|
|
1841
|
-
const FileCard = ({ file, onAction, busy }) => {
|
|
1841
|
+
const FileCard = ({ file, onAction, busy, drive }) => {
|
|
1842
1842
|
const c = useThemeColors();
|
|
1843
1843
|
const thumb2 = file.formats?.thumbnail?.url ?? file.formats?.small?.url ?? file.url;
|
|
1844
1844
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1877,7 +1877,8 @@ const FileCard = ({ file, onAction, busy }) => {
|
|
|
1877
1877
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
|
1878
1878
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: formatSize(file.size) }),
|
|
1879
1879
|
isGenerated(file) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { children: "Generada" }),
|
|
1880
|
-
busy && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { active: true, children: busy })
|
|
1880
|
+
busy && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { active: true, children: busy }),
|
|
1881
|
+
drive?.label && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { variant: drive.tone, title: drive.title, children: drive.label })
|
|
1881
1882
|
] })
|
|
1882
1883
|
] }),
|
|
1883
1884
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { children: [
|
|
@@ -1889,6 +1890,8 @@ const FileCard = ({ file, onAction, busy }) => {
|
|
|
1889
1890
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Item, { onSelect: () => onAction("replace", file), children: "Reemplazar" }),
|
|
1890
1891
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Item, { onSelect: () => onAction("move", file), children: "Mover a…" }),
|
|
1891
1892
|
canRemoveBackground(file) && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Item, { onSelect: () => onAction("removeBackground", file), disabled: !!busy, children: "Quitar fondo" }),
|
|
1893
|
+
drive?.action === "mark" && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Item, { onSelect: () => onAction("syncDrive", file), children: "Sincronizar con Drive" }),
|
|
1894
|
+
drive?.action === "unmark" && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Item, { onSelect: () => onAction("unsyncDrive", file), children: "Dejar de sincronizar" }),
|
|
1892
1895
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Menu.Item, { onSelect: () => onAction("delete", file), variant: "danger", children: "Eliminar" })
|
|
1893
1896
|
] })
|
|
1894
1897
|
] })
|
|
@@ -1897,10 +1900,260 @@ const FileCard = ({ file, onAction, busy }) => {
|
|
|
1897
1900
|
}
|
|
1898
1901
|
);
|
|
1899
1902
|
};
|
|
1903
|
+
const BASE$1 = "/strapi-content-generator-gemini/drive";
|
|
1904
|
+
const FOLDER = "application/vnd.google-apps.folder";
|
|
1905
|
+
const NATIVE_TYPES = {
|
|
1906
|
+
"application/vnd.google-apps.document": "Documento de Google",
|
|
1907
|
+
"application/vnd.google-apps.spreadsheet": "Hoja de cálculo de Google",
|
|
1908
|
+
"application/vnd.google-apps.presentation": "Presentación de Google",
|
|
1909
|
+
"application/vnd.google-apps.form": "Formulario de Google",
|
|
1910
|
+
"application/vnd.google-apps.drawing": "Dibujo de Google",
|
|
1911
|
+
"application/vnd.google-apps.shortcut": "Acceso directo"
|
|
1912
|
+
};
|
|
1913
|
+
const typeLabel = (mime) => {
|
|
1914
|
+
if (mime === FOLDER) return "Carpeta";
|
|
1915
|
+
if (NATIVE_TYPES[mime]) return NATIVE_TYPES[mime];
|
|
1916
|
+
if (mime.startsWith("application/vnd.google-apps.")) return "Archivo de Google";
|
|
1917
|
+
if (mime === "application/pdf") return "PDF";
|
|
1918
|
+
if (mime.startsWith("image/")) return "Imagen";
|
|
1919
|
+
if (mime.startsWith("video/")) return "Video";
|
|
1920
|
+
if (mime.startsWith("audio/")) return "Audio";
|
|
1921
|
+
return "Archivo";
|
|
1922
|
+
};
|
|
1923
|
+
const TypeIcon = ({ mime }) => mime === FOLDER ? /* @__PURE__ */ jsxRuntime.jsx(icons.Folder, { width: 16, height: 16, "aria-hidden": true }) : mime === "application/pdf" ? /* @__PURE__ */ jsxRuntime.jsx(icons.FilePdf, { width: 16, height: 16, "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(icons.File, { width: 16, height: 16, "aria-hidden": true });
|
|
1924
|
+
const formatDate = (iso) => iso ? new Date(iso).toLocaleString("es-MX", { dateStyle: "medium", timeStyle: "short", timeZone: "America/Mexico_City" }) : "—";
|
|
1925
|
+
const confirmText = (item, count) => {
|
|
1926
|
+
const parts = [`«${item.name}» irá a la papelera de Drive, donde se puede recuperar durante 30 días.`];
|
|
1927
|
+
if (item.mimeType === FOLDER && count) {
|
|
1928
|
+
const total = count.files + count.folders;
|
|
1929
|
+
parts.push(
|
|
1930
|
+
total === 0 ? "La carpeta está vacía." : `Contiene ${count.truncated ? "más de " : ""}${total.toLocaleString("es-MX")} ${total === 1 ? "elemento" : "elementos"} (${count.files} archivos y ${count.folders} carpetas), que también se van.`
|
|
1931
|
+
);
|
|
1932
|
+
}
|
|
1933
|
+
if (item.synced || count?.synced) parts.push("Está sincronizado: también se borrará de la Biblioteca del CMS.");
|
|
1934
|
+
return parts.join(" ");
|
|
1935
|
+
};
|
|
1936
|
+
const serverMessage$1 = (error, fallback) => error?.response?.data?.error?.message ?? (error instanceof Error && error.message ? error.message : fallback);
|
|
1937
|
+
const useDriveBrowserApi = () => {
|
|
1938
|
+
const { get, del } = admin.useFetchClient();
|
|
1939
|
+
return react.useMemo(
|
|
1940
|
+
() => ({
|
|
1941
|
+
browse: async (folderId, pageToken) => {
|
|
1942
|
+
try {
|
|
1943
|
+
return (await get(`${BASE$1}/folders/${encodeURIComponent(folderId)}`, { params: pageToken ? { pageToken } : {} })).data;
|
|
1944
|
+
} catch (error) {
|
|
1945
|
+
throw new Error(serverMessage$1(error, "No se pudo leer Google Drive."));
|
|
1946
|
+
}
|
|
1947
|
+
},
|
|
1948
|
+
count: async (id) => (await get(`${BASE$1}/items/${encodeURIComponent(id)}/count`)).data,
|
|
1949
|
+
trash: async (id) => {
|
|
1950
|
+
try {
|
|
1951
|
+
await del(`${BASE$1}/items/${encodeURIComponent(id)}`);
|
|
1952
|
+
} catch (error) {
|
|
1953
|
+
throw new Error(serverMessage$1(error, "No se pudo mandar a la papelera."));
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
}),
|
|
1957
|
+
[get, del]
|
|
1958
|
+
);
|
|
1959
|
+
};
|
|
1960
|
+
const DriveTab = ({ api: injected, notify }) => {
|
|
1961
|
+
const fallbackApi = useDriveBrowserApi();
|
|
1962
|
+
const api = injected ?? fallbackApi;
|
|
1963
|
+
const { toggleNotification } = admin.useNotification();
|
|
1964
|
+
const say = notify ?? ((type, message) => toggleNotification({ type, message }));
|
|
1965
|
+
const [folderId, setFolderId] = react.useState("root");
|
|
1966
|
+
const [page, setPage] = react.useState(null);
|
|
1967
|
+
const [error, setError] = react.useState(null);
|
|
1968
|
+
const [loading2, setLoading] = react.useState(true);
|
|
1969
|
+
const [loadingMore, setLoadingMore] = react.useState(false);
|
|
1970
|
+
const [doomed, setDoomed] = react.useState(null);
|
|
1971
|
+
const load = react.useCallback(async () => {
|
|
1972
|
+
setLoading(true);
|
|
1973
|
+
setError(null);
|
|
1974
|
+
try {
|
|
1975
|
+
setPage(await api.browse(folderId));
|
|
1976
|
+
} catch (err) {
|
|
1977
|
+
setError(err instanceof Error ? err.message : "No se pudo leer Google Drive.");
|
|
1978
|
+
} finally {
|
|
1979
|
+
setLoading(false);
|
|
1980
|
+
}
|
|
1981
|
+
}, [api, folderId]);
|
|
1982
|
+
react.useEffect(() => {
|
|
1983
|
+
load();
|
|
1984
|
+
}, [load]);
|
|
1985
|
+
const more = async () => {
|
|
1986
|
+
if (!page?.nextPageToken) return;
|
|
1987
|
+
setLoadingMore(true);
|
|
1988
|
+
try {
|
|
1989
|
+
const next = await api.browse(folderId, page.nextPageToken);
|
|
1990
|
+
setPage({ ...next, items: [...page.items, ...next.items] });
|
|
1991
|
+
} finally {
|
|
1992
|
+
setLoadingMore(false);
|
|
1993
|
+
}
|
|
1994
|
+
};
|
|
1995
|
+
const askDelete = async (item) => {
|
|
1996
|
+
setDoomed({ item, count: null });
|
|
1997
|
+
if (item.mimeType === FOLDER) {
|
|
1998
|
+
try {
|
|
1999
|
+
const count = await api.count(item.id);
|
|
2000
|
+
setDoomed((d) => d?.item.id === item.id ? { item, count } : d);
|
|
2001
|
+
} catch {
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
};
|
|
2005
|
+
const confirmDelete = async () => {
|
|
2006
|
+
if (!doomed) return;
|
|
2007
|
+
const { item } = doomed;
|
|
2008
|
+
setDoomed(null);
|
|
2009
|
+
try {
|
|
2010
|
+
await api.trash(item.id);
|
|
2011
|
+
say("success", `«${item.name}» se mandó a la papelera de Drive.`);
|
|
2012
|
+
await load();
|
|
2013
|
+
} catch (err) {
|
|
2014
|
+
say("danger", err instanceof Error ? err.message : "No se pudo mandar a la papelera.");
|
|
2015
|
+
}
|
|
2016
|
+
};
|
|
2017
|
+
if (error) return /* @__PURE__ */ jsxRuntime.jsx(EmptyNote, { children: error });
|
|
2018
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
|
|
2019
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { "data-testid": "drive-breadcrumb", gap: 1, alignItems: "center", wrap: "wrap", paddingBottom: 4, children: [
|
|
2020
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "ghost", size: "S", onClick: () => setFolderId("root"), children: "Mi unidad" }),
|
|
2021
|
+
(page?.path ?? []).map((p, i, all) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, alignItems: "center", children: [
|
|
2022
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.ChevronRight, { width: 10, height: 10, "aria-hidden": true }),
|
|
2023
|
+
i === all.length - 1 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: p.name }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "ghost", size: "S", onClick: () => setFolderId(p.id), children: p.name })
|
|
2024
|
+
] }, p.id))
|
|
2025
|
+
] }),
|
|
2026
|
+
loading2 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", padding: 8, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: "Cargando Google Drive…" }) }) : !page?.items.length ? /* @__PURE__ */ jsxRuntime.jsx(EmptyNote, { children: "Esta carpeta de Drive está vacía." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2027
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount: 6, rowCount: page.items.length + 1, children: [
|
|
2028
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
2029
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Nombre" }) }),
|
|
2030
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Tipo" }) }),
|
|
2031
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Modificado" }) }),
|
|
2032
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Tamaño" }) }),
|
|
2033
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: "Estado" }) }),
|
|
2034
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { children: "Acciones" }) })
|
|
2035
|
+
] }) }),
|
|
2036
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: page.items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
2037
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { style: { maxWidth: 420, whiteSpace: "normal" }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
|
|
2038
|
+
/* @__PURE__ */ jsxRuntime.jsx(TypeIcon, { mime: item.mimeType }),
|
|
2039
|
+
item.mimeType === FOLDER ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.TextButton, { onClick: () => setFolderId(item.id), style: { textAlign: "left", height: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", textColor: "neutral800", style: { overflowWrap: "anywhere" }, children: item.name }) }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral800", style: { overflowWrap: "anywhere" }, children: item.name })
|
|
2040
|
+
] }) }),
|
|
2041
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral700", children: typeLabel(item.mimeType) }) }),
|
|
2042
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral700", style: { whiteSpace: "nowrap" }, children: formatDate(item.modifiedTime) }) }),
|
|
2043
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral700", children: item.size === null ? "—" : formatSize(item.size / 1e3) }) }),
|
|
2044
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: item.synced && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { variant: "success", children: "Sincronizado" }) }),
|
|
2045
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, justifyContent: "end", children: [
|
|
2046
|
+
item.webViewLink && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2047
|
+
designSystem.LinkButton,
|
|
2048
|
+
{
|
|
2049
|
+
variant: "tertiary",
|
|
2050
|
+
size: "S",
|
|
2051
|
+
href: item.webViewLink,
|
|
2052
|
+
target: "_blank",
|
|
2053
|
+
rel: "noreferrer noopener",
|
|
2054
|
+
endIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ExternalLink, {}),
|
|
2055
|
+
children: "Abrir en Drive"
|
|
2056
|
+
}
|
|
2057
|
+
),
|
|
2058
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.IconButton, { label: `Eliminar ${item.name}`, variant: "ghost", onClick: () => askDelete(item), children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}) })
|
|
2059
|
+
] }) })
|
|
2060
|
+
] }, item.id)) })
|
|
2061
|
+
] }),
|
|
2062
|
+
page.nextPageToken && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", paddingTop: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", onClick: more, loading: loadingMore, children: "Mostrar más" }) })
|
|
2063
|
+
] }),
|
|
2064
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2065
|
+
ConfirmDialog,
|
|
2066
|
+
{
|
|
2067
|
+
open: !!doomed,
|
|
2068
|
+
title: "¿Mandar a la papelera de Drive?",
|
|
2069
|
+
confirmLabel: "Mandar a la papelera",
|
|
2070
|
+
onClose: () => setDoomed(null),
|
|
2071
|
+
onConfirm: confirmDelete,
|
|
2072
|
+
children: doomed ? confirmText(doomed.item, doomed.count) : ""
|
|
2073
|
+
}
|
|
2074
|
+
)
|
|
2075
|
+
] });
|
|
2076
|
+
};
|
|
2077
|
+
const BASE = "/strapi-content-generator-gemini/drive";
|
|
2078
|
+
const POLL_MS = 1e4;
|
|
2079
|
+
const LABELS = {
|
|
2080
|
+
synced: { label: "Drive", tone: "success" },
|
|
2081
|
+
pending: { label: "Drive: pendiente", tone: "neutral" },
|
|
2082
|
+
error: { label: "Drive: error", tone: "danger" },
|
|
2083
|
+
skipped: { label: "Drive: omitido", tone: "warning" }
|
|
2084
|
+
};
|
|
2085
|
+
const driveView = (links, key, parentInside) => {
|
|
2086
|
+
if (!links?.connected) return null;
|
|
2087
|
+
const item = links.items[key];
|
|
2088
|
+
if (item?.inside) {
|
|
2089
|
+
return { ...LABELS[item.status], title: item.error ?? void 0, action: item.root ? "unmark" : null };
|
|
2090
|
+
}
|
|
2091
|
+
if (parentInside) return { ...LABELS.pending, action: null };
|
|
2092
|
+
return { label: null, tone: "neutral", action: "mark" };
|
|
2093
|
+
};
|
|
2094
|
+
const serverMessage = (error, fallback) => error?.response?.data?.error?.message ?? fallback;
|
|
2095
|
+
const useDriveSync = (watching = false) => {
|
|
2096
|
+
const { get, post, del } = admin.useFetchClient();
|
|
2097
|
+
const [links, setLinks] = react.useState(null);
|
|
2098
|
+
const refresh = react.useCallback(async () => {
|
|
2099
|
+
try {
|
|
2100
|
+
const { data } = await get(`${BASE}/links`);
|
|
2101
|
+
setLinks(data);
|
|
2102
|
+
} catch {
|
|
2103
|
+
setLinks(null);
|
|
2104
|
+
}
|
|
2105
|
+
}, [get]);
|
|
2106
|
+
react.useEffect(() => {
|
|
2107
|
+
refresh();
|
|
2108
|
+
}, [refresh]);
|
|
2109
|
+
const busy = !!links?.connected && (watching || links.pending > 0 || Object.values(links.items).some((i) => i.status === "pending"));
|
|
2110
|
+
react.useEffect(() => {
|
|
2111
|
+
if (!busy) return;
|
|
2112
|
+
const timer = setInterval(refresh, POLL_MS);
|
|
2113
|
+
return () => clearInterval(timer);
|
|
2114
|
+
}, [busy, refresh]);
|
|
2115
|
+
react.useEffect(() => {
|
|
2116
|
+
const onVisible = () => document.visibilityState === "visible" && refresh();
|
|
2117
|
+
document.addEventListener("visibilitychange", onVisible);
|
|
2118
|
+
return () => document.removeEventListener("visibilitychange", onVisible);
|
|
2119
|
+
}, [refresh]);
|
|
2120
|
+
return react.useMemo(
|
|
2121
|
+
() => ({
|
|
2122
|
+
links,
|
|
2123
|
+
refresh,
|
|
2124
|
+
async mark(cmsType, cmsId) {
|
|
2125
|
+
try {
|
|
2126
|
+
await post(`${BASE}/links`, { cmsType, cmsId });
|
|
2127
|
+
} catch (error) {
|
|
2128
|
+
throw new Error(serverMessage(error, "No se pudo sincronizar con Drive."));
|
|
2129
|
+
} finally {
|
|
2130
|
+
await refresh();
|
|
2131
|
+
}
|
|
2132
|
+
},
|
|
2133
|
+
async unmark(cmsType, cmsId) {
|
|
2134
|
+
try {
|
|
2135
|
+
await del(`${BASE}/links/${cmsType}/${cmsId}`);
|
|
2136
|
+
} catch (error) {
|
|
2137
|
+
throw new Error(serverMessage(error, "No se pudo dejar de sincronizar."));
|
|
2138
|
+
} finally {
|
|
2139
|
+
await refresh();
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
}),
|
|
2143
|
+
[links, refresh, post, del]
|
|
2144
|
+
);
|
|
2145
|
+
};
|
|
2146
|
+
const uploadSummary = (total, failed) => {
|
|
2147
|
+
if (failed.length === 0) return { type: "success", message: total === 1 ? "Archivo subido" : `${total} archivos subidos` };
|
|
2148
|
+
if (failed.length === total) return { type: "danger", message: `No se pudo subir: ${failed.join(", ")}.` };
|
|
2149
|
+
return { type: "warning", message: `${total - failed.length} de ${total} archivos subidos. No se pudo subir: ${failed.join(", ")}.` };
|
|
2150
|
+
};
|
|
1900
2151
|
const status = (err) => err?.response?.status ?? err?.status;
|
|
1901
2152
|
const LibraryTab = () => {
|
|
1902
2153
|
const c = useThemeColors();
|
|
1903
2154
|
const { api, notify } = useLibraryApi();
|
|
2155
|
+
const [drivePending, setDrivePending] = react.useState(false);
|
|
2156
|
+
const drive = useDriveSync(drivePending);
|
|
1904
2157
|
const [tree, setTree] = react.useState([]);
|
|
1905
2158
|
const [counts, setCounts] = react.useState({});
|
|
1906
2159
|
const [current, setCurrent] = react.useState(null);
|
|
@@ -1911,7 +2164,10 @@ const LibraryTab = () => {
|
|
|
1911
2164
|
const [dragOver, setDragOver] = react.useState(false);
|
|
1912
2165
|
const [bgBusy, setBgBusy] = react.useState({});
|
|
1913
2166
|
const [bgTarget, setBgTarget] = react.useState(null);
|
|
2167
|
+
const [uploading, setUploading] = react.useState(null);
|
|
1914
2168
|
const uploadInput = react.useRef(null);
|
|
2169
|
+
const currentRef = react.useRef(current);
|
|
2170
|
+
currentRef.current = current;
|
|
1915
2171
|
const replaceInput = react.useRef(null);
|
|
1916
2172
|
const replaceTarget = react.useRef(null);
|
|
1917
2173
|
const path = pathTo(tree, current);
|
|
@@ -1944,7 +2200,20 @@ const LibraryTab = () => {
|
|
|
1944
2200
|
react.useEffect(() => {
|
|
1945
2201
|
loadFiles();
|
|
1946
2202
|
}, [loadFiles]);
|
|
1947
|
-
const refresh = () => Promise.all([loadTree(), loadFiles()]);
|
|
2203
|
+
const refresh = () => Promise.all([loadTree(), loadFiles(), drive.refresh()]);
|
|
2204
|
+
const toggleDrive = async (mode, cmsType, cmsId) => {
|
|
2205
|
+
try {
|
|
2206
|
+
if (mode === "mark") {
|
|
2207
|
+
await drive.mark(cmsType, cmsId);
|
|
2208
|
+
notify("success", "Se sincronizará con Drive en unos segundos.");
|
|
2209
|
+
} else {
|
|
2210
|
+
await drive.unmark(cmsType, cmsId);
|
|
2211
|
+
notify("success", "Dejó de sincronizarse. No se borró nada en Drive ni aquí.");
|
|
2212
|
+
}
|
|
2213
|
+
} catch (err) {
|
|
2214
|
+
notify("danger", err instanceof Error ? err.message : "No se pudo completar la operación con Drive.");
|
|
2215
|
+
}
|
|
2216
|
+
};
|
|
1948
2217
|
const run = async (action, ok) => {
|
|
1949
2218
|
try {
|
|
1950
2219
|
await action();
|
|
@@ -1956,9 +2225,30 @@ const LibraryTab = () => {
|
|
|
1956
2225
|
await refresh();
|
|
1957
2226
|
}
|
|
1958
2227
|
};
|
|
1959
|
-
|
|
2228
|
+
react.useEffect(() => {
|
|
2229
|
+
if (!uploading) return;
|
|
2230
|
+
const warn = (e) => e.preventDefault();
|
|
2231
|
+
window.addEventListener("beforeunload", warn);
|
|
2232
|
+
return () => window.removeEventListener("beforeunload", warn);
|
|
2233
|
+
}, [uploading]);
|
|
2234
|
+
const upload = async (list) => {
|
|
1960
2235
|
const arr = [...list ?? []];
|
|
1961
|
-
if (arr.length
|
|
2236
|
+
if (!arr.length || uploading) return;
|
|
2237
|
+
const folderId = current;
|
|
2238
|
+
const failed = [];
|
|
2239
|
+
for (const [i, file] of arr.entries()) {
|
|
2240
|
+
setUploading({ done: i, total: arr.length, name: file.name });
|
|
2241
|
+
try {
|
|
2242
|
+
const uploaded = await api.uploadFiles([file], folderId);
|
|
2243
|
+
if (currentRef.current === folderId) setFiles((prev) => [...uploaded, ...prev]);
|
|
2244
|
+
} catch {
|
|
2245
|
+
failed.push(file.name);
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
setUploading(null);
|
|
2249
|
+
const { type, message } = uploadSummary(arr.length, failed);
|
|
2250
|
+
notify(type, message);
|
|
2251
|
+
await refresh();
|
|
1962
2252
|
};
|
|
1963
2253
|
const setBgStatus = (file, s) => setBgBusy((b) => {
|
|
1964
2254
|
const next = { ...b };
|
|
@@ -2001,12 +2291,24 @@ const LibraryTab = () => {
|
|
|
2001
2291
|
if (action === "rename") return setDialog({ kind: "renameFile", file });
|
|
2002
2292
|
if (action === "move") return setDialog({ kind: "moveFile", file });
|
|
2003
2293
|
if (action === "delete") return setDialog({ kind: "deleteFile", file });
|
|
2294
|
+
if (action === "syncDrive") return toggleDrive("mark", "file", file.id);
|
|
2295
|
+
if (action === "unsyncDrive") return toggleDrive("unmark", "file", file.id);
|
|
2004
2296
|
};
|
|
2005
2297
|
const validateFolder = (parent, except) => (name) => cleanFolderName(name) !== except && nameTaken(tree, parent, name) ? "Ya existe una carpeta con ese nombre aquí." : null;
|
|
2298
|
+
const pendingShown = (() => {
|
|
2299
|
+
const inside = current !== null && !!drive.links?.items[`folder:${current}`]?.inside;
|
|
2300
|
+
const isPending = (key) => driveView(drive.links, key, inside)?.label === "Drive: pendiente";
|
|
2301
|
+
return files.some((f) => isPending(`file:${f.id}`)) || childrenOf(tree, current).some((f) => isPending(`folder:${f.id}`));
|
|
2302
|
+
})();
|
|
2303
|
+
react.useEffect(() => {
|
|
2304
|
+
setDrivePending(pendingShown);
|
|
2305
|
+
}, [pendingShown]);
|
|
2006
2306
|
if (forbidden) {
|
|
2007
2307
|
return /* @__PURE__ */ jsxRuntime.jsx(EmptyNote, { children: "Para usar la biblioteca necesitas permiso de la Media Library de Strapi. Pídelo a un administrador." });
|
|
2008
2308
|
}
|
|
2009
2309
|
const subfolders = childrenOf(tree, current);
|
|
2310
|
+
const currentInside = current !== null && !!drive.links?.items[`folder:${current}`]?.inside;
|
|
2311
|
+
const folderDrive = current !== null ? driveView(drive.links, `folder:${current}`, !!(folder && path.length > 1 && drive.links?.items[`folder:${path[path.length - 2].id}`]?.inside)) : null;
|
|
2010
2312
|
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, alignItems: "stretch", children: [
|
|
2011
2313
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { width: "280px", shrink: 0, background: "neutral0", padding: 3, hasRadius: true, style: { maxHeight: "calc(100vh - 220px)", overflowY: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2012
2314
|
FolderTree,
|
|
@@ -2028,7 +2330,7 @@ const LibraryTab = () => {
|
|
|
2028
2330
|
hasRadius: true,
|
|
2029
2331
|
position: "relative",
|
|
2030
2332
|
onDragOver: (e) => {
|
|
2031
|
-
if (e.dataTransfer.types.includes("Files")) {
|
|
2333
|
+
if (e.dataTransfer.types.includes("Files") && !uploading) {
|
|
2032
2334
|
e.preventDefault();
|
|
2033
2335
|
setDragOver(true);
|
|
2034
2336
|
}
|
|
@@ -2040,7 +2342,7 @@ const LibraryTab = () => {
|
|
|
2040
2342
|
if (e.dataTransfer.files.length) {
|
|
2041
2343
|
e.preventDefault();
|
|
2042
2344
|
setDragOver(false);
|
|
2043
|
-
upload(e.dataTransfer.files);
|
|
2345
|
+
if (!uploading) upload(e.dataTransfer.files);
|
|
2044
2346
|
}
|
|
2045
2347
|
},
|
|
2046
2348
|
children: [
|
|
@@ -2053,12 +2355,15 @@ const LibraryTab = () => {
|
|
|
2053
2355
|
] }, f.id))
|
|
2054
2356
|
] }),
|
|
2055
2357
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
|
2358
|
+
folder && folderDrive?.label && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { variant: folderDrive.tone, title: folderDrive.title, children: folderDrive.label }),
|
|
2359
|
+
folder && folderDrive?.action === "mark" && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", onClick: () => toggleDrive("mark", "folder", folder.id), children: "Sincronizar con Drive" }),
|
|
2360
|
+
folder && folderDrive?.action === "unmark" && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", onClick: () => toggleDrive("unmark", "folder", folder.id), children: "Dejar de sincronizar" }),
|
|
2056
2361
|
folder && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2057
2362
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {}), onClick: () => setDialog({ kind: "renameFolder" }), children: "Renombrar carpeta" }),
|
|
2058
2363
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "danger-light", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}), onClick: () => setDialog({ kind: "deleteFolder" }), children: "Eliminar carpeta" })
|
|
2059
2364
|
] }),
|
|
2060
2365
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "secondary", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}), onClick: () => setDialog({ kind: "newFolder" }), children: "Nueva carpeta" }),
|
|
2061
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Upload, {}), onClick: () => uploadInput.current?.click(), children: "Subir archivos" })
|
|
2366
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Upload, {}), onClick: () => uploadInput.current?.click(), disabled: !!uploading, loading: !!uploading, children: "Subir archivos" })
|
|
2062
2367
|
] })
|
|
2063
2368
|
] }),
|
|
2064
2369
|
subfolders.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Root, { gap: 2, paddingBottom: 4, children: subfolders.map((f) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, s: 6, xs: 12, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2077,11 +2382,26 @@ const LibraryTab = () => {
|
|
|
2077
2382
|
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
|
|
2078
2383
|
/* @__PURE__ */ jsxRuntime.jsx(icons.Folder, { width: 16, height: 16, "aria-hidden": true }),
|
|
2079
2384
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { ellipsis: true, style: { flex: 1 }, children: f.name }),
|
|
2385
|
+
(() => {
|
|
2386
|
+
const view = driveView(drive.links, `folder:${f.id}`, currentInside);
|
|
2387
|
+
return view?.label ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Badge, { size: "S", variant: view.tone, title: view.title, children: view.label }) : null;
|
|
2388
|
+
})(),
|
|
2080
2389
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: counts[f.id]?.files ?? 0 })
|
|
2081
2390
|
] })
|
|
2082
2391
|
}
|
|
2083
2392
|
) }, f.id)) }),
|
|
2084
|
-
|
|
2393
|
+
uploading && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, marginBottom: 4, hasRadius: true, background: "primary100", borderColor: "primary200", role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
|
2394
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { textColor: "primary700", children: [
|
|
2395
|
+
"Subiendo ",
|
|
2396
|
+
uploading.done + 1,
|
|
2397
|
+
" de ",
|
|
2398
|
+
uploading.total,
|
|
2399
|
+
" · ",
|
|
2400
|
+
uploading.name
|
|
2401
|
+
] }),
|
|
2402
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.ProgressBar, { value: Math.round(uploading.done / uploading.total * 100), children: `${uploading.done} de ${uploading.total} archivos subidos` })
|
|
2403
|
+
] }) }),
|
|
2404
|
+
loading2 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", padding: 8, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: "Cargando archivos…" }) }) : files.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(EmptyNote, { children: subfolders.length ? "No hay archivos sueltos en esta carpeta." : "Carpeta vacía. Arrastra archivos aquí o usa «Subir archivos»." }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Root, { gap: 4, children: files.map((f) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 3, m: 4, s: 6, xs: 12, children: /* @__PURE__ */ jsxRuntime.jsx(FileCard, { file: f, onAction: onFileAction, busy: bgBusy[f.id], drive: driveView(drive.links, `file:${f.id}`, currentInside) }) }, f.id)) }),
|
|
2085
2405
|
dragOver && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { position: "absolute", justifyContent: "center", background: "primary100", hasRadius: true, style: { inset: 0, border: `2px dashed ${c.primary600}`, opacity: 0.95 }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "beta", textColor: "primary700", children: [
|
|
2086
2406
|
"Suelta para subir a «",
|
|
2087
2407
|
folder?.name ?? ROOT_LABEL,
|
|
@@ -2763,6 +3083,15 @@ const editorReducer = (state, action) => {
|
|
|
2763
3083
|
}
|
|
2764
3084
|
}
|
|
2765
3085
|
};
|
|
3086
|
+
const ORIGIN_URL = "/strapi-content-generator-gemini/drive/origin";
|
|
3087
|
+
const recordTemplateOrigin = async (post, files, template) => {
|
|
3088
|
+
for (const file of files) {
|
|
3089
|
+
try {
|
|
3090
|
+
await post(ORIGIN_URL, { fileId: file.id, templateDocumentId: template.documentId ?? template.id, templateName: template.name });
|
|
3091
|
+
} catch {
|
|
3092
|
+
}
|
|
3093
|
+
}
|
|
3094
|
+
};
|
|
2766
3095
|
const useEditorIO = () => {
|
|
2767
3096
|
const { post } = admin.useFetchClient();
|
|
2768
3097
|
const { toggleNotification } = admin.useNotification();
|
|
@@ -2795,7 +3124,8 @@ const useEditorIO = () => {
|
|
|
2795
3124
|
if (!node) return false;
|
|
2796
3125
|
try {
|
|
2797
3126
|
const blob = await renderPiece(node, template, "png");
|
|
2798
|
-
await api.saveBlob(blob, /\.png$/i.test(name) ? name : `${name}.png`, folderId);
|
|
3127
|
+
const saved = await api.saveBlob(blob, /\.png$/i.test(name) ? name : `${name}.png`, folderId);
|
|
3128
|
+
await recordTemplateOrigin((u, body) => post(u, body), saved, template);
|
|
2799
3129
|
toggleNotification({ type: "success", message: "Pieza guardada en la biblioteca." });
|
|
2800
3130
|
return true;
|
|
2801
3131
|
} catch {
|
|
@@ -2803,7 +3133,7 @@ const useEditorIO = () => {
|
|
|
2803
3133
|
return false;
|
|
2804
3134
|
}
|
|
2805
3135
|
},
|
|
2806
|
-
[api, toggleNotification]
|
|
3136
|
+
[api, post, toggleNotification]
|
|
2807
3137
|
);
|
|
2808
3138
|
return { loadImage: loadImage2, exportAs, saveToLibrary };
|
|
2809
3139
|
};
|
|
@@ -5248,7 +5578,8 @@ const TemplatesTab = () => {
|
|
|
5248
5578
|
const STUDIO_TABS = [
|
|
5249
5579
|
{ value: "generator", label: "Generador" },
|
|
5250
5580
|
{ value: "templates", label: "Plantillas" },
|
|
5251
|
-
{ value: "library", label: "Imágenes y documentos" }
|
|
5581
|
+
{ value: "library", label: "Imágenes y documentos" },
|
|
5582
|
+
{ value: "drive", label: "Google Drive" }
|
|
5252
5583
|
];
|
|
5253
5584
|
const PANEL = { height: "100%", overflowY: "auto" };
|
|
5254
5585
|
const isStudioTab = (v) => STUDIO_TABS.some((t) => t.value === v);
|
|
@@ -5276,7 +5607,8 @@ const ImageStudioTabs = () => {
|
|
|
5276
5607
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { flex: "1", style: { minHeight: 0 }, children: [
|
|
5277
5608
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "generator", style: PANEL, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, children: /* @__PURE__ */ jsxRuntime.jsx(GeneratorTab, {}) }) }),
|
|
5278
5609
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "templates", style: PANEL, children: /* @__PURE__ */ jsxRuntime.jsx(TemplatesTab, {}) }),
|
|
5279
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "library", style: PANEL, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, children: /* @__PURE__ */ jsxRuntime.jsx(LibraryTab, {}) }) })
|
|
5610
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "library", style: PANEL, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, children: /* @__PURE__ */ jsxRuntime.jsx(LibraryTab, {}) }) }),
|
|
5611
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "drive", style: PANEL, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, children: tab === "drive" && /* @__PURE__ */ jsxRuntime.jsx(DriveTab, {}) }) })
|
|
5280
5612
|
] })
|
|
5281
5613
|
]
|
|
5282
5614
|
}
|