@strapi/upload 5.52.0 → 5.52.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/admin/future/components/TruncatedText.js +76 -0
- package/dist/admin/future/components/TruncatedText.js.map +1 -0
- package/dist/admin/future/components/TruncatedText.mjs +74 -0
- package/dist/admin/future/components/TruncatedText.mjs.map +1 -0
- package/dist/admin/future/hooks/useTracking.js +57 -0
- package/dist/admin/future/hooks/useTracking.js.map +1 -0
- package/dist/admin/future/hooks/useTracking.mjs +53 -0
- package/dist/admin/future/hooks/useTracking.mjs.map +1 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js +31 -0
- package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
- package/dist/admin/future/pages/Assets/AssetsPage.mjs +31 -0
- package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +9 -6
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +9 -6
- package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +21 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +21 -1
- package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js +3 -4
- package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +4 -5
- package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js +11 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs +11 -1
- package/dist/admin/future/pages/Assets/components/AssetsSearchInput.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.js +6 -4
- package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +6 -4
- package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.js +18 -2
- package/dist/admin/future/pages/Assets/components/FilterMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs +18 -2
- package/dist/admin/future/pages/Assets/components/FilterMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js +9 -7
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs +9 -7
- package/dist/admin/future/pages/Assets/components/FolderActionsMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.js +12 -0
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs +12 -0
- package/dist/admin/future/pages/Assets/components/FolderFormDialog.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js +21 -38
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs +23 -40
- package/dist/admin/future/pages/Assets/components/FolderTree/FolderTree.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.js +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.js.map +1 -1
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs +14 -0
- package/dist/admin/future/pages/Assets/components/SortMenu.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js +5 -0
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.js.map +1 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs +6 -1
- package/dist/admin/future/pages/Assets/hooks/useAssetSelection.mjs.map +1 -1
- package/dist/admin/future/pages/Assets/utils/selection.js +17 -0
- package/dist/admin/future/pages/Assets/utils/selection.js.map +1 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs +17 -1
- package/dist/admin/future/pages/Assets/utils/selection.mjs.map +1 -1
- package/dist/admin/future/services/api.js +7 -8
- package/dist/admin/future/services/api.js.map +1 -1
- package/dist/admin/future/services/api.mjs +7 -8
- package/dist/admin/future/services/api.mjs.map +1 -1
- package/dist/admin/future/services/assets.js +11 -23
- package/dist/admin/future/services/assets.js.map +1 -1
- package/dist/admin/future/services/assets.mjs +11 -23
- package/dist/admin/future/services/assets.mjs.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.js +1 -1
- package/dist/admin/hooks/useAIMetadataJob.js.map +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs +1 -1
- package/dist/admin/hooks/useAIMetadataJob.mjs.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.js +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.js.map +1 -1
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs +2 -2
- package/dist/admin/pages/SettingsPage/SettingsPage.mjs.map +1 -1
- package/dist/admin/src/future/components/TruncatedText.d.ts +32 -0
- package/dist/admin/src/future/hooks/useTracking.d.ts +29 -0
- package/dist/admin/src/future/pages/Assets/components/AssetActionsMenu.d.ts +5 -3
- package/dist/admin/src/future/pages/Assets/components/FolderActionsMenu.d.ts +5 -4
- package/dist/admin/src/future/pages/Assets/hooks/useAssetSelection.d.ts +2 -0
- package/dist/admin/src/future/pages/Assets/utils/selection.d.ts +10 -0
- package/dist/admin/src/future/services/api.d.ts +6 -7
- package/dist/server/controllers/admin-file.js +27 -9
- package/dist/server/controllers/admin-file.js.map +1 -1
- package/dist/server/controllers/admin-file.mjs +27 -9
- package/dist/server/controllers/admin-file.mjs.map +1 -1
- package/dist/server/controllers/admin-upload.js +24 -8
- package/dist/server/controllers/admin-upload.js.map +1 -1
- package/dist/server/controllers/admin-upload.mjs +24 -8
- package/dist/server/controllers/admin-upload.mjs.map +1 -1
- package/dist/server/routes/admin.js +41 -21
- package/dist/server/routes/admin.js.map +1 -1
- package/dist/server/routes/admin.mjs +41 -21
- package/dist/server/routes/admin.mjs.map +1 -1
- package/dist/server/services/ai-metadata.js.map +1 -1
- package/dist/server/services/ai-metadata.mjs.map +1 -1
- package/dist/server/src/controllers/admin-file.d.ts +29 -8
- package/dist/server/src/controllers/admin-file.d.ts.map +1 -1
- package/dist/server/src/controllers/admin-upload.d.ts +20 -4
- package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +4 -4
- package/dist/server/src/index.d.ts +4 -4
- package/dist/server/src/routes/admin.d.ts.map +1 -1
- package/dist/server/src/services/ai-metadata.d.ts +2 -2
- package/dist/server/src/services/ai-metadata.d.ts.map +1 -1
- package/dist/shared/contracts/ai-metadata-jobs.d.ts +10 -32
- package/dist/shared/contracts/ai-metadata-jobs.d.ts.map +1 -1
- package/dist/shared/contracts/files.d.ts +10 -10
- package/dist/shared/contracts/files.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
+
var React = require('react');
|
|
5
|
+
var designSystem = require('@strapi/design-system');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Text that ellipsizes, with a tooltip carrying the full value once it actually
|
|
9
|
+
* does. Used for folder and asset names, which are user-supplied and routinely
|
|
10
|
+
* longer than the column, card or rail holding them.
|
|
11
|
+
*
|
|
12
|
+
* The tooltip is conditional rather than always-on: a permanent tooltip would
|
|
13
|
+
* make every short name hoverable for no reason, and would announce a
|
|
14
|
+
* description that merely repeats the visible text.
|
|
15
|
+
*
|
|
16
|
+
* Whether the text is truncated can't be derived from the string — it depends on
|
|
17
|
+
* the rendered width — so it has to be measured. That measurement happens when
|
|
18
|
+
* the pointer or focus arrives, not at mount.
|
|
19
|
+
*
|
|
20
|
+
* Measuring at mount is the obvious approach and it does not work here. The
|
|
21
|
+
* reading is only correct once the row's width constraint has reached this span,
|
|
22
|
+
* and the tree remounts its rows during first render: the instance that survives
|
|
23
|
+
* can take its one measurement while still unconstrained, conclude it fits, and
|
|
24
|
+
* be stuck there. Nothing corrects it afterwards, because a ResizeObserver on
|
|
25
|
+
* this span never fires again — an ancestor clamps the row, so the text
|
|
26
|
+
* overflows inside a box whose own size stops changing.
|
|
27
|
+
*
|
|
28
|
+
* Reading on hover sidesteps all of that. It is the only moment the answer is
|
|
29
|
+
* needed, the layout is settled by then, and nothing is cached across remounts
|
|
30
|
+
* or resizes that could go stale.
|
|
31
|
+
*/ const TruncatedText = ({ children, ...props })=>{
|
|
32
|
+
const textRef = React.useRef(null);
|
|
33
|
+
const [isTruncated, setIsTruncated] = React.useState(false);
|
|
34
|
+
const checkTruncation = ()=>{
|
|
35
|
+
const el = textRef.current;
|
|
36
|
+
if (el) {
|
|
37
|
+
setIsTruncated(el.scrollWidth > el.clientWidth);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
// A ref callback rather than useRef alone, so the first measurement happens
|
|
41
|
+
// when the node attaches and again whenever it is replaced. The tree remounts
|
|
42
|
+
// its rows during first render, and a value measured against the discarded
|
|
43
|
+
// node would never be revisited — this re-runs against the node that survives.
|
|
44
|
+
const attachRef = (el)=>{
|
|
45
|
+
textRef.current = el;
|
|
46
|
+
if (el) {
|
|
47
|
+
checkTruncation();
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
// The Tooltip stays mounted and the *label* is what's conditional, rather than
|
|
51
|
+
// swapping between a wrapped and unwrapped span. Swapping loses the first
|
|
52
|
+
// hover: the measurement that decides to show a tooltip is itself triggered by
|
|
53
|
+
// the pointer arriving, so the trigger would mount underneath a pointer that
|
|
54
|
+
// has already entered, and Radix — which starts watching at mount — sees no
|
|
55
|
+
// enter event and stays closed until the pointer leaves and returns.
|
|
56
|
+
//
|
|
57
|
+
// With `label` empty the DS Tooltip renders its child as-is and attaches
|
|
58
|
+
// nothing, so untruncated text still costs no DOM node and announces no
|
|
59
|
+
// description duplicating what is already on screen.
|
|
60
|
+
return /*#__PURE__*/ jsxRuntime.jsx(designSystem.Tooltip, {
|
|
61
|
+
label: isTruncated ? children : undefined,
|
|
62
|
+
children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.Typography, {
|
|
63
|
+
ref: attachRef,
|
|
64
|
+
ellipsis: true,
|
|
65
|
+
// Focus is covered as well as hover: the tooltip has to be reachable by
|
|
66
|
+
// keyboard, and these rows are buttons.
|
|
67
|
+
onPointerEnter: checkTruncation,
|
|
68
|
+
onFocus: checkTruncation,
|
|
69
|
+
...props,
|
|
70
|
+
children: children
|
|
71
|
+
})
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
exports.TruncatedText = TruncatedText;
|
|
76
|
+
//# sourceMappingURL=TruncatedText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TruncatedText.js","sources":["../../../../admin/src/future/components/TruncatedText.tsx"],"sourcesContent":["import { useRef, useState } from 'react';\n\nimport { Tooltip, Typography, type TypographyProps } from '@strapi/design-system';\n\ninterface TruncatedTextProps extends Omit<TypographyProps, 'children' | 'ellipsis'> {\n /** The full text. Doubles as the tooltip content once it no longer fits. */\n children: string;\n}\n\n/**\n * Text that ellipsizes, with a tooltip carrying the full value once it actually\n * does. Used for folder and asset names, which are user-supplied and routinely\n * longer than the column, card or rail holding them.\n *\n * The tooltip is conditional rather than always-on: a permanent tooltip would\n * make every short name hoverable for no reason, and would announce a\n * description that merely repeats the visible text.\n *\n * Whether the text is truncated can't be derived from the string — it depends on\n * the rendered width — so it has to be measured. That measurement happens when\n * the pointer or focus arrives, not at mount.\n *\n * Measuring at mount is the obvious approach and it does not work here. The\n * reading is only correct once the row's width constraint has reached this span,\n * and the tree remounts its rows during first render: the instance that survives\n * can take its one measurement while still unconstrained, conclude it fits, and\n * be stuck there. Nothing corrects it afterwards, because a ResizeObserver on\n * this span never fires again — an ancestor clamps the row, so the text\n * overflows inside a box whose own size stops changing.\n *\n * Reading on hover sidesteps all of that. It is the only moment the answer is\n * needed, the layout is settled by then, and nothing is cached across remounts\n * or resizes that could go stale.\n */\nexport const TruncatedText = ({ children, ...props }: TruncatedTextProps) => {\n const textRef = useRef<HTMLSpanElement | null>(null);\n const [isTruncated, setIsTruncated] = useState(false);\n\n const checkTruncation = () => {\n const el = textRef.current;\n\n if (el) {\n setIsTruncated(el.scrollWidth > el.clientWidth);\n }\n };\n\n // A ref callback rather than useRef alone, so the first measurement happens\n // when the node attaches and again whenever it is replaced. The tree remounts\n // its rows during first render, and a value measured against the discarded\n // node would never be revisited — this re-runs against the node that survives.\n const attachRef = (el: HTMLSpanElement | null) => {\n textRef.current = el;\n\n if (el) {\n checkTruncation();\n }\n };\n\n // The Tooltip stays mounted and the *label* is what's conditional, rather than\n // swapping between a wrapped and unwrapped span. Swapping loses the first\n // hover: the measurement that decides to show a tooltip is itself triggered by\n // the pointer arriving, so the trigger would mount underneath a pointer that\n // has already entered, and Radix — which starts watching at mount — sees no\n // enter event and stays closed until the pointer leaves and returns.\n //\n // With `label` empty the DS Tooltip renders its child as-is and attaches\n // nothing, so untruncated text still costs no DOM node and announces no\n // description duplicating what is already on screen.\n return (\n <Tooltip label={isTruncated ? children : undefined}>\n <Typography\n ref={attachRef}\n ellipsis\n // Focus is covered as well as hover: the tooltip has to be reachable by\n // keyboard, and these rows are buttons.\n onPointerEnter={checkTruncation}\n onFocus={checkTruncation}\n {...props}\n >\n {children}\n </Typography>\n </Tooltip>\n );\n};\n"],"names":["TruncatedText","children","props","textRef","useRef","isTruncated","setIsTruncated","useState","checkTruncation","el","current","scrollWidth","clientWidth","attachRef","_jsx","Tooltip","label","undefined","Typography","ref","ellipsis","onPointerEnter","onFocus"],"mappings":";;;;;;AASA;;;;;;;;;;;;;;;;;;;;;;;;UAyBaA,aAAAA,GAAgB,CAAC,EAAEC,QAAQ,EAAE,GAAGC,KAAAA,EAA2B,GAAA;AACtE,IAAA,MAAMC,UAAUC,YAAAA,CAA+B,IAAA,CAAA;AAC/C,IAAA,MAAM,CAACC,WAAAA,EAAaC,cAAAA,CAAe,GAAGC,cAAAA,CAAS,KAAA,CAAA;AAE/C,IAAA,MAAMC,eAAAA,GAAkB,IAAA;QACtB,MAAMC,EAAAA,GAAKN,QAAQO,OAAO;AAE1B,QAAA,IAAID,EAAAA,EAAI;AACNH,YAAAA,cAAAA,CAAeG,EAAAA,CAAGE,WAAW,GAAGF,EAAAA,CAAGG,WAAW,CAAA;AAChD,QAAA;AACF,IAAA,CAAA;;;;;AAMA,IAAA,MAAMC,YAAY,CAACJ,EAAAA,GAAAA;AACjBN,QAAAA,OAAAA,CAAQO,OAAO,GAAGD,EAAAA;AAElB,QAAA,IAAIA,EAAAA,EAAI;AACND,YAAAA,eAAAA,EAAAA;AACF,QAAA;AACF,IAAA,CAAA;;;;;;;;;;;AAYA,IAAA,qBACEM,cAAA,CAACC,oBAAAA,EAAAA;AAAQC,QAAAA,KAAAA,EAAOX,cAAcJ,QAAAA,GAAWgB,SAAAA;AACvC,QAAA,QAAA,gBAAAH,cAAA,CAACI,uBAAAA,EAAAA;YACCC,GAAAA,EAAKN,SAAAA;YACLO,QAAQ,EAAA,IAAA;;;YAGRC,cAAAA,EAAgBb,eAAAA;YAChBc,OAAAA,EAASd,eAAAA;AACR,YAAA,GAAGN,KAAK;AAERD,YAAAA,QAAAA,EAAAA;;;AAIT;;;;"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useRef, useState } from 'react';
|
|
3
|
+
import { Tooltip, Typography } from '@strapi/design-system';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Text that ellipsizes, with a tooltip carrying the full value once it actually
|
|
7
|
+
* does. Used for folder and asset names, which are user-supplied and routinely
|
|
8
|
+
* longer than the column, card or rail holding them.
|
|
9
|
+
*
|
|
10
|
+
* The tooltip is conditional rather than always-on: a permanent tooltip would
|
|
11
|
+
* make every short name hoverable for no reason, and would announce a
|
|
12
|
+
* description that merely repeats the visible text.
|
|
13
|
+
*
|
|
14
|
+
* Whether the text is truncated can't be derived from the string — it depends on
|
|
15
|
+
* the rendered width — so it has to be measured. That measurement happens when
|
|
16
|
+
* the pointer or focus arrives, not at mount.
|
|
17
|
+
*
|
|
18
|
+
* Measuring at mount is the obvious approach and it does not work here. The
|
|
19
|
+
* reading is only correct once the row's width constraint has reached this span,
|
|
20
|
+
* and the tree remounts its rows during first render: the instance that survives
|
|
21
|
+
* can take its one measurement while still unconstrained, conclude it fits, and
|
|
22
|
+
* be stuck there. Nothing corrects it afterwards, because a ResizeObserver on
|
|
23
|
+
* this span never fires again — an ancestor clamps the row, so the text
|
|
24
|
+
* overflows inside a box whose own size stops changing.
|
|
25
|
+
*
|
|
26
|
+
* Reading on hover sidesteps all of that. It is the only moment the answer is
|
|
27
|
+
* needed, the layout is settled by then, and nothing is cached across remounts
|
|
28
|
+
* or resizes that could go stale.
|
|
29
|
+
*/ const TruncatedText = ({ children, ...props })=>{
|
|
30
|
+
const textRef = useRef(null);
|
|
31
|
+
const [isTruncated, setIsTruncated] = useState(false);
|
|
32
|
+
const checkTruncation = ()=>{
|
|
33
|
+
const el = textRef.current;
|
|
34
|
+
if (el) {
|
|
35
|
+
setIsTruncated(el.scrollWidth > el.clientWidth);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
// A ref callback rather than useRef alone, so the first measurement happens
|
|
39
|
+
// when the node attaches and again whenever it is replaced. The tree remounts
|
|
40
|
+
// its rows during first render, and a value measured against the discarded
|
|
41
|
+
// node would never be revisited — this re-runs against the node that survives.
|
|
42
|
+
const attachRef = (el)=>{
|
|
43
|
+
textRef.current = el;
|
|
44
|
+
if (el) {
|
|
45
|
+
checkTruncation();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
// The Tooltip stays mounted and the *label* is what's conditional, rather than
|
|
49
|
+
// swapping between a wrapped and unwrapped span. Swapping loses the first
|
|
50
|
+
// hover: the measurement that decides to show a tooltip is itself triggered by
|
|
51
|
+
// the pointer arriving, so the trigger would mount underneath a pointer that
|
|
52
|
+
// has already entered, and Radix — which starts watching at mount — sees no
|
|
53
|
+
// enter event and stays closed until the pointer leaves and returns.
|
|
54
|
+
//
|
|
55
|
+
// With `label` empty the DS Tooltip renders its child as-is and attaches
|
|
56
|
+
// nothing, so untruncated text still costs no DOM node and announces no
|
|
57
|
+
// description duplicating what is already on screen.
|
|
58
|
+
return /*#__PURE__*/ jsx(Tooltip, {
|
|
59
|
+
label: isTruncated ? children : undefined,
|
|
60
|
+
children: /*#__PURE__*/ jsx(Typography, {
|
|
61
|
+
ref: attachRef,
|
|
62
|
+
ellipsis: true,
|
|
63
|
+
// Focus is covered as well as hover: the tooltip has to be reachable by
|
|
64
|
+
// keyboard, and these rows are buttons.
|
|
65
|
+
onPointerEnter: checkTruncation,
|
|
66
|
+
onFocus: checkTruncation,
|
|
67
|
+
...props,
|
|
68
|
+
children: children
|
|
69
|
+
})
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export { TruncatedText };
|
|
74
|
+
//# sourceMappingURL=TruncatedText.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TruncatedText.mjs","sources":["../../../../admin/src/future/components/TruncatedText.tsx"],"sourcesContent":["import { useRef, useState } from 'react';\n\nimport { Tooltip, Typography, type TypographyProps } from '@strapi/design-system';\n\ninterface TruncatedTextProps extends Omit<TypographyProps, 'children' | 'ellipsis'> {\n /** The full text. Doubles as the tooltip content once it no longer fits. */\n children: string;\n}\n\n/**\n * Text that ellipsizes, with a tooltip carrying the full value once it actually\n * does. Used for folder and asset names, which are user-supplied and routinely\n * longer than the column, card or rail holding them.\n *\n * The tooltip is conditional rather than always-on: a permanent tooltip would\n * make every short name hoverable for no reason, and would announce a\n * description that merely repeats the visible text.\n *\n * Whether the text is truncated can't be derived from the string — it depends on\n * the rendered width — so it has to be measured. That measurement happens when\n * the pointer or focus arrives, not at mount.\n *\n * Measuring at mount is the obvious approach and it does not work here. The\n * reading is only correct once the row's width constraint has reached this span,\n * and the tree remounts its rows during first render: the instance that survives\n * can take its one measurement while still unconstrained, conclude it fits, and\n * be stuck there. Nothing corrects it afterwards, because a ResizeObserver on\n * this span never fires again — an ancestor clamps the row, so the text\n * overflows inside a box whose own size stops changing.\n *\n * Reading on hover sidesteps all of that. It is the only moment the answer is\n * needed, the layout is settled by then, and nothing is cached across remounts\n * or resizes that could go stale.\n */\nexport const TruncatedText = ({ children, ...props }: TruncatedTextProps) => {\n const textRef = useRef<HTMLSpanElement | null>(null);\n const [isTruncated, setIsTruncated] = useState(false);\n\n const checkTruncation = () => {\n const el = textRef.current;\n\n if (el) {\n setIsTruncated(el.scrollWidth > el.clientWidth);\n }\n };\n\n // A ref callback rather than useRef alone, so the first measurement happens\n // when the node attaches and again whenever it is replaced. The tree remounts\n // its rows during first render, and a value measured against the discarded\n // node would never be revisited — this re-runs against the node that survives.\n const attachRef = (el: HTMLSpanElement | null) => {\n textRef.current = el;\n\n if (el) {\n checkTruncation();\n }\n };\n\n // The Tooltip stays mounted and the *label* is what's conditional, rather than\n // swapping between a wrapped and unwrapped span. Swapping loses the first\n // hover: the measurement that decides to show a tooltip is itself triggered by\n // the pointer arriving, so the trigger would mount underneath a pointer that\n // has already entered, and Radix — which starts watching at mount — sees no\n // enter event and stays closed until the pointer leaves and returns.\n //\n // With `label` empty the DS Tooltip renders its child as-is and attaches\n // nothing, so untruncated text still costs no DOM node and announces no\n // description duplicating what is already on screen.\n return (\n <Tooltip label={isTruncated ? children : undefined}>\n <Typography\n ref={attachRef}\n ellipsis\n // Focus is covered as well as hover: the tooltip has to be reachable by\n // keyboard, and these rows are buttons.\n onPointerEnter={checkTruncation}\n onFocus={checkTruncation}\n {...props}\n >\n {children}\n </Typography>\n </Tooltip>\n );\n};\n"],"names":["TruncatedText","children","props","textRef","useRef","isTruncated","setIsTruncated","useState","checkTruncation","el","current","scrollWidth","clientWidth","attachRef","_jsx","Tooltip","label","undefined","Typography","ref","ellipsis","onPointerEnter","onFocus"],"mappings":";;;;AASA;;;;;;;;;;;;;;;;;;;;;;;;UAyBaA,aAAAA,GAAgB,CAAC,EAAEC,QAAQ,EAAE,GAAGC,KAAAA,EAA2B,GAAA;AACtE,IAAA,MAAMC,UAAUC,MAAAA,CAA+B,IAAA,CAAA;AAC/C,IAAA,MAAM,CAACC,WAAAA,EAAaC,cAAAA,CAAe,GAAGC,QAAAA,CAAS,KAAA,CAAA;AAE/C,IAAA,MAAMC,eAAAA,GAAkB,IAAA;QACtB,MAAMC,EAAAA,GAAKN,QAAQO,OAAO;AAE1B,QAAA,IAAID,EAAAA,EAAI;AACNH,YAAAA,cAAAA,CAAeG,EAAAA,CAAGE,WAAW,GAAGF,EAAAA,CAAGG,WAAW,CAAA;AAChD,QAAA;AACF,IAAA,CAAA;;;;;AAMA,IAAA,MAAMC,YAAY,CAACJ,EAAAA,GAAAA;AACjBN,QAAAA,OAAAA,CAAQO,OAAO,GAAGD,EAAAA;AAElB,QAAA,IAAIA,EAAAA,EAAI;AACND,YAAAA,eAAAA,EAAAA;AACF,QAAA;AACF,IAAA,CAAA;;;;;;;;;;;AAYA,IAAA,qBACEM,GAAA,CAACC,OAAAA,EAAAA;AAAQC,QAAAA,KAAAA,EAAOX,cAAcJ,QAAAA,GAAWgB,SAAAA;AACvC,QAAA,QAAA,gBAAAH,GAAA,CAACI,UAAAA,EAAAA;YACCC,GAAAA,EAAKN,SAAAA;YACLO,QAAQ,EAAA,IAAA;;;YAGRC,cAAAA,EAAgBb,eAAAA;YAChBc,OAAAA,EAASd,eAAAA;AACR,YAAA,GAAGN,KAAK;AAERD,YAAAA,QAAAA,EAAAA;;;AAIT;;;;"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var strapiAdmin = require('@strapi/admin/strapi-admin');
|
|
5
|
+
var ee = require('@strapi/admin/strapi-admin/ee');
|
|
6
|
+
var settings = require('../services/settings.js');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Media Library version tag stamped on every event fired from the new
|
|
10
|
+
* (`src/future`) Media Library. Legacy events omit it, so analytics can filter
|
|
11
|
+
* new usage from the old plan while both trees emit the SAME event names (see
|
|
12
|
+
* CMS-246). Bump this if a future revamp ever needs its own bucket.
|
|
13
|
+
*/ const MEDIA_LIBRARY_VERSION = 'v2';
|
|
14
|
+
/**
|
|
15
|
+
* `location` value for every new Media Library event. The new tree is the
|
|
16
|
+
* standalone Media Library page, which the legacy plan tags `'upload'` (as
|
|
17
|
+
* opposed to `'content-manager'` for the asset-picker modal). Kept identical so
|
|
18
|
+
* migrated events line up with the legacy ones on the `location` axis.
|
|
19
|
+
*/ const MEDIA_LIBRARY_LOCATION = 'upload';
|
|
20
|
+
/**
|
|
21
|
+
* Tracking wrapper scoped to the new Media Library. Mirrors the legacy
|
|
22
|
+
* `admin/src/hooks/useTracking` — it forwards to the admin `trackUsage` and
|
|
23
|
+
* injects `isAiMediaLibraryConfigured` when AI is available — and additionally
|
|
24
|
+
* stamps `mediaLibraryVersion` on every event so the migrated plan stays
|
|
25
|
+
* distinguishable from the legacy one.
|
|
26
|
+
*
|
|
27
|
+
* The cast mirrors the legacy wrapper: these two properties are cross-cutting
|
|
28
|
+
* media-tracking metadata that the admin `TrackingEvent` type does not (and
|
|
29
|
+
* should not) enumerate per event.
|
|
30
|
+
*/ const useTracking = ()=>{
|
|
31
|
+
const { trackUsage: trackStrapiUsage } = strapiAdmin.useTracking();
|
|
32
|
+
const { data } = settings.useGetUploadSettingsQuery();
|
|
33
|
+
const isAiAvailable = ee.useAIAvailability();
|
|
34
|
+
// Memoised so consumers can safely list `trackUsage` in effect deps (the
|
|
35
|
+
// search-input debounce commit does) without re-firing every render.
|
|
36
|
+
const trackUsage = React.useCallback((event, properties)=>{
|
|
37
|
+
return trackStrapiUsage(event, {
|
|
38
|
+
...properties,
|
|
39
|
+
...isAiAvailable ? {
|
|
40
|
+
isAiMediaLibraryConfigured: Boolean(data?.data?.aiMetadata)
|
|
41
|
+
} : {},
|
|
42
|
+
mediaLibraryVersion: MEDIA_LIBRARY_VERSION
|
|
43
|
+
});
|
|
44
|
+
}, [
|
|
45
|
+
trackStrapiUsage,
|
|
46
|
+
isAiAvailable,
|
|
47
|
+
data
|
|
48
|
+
]);
|
|
49
|
+
return {
|
|
50
|
+
trackUsage
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
exports.MEDIA_LIBRARY_LOCATION = MEDIA_LIBRARY_LOCATION;
|
|
55
|
+
exports.MEDIA_LIBRARY_VERSION = MEDIA_LIBRARY_VERSION;
|
|
56
|
+
exports.useTracking = useTracking;
|
|
57
|
+
//# sourceMappingURL=useTracking.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTracking.js","sources":["../../../../admin/src/future/hooks/useTracking.ts"],"sourcesContent":["import { useCallback } from 'react';\n\nimport { useTracking as useStrapiTracking, type TrackingEvent } from '@strapi/admin/strapi-admin';\nimport { useAIAvailability } from '@strapi/admin/strapi-admin/ee';\n\nimport { useGetUploadSettingsQuery } from '../services/settings';\n\n/**\n * Media Library version tag stamped on every event fired from the new\n * (`src/future`) Media Library. Legacy events omit it, so analytics can filter\n * new usage from the old plan while both trees emit the SAME event names (see\n * CMS-246). Bump this if a future revamp ever needs its own bucket.\n */\nexport const MEDIA_LIBRARY_VERSION = 'v2';\n\n/**\n * `location` value for every new Media Library event. The new tree is the\n * standalone Media Library page, which the legacy plan tags `'upload'` (as\n * opposed to `'content-manager'` for the asset-picker modal). Kept identical so\n * migrated events line up with the legacy ones on the `location` axis.\n */\nexport const MEDIA_LIBRARY_LOCATION = 'upload';\n\n/**\n * Tracking wrapper scoped to the new Media Library. Mirrors the legacy\n * `admin/src/hooks/useTracking` — it forwards to the admin `trackUsage` and\n * injects `isAiMediaLibraryConfigured` when AI is available — and additionally\n * stamps `mediaLibraryVersion` on every event so the migrated plan stays\n * distinguishable from the legacy one.\n *\n * The cast mirrors the legacy wrapper: these two properties are cross-cutting\n * media-tracking metadata that the admin `TrackingEvent` type does not (and\n * should not) enumerate per event.\n */\nexport const useTracking = () => {\n const { trackUsage: trackStrapiUsage } = useStrapiTracking();\n const { data } = useGetUploadSettingsQuery();\n const isAiAvailable = useAIAvailability();\n\n // Memoised so consumers can safely list `trackUsage` in effect deps (the\n // search-input debounce commit does) without re-firing every render.\n const trackUsage = useCallback(\n <TEvent extends TrackingEvent>(event: TEvent['name'], properties?: TEvent['properties']) => {\n return trackStrapiUsage(event, {\n ...properties,\n ...(isAiAvailable ? { isAiMediaLibraryConfigured: Boolean(data?.data?.aiMetadata) } : {}),\n mediaLibraryVersion: MEDIA_LIBRARY_VERSION,\n } as TEvent['properties']);\n },\n [trackStrapiUsage, isAiAvailable, data]\n );\n\n return { trackUsage };\n};\n"],"names":["MEDIA_LIBRARY_VERSION","MEDIA_LIBRARY_LOCATION","useTracking","trackUsage","trackStrapiUsage","useStrapiTracking","data","useGetUploadSettingsQuery","isAiAvailable","useAIAvailability","useCallback","event","properties","isAiMediaLibraryConfigured","Boolean","aiMetadata","mediaLibraryVersion"],"mappings":";;;;;;;AAOA;;;;;IAMO,MAAMA,qBAAAA,GAAwB;AAErC;;;;;IAMO,MAAMC,sBAAAA,GAAyB;AAEtC;;;;;;;;;;UAWaC,WAAAA,GAAc,IAAA;AACzB,IAAA,MAAM,EAAEC,UAAAA,EAAYC,gBAAgB,EAAE,GAAGC,uBAAAA,EAAAA;IACzC,MAAM,EAAEC,IAAI,EAAE,GAAGC,kCAAAA,EAAAA;AACjB,IAAA,MAAMC,aAAAA,GAAgBC,oBAAAA,EAAAA;;;IAItB,MAAMN,UAAAA,GAAaO,iBAAAA,CACjB,CAA+BC,KAAAA,EAAuBC,UAAAA,GAAAA;AACpD,QAAA,OAAOR,iBAAiBO,KAAAA,EAAO;AAC7B,YAAA,GAAGC,UAAU;AACb,YAAA,GAAIJ,aAAAA,GAAgB;gBAAEK,0BAAAA,EAA4BC,OAAAA,CAAQR,MAAMA,IAAAA,EAAMS,UAAAA;AAAY,aAAA,GAAI,EAAE;YACxFC,mBAAAA,EAAqBhB;AACvB,SAAA,CAAA;IACF,CAAA,EACA;AAACI,QAAAA,gBAAAA;AAAkBI,QAAAA,aAAAA;AAAeF,QAAAA;AAAK,KAAA,CAAA;IAGzC,OAAO;AAAEH,QAAAA;AAAW,KAAA;AACtB;;;;;;"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { useTracking as useTracking$1 } from '@strapi/admin/strapi-admin';
|
|
3
|
+
import { useAIAvailability } from '@strapi/admin/strapi-admin/ee';
|
|
4
|
+
import { useGetUploadSettingsQuery } from '../services/settings.mjs';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Media Library version tag stamped on every event fired from the new
|
|
8
|
+
* (`src/future`) Media Library. Legacy events omit it, so analytics can filter
|
|
9
|
+
* new usage from the old plan while both trees emit the SAME event names (see
|
|
10
|
+
* CMS-246). Bump this if a future revamp ever needs its own bucket.
|
|
11
|
+
*/ const MEDIA_LIBRARY_VERSION = 'v2';
|
|
12
|
+
/**
|
|
13
|
+
* `location` value for every new Media Library event. The new tree is the
|
|
14
|
+
* standalone Media Library page, which the legacy plan tags `'upload'` (as
|
|
15
|
+
* opposed to `'content-manager'` for the asset-picker modal). Kept identical so
|
|
16
|
+
* migrated events line up with the legacy ones on the `location` axis.
|
|
17
|
+
*/ const MEDIA_LIBRARY_LOCATION = 'upload';
|
|
18
|
+
/**
|
|
19
|
+
* Tracking wrapper scoped to the new Media Library. Mirrors the legacy
|
|
20
|
+
* `admin/src/hooks/useTracking` — it forwards to the admin `trackUsage` and
|
|
21
|
+
* injects `isAiMediaLibraryConfigured` when AI is available — and additionally
|
|
22
|
+
* stamps `mediaLibraryVersion` on every event so the migrated plan stays
|
|
23
|
+
* distinguishable from the legacy one.
|
|
24
|
+
*
|
|
25
|
+
* The cast mirrors the legacy wrapper: these two properties are cross-cutting
|
|
26
|
+
* media-tracking metadata that the admin `TrackingEvent` type does not (and
|
|
27
|
+
* should not) enumerate per event.
|
|
28
|
+
*/ const useTracking = ()=>{
|
|
29
|
+
const { trackUsage: trackStrapiUsage } = useTracking$1();
|
|
30
|
+
const { data } = useGetUploadSettingsQuery();
|
|
31
|
+
const isAiAvailable = useAIAvailability();
|
|
32
|
+
// Memoised so consumers can safely list `trackUsage` in effect deps (the
|
|
33
|
+
// search-input debounce commit does) without re-firing every render.
|
|
34
|
+
const trackUsage = useCallback((event, properties)=>{
|
|
35
|
+
return trackStrapiUsage(event, {
|
|
36
|
+
...properties,
|
|
37
|
+
...isAiAvailable ? {
|
|
38
|
+
isAiMediaLibraryConfigured: Boolean(data?.data?.aiMetadata)
|
|
39
|
+
} : {},
|
|
40
|
+
mediaLibraryVersion: MEDIA_LIBRARY_VERSION
|
|
41
|
+
});
|
|
42
|
+
}, [
|
|
43
|
+
trackStrapiUsage,
|
|
44
|
+
isAiAvailable,
|
|
45
|
+
data
|
|
46
|
+
]);
|
|
47
|
+
return {
|
|
48
|
+
trackUsage
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { MEDIA_LIBRARY_LOCATION, MEDIA_LIBRARY_VERSION, useTracking };
|
|
53
|
+
//# sourceMappingURL=useTracking.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTracking.mjs","sources":["../../../../admin/src/future/hooks/useTracking.ts"],"sourcesContent":["import { useCallback } from 'react';\n\nimport { useTracking as useStrapiTracking, type TrackingEvent } from '@strapi/admin/strapi-admin';\nimport { useAIAvailability } from '@strapi/admin/strapi-admin/ee';\n\nimport { useGetUploadSettingsQuery } from '../services/settings';\n\n/**\n * Media Library version tag stamped on every event fired from the new\n * (`src/future`) Media Library. Legacy events omit it, so analytics can filter\n * new usage from the old plan while both trees emit the SAME event names (see\n * CMS-246). Bump this if a future revamp ever needs its own bucket.\n */\nexport const MEDIA_LIBRARY_VERSION = 'v2';\n\n/**\n * `location` value for every new Media Library event. The new tree is the\n * standalone Media Library page, which the legacy plan tags `'upload'` (as\n * opposed to `'content-manager'` for the asset-picker modal). Kept identical so\n * migrated events line up with the legacy ones on the `location` axis.\n */\nexport const MEDIA_LIBRARY_LOCATION = 'upload';\n\n/**\n * Tracking wrapper scoped to the new Media Library. Mirrors the legacy\n * `admin/src/hooks/useTracking` — it forwards to the admin `trackUsage` and\n * injects `isAiMediaLibraryConfigured` when AI is available — and additionally\n * stamps `mediaLibraryVersion` on every event so the migrated plan stays\n * distinguishable from the legacy one.\n *\n * The cast mirrors the legacy wrapper: these two properties are cross-cutting\n * media-tracking metadata that the admin `TrackingEvent` type does not (and\n * should not) enumerate per event.\n */\nexport const useTracking = () => {\n const { trackUsage: trackStrapiUsage } = useStrapiTracking();\n const { data } = useGetUploadSettingsQuery();\n const isAiAvailable = useAIAvailability();\n\n // Memoised so consumers can safely list `trackUsage` in effect deps (the\n // search-input debounce commit does) without re-firing every render.\n const trackUsage = useCallback(\n <TEvent extends TrackingEvent>(event: TEvent['name'], properties?: TEvent['properties']) => {\n return trackStrapiUsage(event, {\n ...properties,\n ...(isAiAvailable ? { isAiMediaLibraryConfigured: Boolean(data?.data?.aiMetadata) } : {}),\n mediaLibraryVersion: MEDIA_LIBRARY_VERSION,\n } as TEvent['properties']);\n },\n [trackStrapiUsage, isAiAvailable, data]\n );\n\n return { trackUsage };\n};\n"],"names":["MEDIA_LIBRARY_VERSION","MEDIA_LIBRARY_LOCATION","useTracking","trackUsage","trackStrapiUsage","useStrapiTracking","data","useGetUploadSettingsQuery","isAiAvailable","useAIAvailability","useCallback","event","properties","isAiMediaLibraryConfigured","Boolean","aiMetadata","mediaLibraryVersion"],"mappings":";;;;;AAOA;;;;;IAMO,MAAMA,qBAAAA,GAAwB;AAErC;;;;;IAMO,MAAMC,sBAAAA,GAAyB;AAEtC;;;;;;;;;;UAWaC,WAAAA,GAAc,IAAA;AACzB,IAAA,MAAM,EAAEC,UAAAA,EAAYC,gBAAgB,EAAE,GAAGC,aAAAA,EAAAA;IACzC,MAAM,EAAEC,IAAI,EAAE,GAAGC,yBAAAA,EAAAA;AACjB,IAAA,MAAMC,aAAAA,GAAgBC,iBAAAA,EAAAA;;;IAItB,MAAMN,UAAAA,GAAaO,WAAAA,CACjB,CAA+BC,KAAAA,EAAuBC,UAAAA,GAAAA;AACpD,QAAA,OAAOR,iBAAiBO,KAAAA,EAAO;AAC7B,YAAA,GAAGC,UAAU;AACb,YAAA,GAAIJ,aAAAA,GAAgB;gBAAEK,0BAAAA,EAA4BC,OAAAA,CAAQR,MAAMA,IAAAA,EAAMS,UAAAA;AAAY,aAAA,GAAI,EAAE;YACxFC,mBAAAA,EAAqBhB;AACvB,SAAA,CAAA;IACF,CAAA,EACA;AAACI,QAAAA,gBAAAA;AAAkBI,QAAAA,aAAAA;AAAeF,QAAAA;AAAK,KAAA,CAAA;IAGzC,OAAO;AAAEH,QAAAA;AAAW,KAAA;AACtB;;;;"}
|
|
@@ -8,9 +8,11 @@ var designSystem = require('@strapi/design-system');
|
|
|
8
8
|
var icons = require('@strapi/icons');
|
|
9
9
|
var reactIntl = require('react-intl');
|
|
10
10
|
var styledComponents = require('styled-components');
|
|
11
|
+
var typeFromMime = require('../../../utils/typeFromMime.js');
|
|
11
12
|
var BetaNotice = require('../../components/BetaNotice.js');
|
|
12
13
|
var useAIMetadataEnabled = require('../../hooks/useAIMetadataEnabled.js');
|
|
13
14
|
var useMediaLibraryPermissions = require('../../hooks/useMediaLibraryPermissions.js');
|
|
15
|
+
var useTracking = require('../../hooks/useTracking.js');
|
|
14
16
|
var api = require('../../services/api.js');
|
|
15
17
|
var folders = require('../../services/folders.js');
|
|
16
18
|
var settings = require('../../services/settings.js');
|
|
@@ -488,8 +490,20 @@ const AssetsPage = ()=>{
|
|
|
488
490
|
// dialog. No mime argument: the files are not known until they are picked,
|
|
489
491
|
// and the server filters the batch on the same allowlist anyway.
|
|
490
492
|
const isAiMetadataEnabled = useAIMetadataEnabled.useAIMetadataEnabled();
|
|
493
|
+
const { trackUsage } = useTracking.useTracking();
|
|
491
494
|
const uploadFilesToFolder = async (files, folderId)=>{
|
|
492
495
|
if (files.length === 0) return;
|
|
496
|
+
// Mirror the legacy `willAddMediaLibraryAssets` payload: the count of files
|
|
497
|
+
// about to upload, broken down by asset type.
|
|
498
|
+
const assetsCountByType = files.reduce((acc, file)=>{
|
|
499
|
+
const type = typeFromMime.typeFromMime(file.type);
|
|
500
|
+
acc[type] = (acc[type] ?? 0) + 1;
|
|
501
|
+
return acc;
|
|
502
|
+
}, {});
|
|
503
|
+
trackUsage('willAddMediaLibraryAssets', {
|
|
504
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION,
|
|
505
|
+
...assetsCountByType
|
|
506
|
+
});
|
|
493
507
|
const formData = new FormData();
|
|
494
508
|
const fileInfoArray = [];
|
|
495
509
|
files.forEach((file)=>{
|
|
@@ -519,6 +533,10 @@ const AssetsPage = ()=>{
|
|
|
519
533
|
const handleFileChange = async (e)=>{
|
|
520
534
|
const files = e.target.files;
|
|
521
535
|
if (files && files.length > 0) {
|
|
536
|
+
trackUsage('didSelectFile', {
|
|
537
|
+
source: 'computer',
|
|
538
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION
|
|
539
|
+
});
|
|
522
540
|
await uploadFilesToFolder(Array.from(files), currentFolderId);
|
|
523
541
|
}
|
|
524
542
|
e.target.value = '';
|
|
@@ -527,9 +545,22 @@ const AssetsPage = ()=>{
|
|
|
527
545
|
// Defence in depth: the provider is `disabled` without `assets.create`
|
|
528
546
|
// (so onDrop won't fire), but guard here too in case it's ever wired live.
|
|
529
547
|
if (!canCreate) return;
|
|
548
|
+
trackUsage('didSelectFile', {
|
|
549
|
+
source: 'computer',
|
|
550
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION
|
|
551
|
+
});
|
|
530
552
|
await uploadFilesToFolder(files, currentFolderId);
|
|
531
553
|
};
|
|
532
554
|
const handleUrlUpload = async (urls)=>{
|
|
555
|
+
trackUsage('didSelectFile', {
|
|
556
|
+
source: 'url',
|
|
557
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION
|
|
558
|
+
});
|
|
559
|
+
// Counts-by-type aren't available client-side for the URL flow (the server
|
|
560
|
+
// fetches the files), so this fires the event with location only.
|
|
561
|
+
trackUsage('willAddMediaLibraryAssets', {
|
|
562
|
+
location: useTracking.MEDIA_LIBRARY_LOCATION
|
|
563
|
+
});
|
|
533
564
|
try {
|
|
534
565
|
await uploadFromUrls({
|
|
535
566
|
urls,
|