Skip to content

Commit 75326aa

Browse files
committed
0.2.0 - add default downloader.
Add the default downloader component `Downloader`. It is implemented by using `StreamSaver.js`.
1 parent b5a6ff5 commit 75326aa

File tree

12 files changed

+504
-32
lines changed

12 files changed

+504
-32
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#### :mega: New
1010

1111
1. Add the Dash component project based on TypeScript. The project contains a `PlainDownloader` component.
12+
2. Add the default downloader component `Downloader`. It is implemented by using `StreamSaver.js`.
1213

1314
#### :floppy_disk: Change
1415

dash_file_cache/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
# Import frequently-used classes.
3434
from .caches import CachePlain, CacheQueue, CacheFile
3535
from .services import ServiceData
36-
from .components import PlainDownloader
36+
from .components import PlainDownloader, Downloader
3737

3838
__all__ = (
3939
"__version__",
@@ -47,6 +47,7 @@
4747
"CacheFile",
4848
"ServiceData",
4949
"PlainDownloader",
50+
"Downloader",
5051
)
5152

5253
_js_dist = []

dash_file_cache/components/__init__.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@
2828
import dash as _dash
2929

3030
# noinspection PyUnresolvedReferences
31-
from ._imports_ import PlainDownloader
31+
from ._imports_ import PlainDownloader, Downloader
3232
from ._imports_ import __all__ as __import_all__
3333

3434

35-
__all__ = ("PlainDownloader",)
35+
__all__ = ("PlainDownloader", "Downloader")
3636

3737
if not hasattr(_dash, "__plotly_dash") and not hasattr(_dash, "development"):
3838
print(
@@ -55,9 +55,7 @@
5555

5656
_this_module = _sys.modules[__name__]
5757

58-
async_resources = [
59-
"PlainDownloader",
60-
]
58+
async_resources = ["PlainDownloader", "Downloader"]
6159

6260
_js_dist = []
6361

@@ -105,7 +103,6 @@
105103

106104
for _component in __import_all__:
107105
_component_obj = locals()[_component]
108-
print(_component_obj.__module__)
109106
setattr(
110107
_component_obj,
111108
"_namespace",

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@
3939
"author": "Yuchen Jin (cainmagi) <cainmagi@gmail.com>",
4040
"license": "MIT",
4141
"dependencies": {
42-
"ramda": "^0.28.0"
42+
"header-case-normalizer": "^1.0.3",
43+
"ramda": "^0.28.0",
44+
"streamsaver": "^2.0.6",
45+
"web-streams-polyfill": "^4.1.0"
4346
},
4447
"devDependencies": {
4548
"@babel/core": "^7.22.1",
@@ -52,6 +55,7 @@
5255
"@types/prop-types": "^15.7.14",
5356
"@types/ramda": "^0.28.0",
5457
"@types/react": "^17.0.2",
58+
"@types/streamsaver": "^2",
5559
"@yarnpkg/types": "^4.0.0",
5660
"babel-eslint": "^10.1.0",
5761
"babel-loader": "^9.1.2",

src/declaration.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ declare module '*.scss' {
77
const content: Record<string, string>;
88
export default content;
99
}
10+
11+
interface Window {
12+
writer: any;
13+
}

src/lib/LazyLoader.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ export const PlainDownloader = React.lazy(() =>
55
/* webpackChunkName: "PlainDownloader" */ "./fragments/PlainDownloader.react"
66
)
77
);
8+
9+
export const Downloader = React.lazy(() =>
10+
import(/* webpackChunkName: "Downloader" */ "./fragments/Downloader.react")
11+
);
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/**
2+
* Downloader (Signature)
3+
*
4+
* The lazy-loaded version with the property definition.
5+
*
6+
* Author: Yuchen Jin (cainmagi)
7+
* GitHub: https://github.com/cainmagi/dash-file-cache
8+
* License: MIT
9+
*/
10+
11+
import React from "react";
12+
import PropTypes, {InferProps} from "prop-types";
13+
import {Downloader as RealComponent} from "../LazyLoader";
14+
15+
/**
16+
* Default values of Downloader.
17+
*/
18+
const defaultProps = {
19+
url: "",
20+
allow_cross_origin: false,
21+
};
22+
23+
/**
24+
* Property types of Downloader.
25+
*/
26+
const propTypes = {
27+
/**
28+
* The ID used to identify this component in Dash callbacks.
29+
*/
30+
id: PropTypes.string,
31+
32+
/**
33+
* The URL used to access the data to be downloaded.
34+
*
35+
* Each time when this value is set, a download event will be triggered. After
36+
* triggering the download event, this value will be reset by a blank string.
37+
*/
38+
url: PropTypes.oneOfType([
39+
PropTypes.string,
40+
PropTypes.exact({
41+
/**
42+
* The URL used to access the data to be downloaded.
43+
*/
44+
url: PropTypes.string.isRequired,
45+
46+
/**
47+
* A maunally configured file name. If this file name is configured, it will
48+
* be used when the file name cannot be parsed in the headers. This configuration
49+
* is useful when the URL is from a cross-origin site.
50+
*/
51+
file_name_fallback: PropTypes.string,
52+
}),
53+
]),
54+
55+
/**
56+
* The extra headers to be used when submitting the request of the downloading
57+
* event.
58+
*
59+
* This property may need to be configured when the downloading event needs to
60+
* add authentication information.
61+
*/
62+
headers: PropTypes.object,
63+
64+
/**
65+
* A flag determineing whether the cross-origin downloading link can be used.
66+
*
67+
* If the data to be downloaded is from a cross-domain site, need to configure this
68+
* value as `True` while the remote site needs to configure the headers
69+
* Access-Control-Allow-Origin
70+
*/
71+
allow_cross_origin: PropTypes.bool,
72+
73+
/**
74+
* The status code when a downloading event is finalized.
75+
*
76+
* If multiple downloading events are triggered by the same downloader, the later
77+
* event will overwrite the status from the former events.
78+
*/
79+
status: PropTypes.exact({
80+
/**
81+
* The status code of the event. If the event is successful, this value should
82+
* be "success" once the downloading event is finalized.
83+
*/
84+
code: PropTypes.oneOf([
85+
"success",
86+
"error-connect",
87+
"error-config",
88+
"error-io",
89+
"error-unknown",
90+
]),
91+
92+
/**
93+
* The HTTP code from the response. If the event is successful, this value should
94+
* be in the range of 200-299.
95+
*/
96+
http_code: PropTypes.number,
97+
}),
98+
99+
/**
100+
* Dash-assigned callback that should be called to report property changes
101+
* to Dash, to make them available for callbacks.
102+
*/
103+
setProps: PropTypes.func,
104+
105+
/**
106+
* Object that holds the loading state object coming from dash-renderer
107+
*/
108+
loading_state: PropTypes.shape({
109+
/**
110+
* Determines if the component is loading or not
111+
*/
112+
is_loading: PropTypes.bool,
113+
/**
114+
* Holds which property is loading
115+
*/
116+
prop_name: PropTypes.string,
117+
/**
118+
* Holds the name of the component that is loading
119+
*/
120+
component_name: PropTypes.string,
121+
}),
122+
};
123+
124+
export type ComponentTypes = InferProps<typeof propTypes>;
125+
126+
/**
127+
* Downloader is a React component based on StreamSaver.
128+
*
129+
* The StreamSaver.js project provides a customizable way to access and download
130+
* an online stream. This is the recommended downloader for practical uses. It has
131+
* the optimized performance for triggering multiple downloading events.
132+
*/
133+
const Downloader = (props: ComponentTypes = defaultProps): JSX.Element => {
134+
return (
135+
<React.Suspense fallback={null}>
136+
<RealComponent {...props} />
137+
</React.Suspense>
138+
);
139+
};
140+
141+
Downloader.propTypes = propTypes;
142+
Downloader.defaultProps = defaultProps;
143+
144+
export default Downloader;

0 commit comments

Comments
 (0)