Compare commits
22 Commits
@portaljs/
...
@portaljs/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68fbf2cda6 | ||
|
|
83fd7727ba | ||
|
|
083d3178cd | ||
|
|
3200dc5ade | ||
|
|
32dce434eb | ||
|
|
37ef29d9a2 | ||
|
|
98d62532c5 | ||
|
|
50122cd0cb | ||
|
|
0156e72dd3 | ||
|
|
91217f3256 | ||
|
|
11f9253709 | ||
|
|
c09c78b015 | ||
|
|
4a1ccd2f8d | ||
|
|
728d5b1465 | ||
|
|
a43d4a3b86 | ||
|
|
4bc7ce5ce7 | ||
|
|
8c5c6a2112 | ||
|
|
8e896138c6 | ||
|
|
b2b4fbdf12 | ||
|
|
099f3c5204 | ||
|
|
88ccee6f0a | ||
|
|
3efba6578d |
6
package-lock.json
generated
6
package-lock.json
generated
@@ -46942,7 +46942,7 @@
|
||||
},
|
||||
"packages/ckan": {
|
||||
"name": "@portaljs/ckan",
|
||||
"version": "0.0.3",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"formik": "^2.2.9",
|
||||
"swr": "^2.1.5",
|
||||
@@ -47347,7 +47347,7 @@
|
||||
},
|
||||
"packages/components": {
|
||||
"name": "@portaljs/components",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.2",
|
||||
"dependencies": {
|
||||
"@githubocto/flat-ui": "^0.14.1",
|
||||
"@heroicons/react": "^2.0.17",
|
||||
@@ -47828,7 +47828,7 @@
|
||||
},
|
||||
"packages/remark-wiki-link": {
|
||||
"name": "@portaljs/remark-wiki-link",
|
||||
"version": "1.0.4",
|
||||
"version": "1.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mdast-util-to-markdown": "^1.5.0",
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# @portaljs/ckan
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1018](https://github.com/datopian/portaljs/pull/1018) [`50122cd0`](https://github.com/datopian/portaljs/commit/50122cd0cbbf68bdadc641341279b30b22538cfd) Thanks [@demenech](https://github.com/demenech)! - package_search method now supports custom headers and include_private parameter
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1016](https://github.com/datopian/portaljs/pull/1016) [`91217f32`](https://github.com/datopian/portaljs/commit/91217f325657e2f298b0e632793ae9bb8b08e870) Thanks [@luccasmmg](https://github.com/luccasmmg)! - remove optional from id in resource interface
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1009](https://github.com/datopian/portaljs/pull/1009) [`88ccee6f`](https://github.com/datopian/portaljs/commit/88ccee6f0aa05decd3efbe7279925340ae817127) Thanks [@luccasmmg](https://github.com/luccasmmg)! - added package_count to organization type
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1009](https://github.com/datopian/portaljs/pull/1009) [`099f3c52`](https://github.com/datopian/portaljs/commit/099f3c520407a7215b5b41f67dc8ea5ac73d07c4) Thanks [@luccasmmg](https://github.com/luccasmmg)! - added package_count to organization type
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@portaljs/ckan",
|
||||
"version": "0.0.3",
|
||||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"description": "https://portaljs.org",
|
||||
"keywords": [
|
||||
|
||||
@@ -41,7 +41,7 @@ export interface Resource {
|
||||
description?: string;
|
||||
format?: string;
|
||||
hash?: string;
|
||||
id?: string;
|
||||
id: string;
|
||||
last_modified?: string;
|
||||
metadata_modified?: string;
|
||||
mimetype?: string;
|
||||
@@ -69,6 +69,7 @@ export interface PackageSearchOptions {
|
||||
query?: string;
|
||||
resFormat?: Array<string>;
|
||||
sort?: string;
|
||||
include_private?: boolean;
|
||||
}
|
||||
|
||||
export interface Tag {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Activity } from "./activity.interface";
|
||||
import { Dataset, Tag } from "./dataset.interface";
|
||||
import { User } from "./user.interface";
|
||||
import { Activity } from './activity.interface';
|
||||
import { Dataset, Tag } from './dataset.interface';
|
||||
import { User } from './user.interface';
|
||||
|
||||
export interface Group {
|
||||
display_name: string;
|
||||
@@ -10,9 +10,9 @@ export interface Group {
|
||||
created: string;
|
||||
name: string;
|
||||
is_organization: false;
|
||||
state: "active" | "deleted" | "inactive";
|
||||
state: 'active' | 'deleted' | 'inactive';
|
||||
image_url: string;
|
||||
type: "group";
|
||||
type: 'group';
|
||||
title: string;
|
||||
revision_id: string;
|
||||
num_followers: number;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Activity } from "./activity.interface";
|
||||
import { Dataset, Tag } from "./dataset.interface";
|
||||
import { User } from "./user.interface";
|
||||
import { Activity } from './activity.interface';
|
||||
import { Dataset, Tag } from './dataset.interface';
|
||||
import { User } from './user.interface';
|
||||
|
||||
export interface Organization {
|
||||
id: string;
|
||||
@@ -13,8 +13,9 @@ export interface Organization {
|
||||
image_display_url?: string;
|
||||
created?: string;
|
||||
is_organization: boolean;
|
||||
approval_status?: "approved";
|
||||
state: "active";
|
||||
package_count: number;
|
||||
approval_status?: 'approved';
|
||||
state: 'active';
|
||||
packages?: Array<Dataset>;
|
||||
activity_stream?: Array<Activity>;
|
||||
users?: Array<User>;
|
||||
|
||||
@@ -31,11 +31,7 @@ export default class CKAN {
|
||||
|
||||
async getDatasetsListWithDetails(options: DatasetListQueryOptions) {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/current_package_list_with_resources?offset=${
|
||||
options.offset
|
||||
}&limit=${options.limit}`,
|
||||
`${this.DMS}/api/3/action/current_package_list_with_resources?offset=${options.offset}&limit=${options.limit}`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -44,7 +40,8 @@ export default class CKAN {
|
||||
}
|
||||
|
||||
async packageSearch(
|
||||
options: PackageSearchOptions
|
||||
options: PackageSearchOptions,
|
||||
reqOptions: Partial<RequestInit> = {}
|
||||
): Promise<{ datasets: Dataset[]; count: number }> {
|
||||
function buildGroupsQuery(groups: Array<string>) {
|
||||
if (groups.length > 0) {
|
||||
@@ -99,16 +96,18 @@ export default class CKAN {
|
||||
options.groups,
|
||||
options?.resFormat
|
||||
);
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/package_search?start=${options.offset}&rows=${
|
||||
options.limit
|
||||
}${fq ? fq : ''}${options.query ? '&q=' + options.query : ''}${
|
||||
options.sort ? '&sort=' + options.sort : ''
|
||||
}`,
|
||||
3
|
||||
);
|
||||
|
||||
let url = `${this.DMS}/api/3/action/package_search?`;
|
||||
url += `start=${options.offset}`;
|
||||
url += `&rows=${options.limit}`;
|
||||
url += fq ? fq : '';
|
||||
url += options.query ? '&q=' + options.query : '';
|
||||
url += options.sort ? '&sort=' + options.sort : '';
|
||||
url += options.include_private
|
||||
? '&include_private=' + options.include_private
|
||||
: '';
|
||||
|
||||
const response = await fetchRetry(url, 3, reqOptions);
|
||||
const responseData = await response.json();
|
||||
const datasets: Array<Dataset> = responseData.result.results;
|
||||
return { datasets, count: responseData.result.count };
|
||||
@@ -116,9 +115,7 @@ export default class CKAN {
|
||||
|
||||
async getDatasetDetails(datasetName: string) {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/package_show?id=${datasetName}`,
|
||||
`${this.DMS}/api/3/action/package_show?id=${datasetName}`,
|
||||
1
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -131,9 +128,7 @@ export default class CKAN {
|
||||
|
||||
async getDatasetActivityStream(datasetName: string) {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/package_activity_list?id=${datasetName}`,
|
||||
`${this.DMS}/api/3/action/package_activity_list?id=${datasetName}`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -151,9 +146,7 @@ export default class CKAN {
|
||||
async getUser(userId: string) {
|
||||
try {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/user_show?id=${userId}`,
|
||||
`${this.DMS}/api/3/action/user_show?id=${userId}`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -166,10 +159,7 @@ export default class CKAN {
|
||||
}
|
||||
|
||||
async getGroupList() {
|
||||
const response = await fetchRetry(
|
||||
`${this.DMS}/api/3/action/group_list`,
|
||||
3
|
||||
);
|
||||
const response = await fetchRetry(`${this.DMS}/api/3/action/group_list`, 3);
|
||||
const responseData = await response.json();
|
||||
const groups: Array<string> = responseData.result;
|
||||
return groups;
|
||||
@@ -177,9 +167,7 @@ export default class CKAN {
|
||||
|
||||
async getGroupsWithDetails() {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/group_list?all_fields=True`,
|
||||
`${this.DMS}/api/3/action/group_list?all_fields=True`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -189,9 +177,7 @@ export default class CKAN {
|
||||
|
||||
async getGroupDetails(groupName: string) {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/group_show?id=${groupName}&include_datasets=True`,
|
||||
`${this.DMS}/api/3/action/group_show?id=${groupName}&include_datasets=True`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -201,9 +187,7 @@ export default class CKAN {
|
||||
|
||||
async getGroupActivityStream(groupName: string) {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/group_activity_list?id=${groupName}`,
|
||||
`${this.DMS}/api/3/action/group_activity_list?id=${groupName}`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -230,9 +214,7 @@ export default class CKAN {
|
||||
async getOrgsWithDetails(accrossPages?: boolean) {
|
||||
if (!accrossPages) {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/organization_list?all_fields=True`,
|
||||
`${this.DMS}/api/3/action/organization_list?all_fields=True`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -251,9 +233,7 @@ export default class CKAN {
|
||||
|
||||
for (let i = 0; i < pages; i++) {
|
||||
let allOrgListResponse = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/organization_list?all_fields=True&offset=${
|
||||
`${this.DMS}/api/3/action/organization_list?all_fields=True&offset=${
|
||||
i * 25
|
||||
}&limit=25`,
|
||||
3
|
||||
@@ -267,9 +247,7 @@ export default class CKAN {
|
||||
|
||||
async getOrgDetails(orgName: string) {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/organization_show?id=${orgName}&include_datasets=True`,
|
||||
`${this.DMS}/api/3/action/organization_show?id=${orgName}&include_datasets=True`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -279,9 +257,7 @@ export default class CKAN {
|
||||
|
||||
async getOrgActivityStream(orgName: string) {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/organization_activity_list?id=${orgName}`,
|
||||
`${this.DMS}/api/3/action/organization_activity_list?id=${orgName}`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -297,9 +273,7 @@ export default class CKAN {
|
||||
|
||||
async getAllTags() {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/tag_list?all_fields=True`,
|
||||
`${this.DMS}/api/3/action/tag_list?all_fields=True`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -308,49 +282,41 @@ export default class CKAN {
|
||||
}
|
||||
|
||||
async getResourcesWithAliasList() {
|
||||
const response = await fetch(
|
||||
`${this.DMS}/api/3/action/datastore_search`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: '_table_metadata',
|
||||
limit: '32000',
|
||||
}),
|
||||
}
|
||||
);
|
||||
const response = await fetch(`${this.DMS}/api/3/action/datastore_search`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: '_table_metadata',
|
||||
limit: '32000',
|
||||
}),
|
||||
});
|
||||
const responseData = await response.json();
|
||||
const tableMetadata: Array<TableMetadata> = responseData.result.records;
|
||||
return tableMetadata.filter((item) => item.alias_of);
|
||||
}
|
||||
|
||||
async datastoreSearch(resourceId: string) {
|
||||
const response = await fetch(
|
||||
`${this.DMS}/api/3/action/datastore_search`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: resourceId,
|
||||
limit: '32000',
|
||||
}),
|
||||
}
|
||||
);
|
||||
const response = await fetch(`${this.DMS}/api/3/action/datastore_search`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id: resourceId,
|
||||
limit: '32000',
|
||||
}),
|
||||
});
|
||||
const responseData = await response.json();
|
||||
return responseData.result.records;
|
||||
}
|
||||
|
||||
async getResourceMetadata(resourceId: string) {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/resource_show?id=${resourceId}`,
|
||||
`${this.DMS}/api/3/action/resource_show?id=${resourceId}`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
@@ -359,17 +325,14 @@ export default class CKAN {
|
||||
}
|
||||
|
||||
async getResourceInfo(resourceId: string) {
|
||||
const response = await fetch(
|
||||
`${this.DMS}/api/3/action/datastore_info`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ resource_id: resourceId }),
|
||||
}
|
||||
);
|
||||
const response = await fetch(`${this.DMS}/api/3/action/datastore_info`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ resource_id: resourceId }),
|
||||
});
|
||||
const responseData = await response.json();
|
||||
const resourceInfo: Array<ResourceInfo> = responseData.result;
|
||||
return resourceInfo;
|
||||
@@ -377,9 +340,7 @@ export default class CKAN {
|
||||
|
||||
async getFacetFields(field: 'res_format' | 'tags') {
|
||||
const response = await fetchRetry(
|
||||
`${
|
||||
this.DMS
|
||||
}/api/3/action/package_search?facet.field=["${field}"]&rows=0`,
|
||||
`${this.DMS}/api/3/action/package_search?facet.field=["${field}"]&rows=0`,
|
||||
3
|
||||
);
|
||||
const responseData = await response.json();
|
||||
|
||||
@@ -9,10 +9,14 @@ export function getDaysAgo(date: string) {
|
||||
return (+today - +createdOn) / msInDay;
|
||||
}
|
||||
|
||||
export default async function fetchRetry(url: string, n: number): Promise<any> {
|
||||
export default async function fetchRetry(
|
||||
url: string,
|
||||
n: number,
|
||||
opts: Partial<RequestInit> = {}
|
||||
): Promise<any> {
|
||||
const abortController = new AbortController();
|
||||
const id = setTimeout(() => abortController.abort(), 30000);
|
||||
const res = await fetch(url, { signal: abortController.signal });
|
||||
const res = await fetch(url, { signal: abortController.signal, ...opts });
|
||||
clearTimeout(id);
|
||||
if (!res.ok && n && n > 0) {
|
||||
return await fetchRetry(url, n - 1);
|
||||
@@ -21,13 +25,13 @@ export default async function fetchRetry(url: string, n: number): Promise<any> {
|
||||
}
|
||||
|
||||
export function removeTag(tag?: string) {
|
||||
if (tag === "{{description}}" || !tag) {
|
||||
if (tag === '{{description}}' || !tag) {
|
||||
return undefined;
|
||||
}
|
||||
if (typeof window !== "undefined") {
|
||||
const div = document.createElement("div");
|
||||
if (typeof window !== 'undefined') {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = tag;
|
||||
return div.textContent || div.innerText || "";
|
||||
return div.textContent || div.innerText || '';
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
@@ -38,10 +42,10 @@ export function convertFieldSchema(
|
||||
) {
|
||||
function convertToGraphqlString(fieldName: string) {
|
||||
return fieldName
|
||||
.replaceAll(" ", "_")
|
||||
.replaceAll("(", "_")
|
||||
.replaceAll(")", "_")
|
||||
.replace(/[^\w\s]|(_)\1/gi, "_");
|
||||
.replaceAll(' ', '_')
|
||||
.replaceAll('(', '_')
|
||||
.replaceAll(')', '_')
|
||||
.replace(/[^\w\s]|(_)\1/gi, '_');
|
||||
}
|
||||
const entries = Object.entries(schema);
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @portaljs/components
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1022](https://github.com/datopian/portaljs/pull/1022) [`83fd7727`](https://github.com/datopian/portaljs/commit/83fd7727bafb4902218777597e9848a3e3a71d87) Thanks [@luccasmmg](https://github.com/luccasmmg)! - FlatUiTables now accepts a bytes param and a parsingConfig param for CSV links
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1011](https://github.com/datopian/portaljs/pull/1011) [`8e896138`](https://github.com/datopian/portaljs/commit/8e896138c622615d9bd9bd1d4a18de0cf38d85ec) Thanks [@luccasmmg](https://github.com/luccasmmg)! - fix bug when there were multiple flatuitable components at the same time
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@portaljs/components",
|
||||
"version": "0.3.1",
|
||||
"version": "0.4.0",
|
||||
"type": "module",
|
||||
"description": "https://portaljs.org",
|
||||
"keywords": [
|
||||
|
||||
Binary file not shown.
@@ -5,22 +5,20 @@ import LoadingSpinner from './LoadingSpinner';
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
export async function getCsv(url: string, corsProxy?: string) {
|
||||
if (corsProxy) {
|
||||
url = corsProxy + url;
|
||||
}
|
||||
export async function getCsv(url: string, bytes) {
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
Range: 'bytes=0-5132288',
|
||||
Range: `bytes=0-${bytes}`,
|
||||
},
|
||||
});
|
||||
const data = await response.text();
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function parseCsv(file: string): Promise<any> {
|
||||
export async function parseCsv(file: string, parsingConfig): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
Papa.parse(file, {
|
||||
...parsingConfig,
|
||||
header: true,
|
||||
dynamicTyping: true,
|
||||
skipEmptyLines: true,
|
||||
@@ -41,18 +39,29 @@ export interface FlatUiTableProps {
|
||||
url?: string;
|
||||
data?: { [key: string]: number | string }[];
|
||||
rawCsv?: string;
|
||||
corsProxy?: string;
|
||||
randomId?: number;
|
||||
bytes: number;
|
||||
parsingConfig: any;
|
||||
}
|
||||
export const FlatUiTable: React.FC<FlatUiTableProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
corsProxy,
|
||||
bytes = 5132288,
|
||||
parsingConfig = {},
|
||||
}) => {
|
||||
const randomId = Math.random();
|
||||
return (
|
||||
// Provide the client to your App
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TableInner corsProxy={corsProxy} url={url} data={data} rawCsv={rawCsv} />
|
||||
<TableInner
|
||||
bytes={bytes}
|
||||
url={url}
|
||||
data={data}
|
||||
rawCsv={rawCsv}
|
||||
randomId={randomId}
|
||||
parsingConfig={parsingConfig}
|
||||
/>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
};
|
||||
@@ -61,7 +70,9 @@ const TableInner: React.FC<FlatUiTableProps> = ({
|
||||
url,
|
||||
data,
|
||||
rawCsv,
|
||||
corsProxy,
|
||||
randomId,
|
||||
bytes,
|
||||
parsingConfig,
|
||||
}) => {
|
||||
if (data) {
|
||||
return (
|
||||
@@ -71,13 +82,17 @@ const TableInner: React.FC<FlatUiTableProps> = ({
|
||||
);
|
||||
}
|
||||
const { data: csvString, isLoading: isDownloadingCSV } = useQuery(
|
||||
['dataCsv', url],
|
||||
() => getCsv(url as string, corsProxy),
|
||||
['dataCsv', url, randomId],
|
||||
() => getCsv(url as string, bytes),
|
||||
{ enabled: !!url }
|
||||
);
|
||||
const { data: parsedData, isLoading: isParsing } = useQuery(
|
||||
['dataPreview', csvString],
|
||||
() => parseCsv(rawCsv ? (rawCsv as string) : (csvString as string)),
|
||||
['dataPreview', csvString, randomId],
|
||||
() =>
|
||||
parseCsv(
|
||||
rawCsv ? (rawCsv as string) : (csvString as string),
|
||||
parsingConfig
|
||||
),
|
||||
{ enabled: rawCsv ? true : !!csvString }
|
||||
);
|
||||
if (isParsing || isDownloadingCSV)
|
||||
|
||||
@@ -9,17 +9,24 @@ const meta: Meta = {
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
data: {
|
||||
description: "Data to be displayed in the table, must be setup as an array of key value pairs"
|
||||
description:
|
||||
'Data to be displayed in the table, must be setup as an array of key value pairs',
|
||||
},
|
||||
csv: {
|
||||
description: "CSV data as string.",
|
||||
description: 'CSV data as string.',
|
||||
},
|
||||
url: {
|
||||
description: "Fetch the data from a CSV file remotely. only the first 5MB of data will be displayed"
|
||||
description:
|
||||
'Fetch the data from a CSV file remotely. only the first 5MB of data will be displayed',
|
||||
},
|
||||
bytes: {
|
||||
description:
|
||||
'Fetch the data from a CSV file remotely. only the first <bytes> of data will be displayed',
|
||||
},
|
||||
parsingConfig: {
|
||||
description:
|
||||
'Configuration for parsing the CSV data. See https://www.papaparse.com/docs#config for more details',
|
||||
},
|
||||
corsProxy: {
|
||||
description: "Optionally you cant set a CORS Proxy to which all your requests you be redirected"
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -29,7 +36,7 @@ type Story = StoryObj<FlatUiTableProps>;
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
|
||||
export const FromColumnsAndData: Story = {
|
||||
name: "Table data",
|
||||
name: 'Table data',
|
||||
args: {
|
||||
data: [
|
||||
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 },
|
||||
@@ -44,20 +51,19 @@ export const FromColumnsAndData: Story = {
|
||||
};
|
||||
|
||||
export const FromRawCSV: Story = {
|
||||
name: "Table from raw CSV",
|
||||
name: 'Table from raw CSV',
|
||||
args: {
|
||||
rawCsv: `
|
||||
Year,Temp Anomaly
|
||||
1850,-0.418
|
||||
2020,0.923
|
||||
`
|
||||
}
|
||||
`,
|
||||
},
|
||||
};
|
||||
|
||||
export const FromURL: Story = {
|
||||
name: "Table from URL",
|
||||
name: 'Table from URL',
|
||||
args: {
|
||||
url: "https://raw.githubusercontent.com/datasets/finance-vix/main/data/vix-daily.csv"
|
||||
}
|
||||
url: 'https://ckan-dev.sse.datopian.com/datastore/dump/601c9cf0-595e-46d8-88fc-d1ab2904e2db',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ function fromMarkdown(opts: FromMarkdownOptions = {}) {
|
||||
data: { isEmbed, target, alias },
|
||||
} = wikiLink;
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const wikiLinkWithHeadingPattern = /([\w\s\/\.-]*)(#.*)?/;
|
||||
const wikiLinkWithHeadingPattern = /([\p{Letter}\d\s\/\.-_]*)(#.*)?/u;
|
||||
const [, path, heading = ""] = target.match(wikiLinkWithHeadingPattern);
|
||||
|
||||
const possibleWikiLinkPermalinks = wikiLinkResolver(path);
|
||||
|
||||
@@ -3,31 +3,6 @@ import ButtonLink from './ButtonLink';
|
||||
import NewsletterForm from './NewsletterForm';
|
||||
import Image from 'next/image';
|
||||
import DatahubExampleImg from '@/public/images/showcases/datahub.webp';
|
||||
|
||||
const codeLanguage = 'javascript';
|
||||
const code = `export default {
|
||||
strategy: 'predictive',
|
||||
engine: {
|
||||
cpus: 12,
|
||||
backups: ['./storage/cache.wtf'],
|
||||
},
|
||||
}`;
|
||||
|
||||
const tabs = [
|
||||
{ name: 'cache-advance.config.js', isActive: true },
|
||||
{ name: 'package.json', isActive: false },
|
||||
];
|
||||
|
||||
function TrafficLightsIcon(props) {
|
||||
return (
|
||||
<svg aria-hidden="true" viewBox="0 0 42 10" fill="none" {...props}>
|
||||
<circle cx="5" cy="5" r="4.5" />
|
||||
<circle cx="21" cy="5" r="4.5" />
|
||||
<circle cx="37" cy="5" r="4.5" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
/* eslint jsx-a11y/label-has-associated-control: off */
|
||||
export function Hero() {
|
||||
const el = useRef(null);
|
||||
@@ -50,7 +25,7 @@ export function Hero() {
|
||||
Rapidly build rich data portals using a modern frontend framework.
|
||||
</p>
|
||||
|
||||
<ButtonLink className="mt-8" href="/docs">
|
||||
<ButtonLink style="secondary" className="mt-8" href="/docs">
|
||||
Get started
|
||||
</ButtonLink>
|
||||
|
||||
|
||||
@@ -1,14 +1,37 @@
|
||||
import { loadScripts } from '@/lib/loadNewsletterScripts';
|
||||
import Script from 'next/script';
|
||||
import { useEffect } from 'react';
|
||||
import { CloudIcon } from '@heroicons/react/solid';
|
||||
|
||||
export default function NewsletterForm() {
|
||||
useEffect(() => {
|
||||
/*
|
||||
* The newsletter scripts MUST be loaded after
|
||||
* the document is loaded, as they depend on
|
||||
* the presence of some elements
|
||||
*
|
||||
*/
|
||||
if (document.readyState === 'complete') {
|
||||
const { resetElements } = loadScripts();
|
||||
|
||||
return () => {
|
||||
resetElements();
|
||||
};
|
||||
} else {
|
||||
window.addEventListener('load', loadScripts);
|
||||
return () => window.removeEventListener('load', loadScripts);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
id="sib-form-container"
|
||||
className="mt-8 sm:mx-auto sm:text-center lg:text-left lg:mx-0"
|
||||
>
|
||||
<p className="text-base font-medium text-slate-400 dark:text-slate-400">
|
||||
Sign up to get notified about updates
|
||||
<p className="text-base font-medium flex items-center">
|
||||
<CloudIcon className="w-6 h-6 mr-1" />
|
||||
Join the PortalJS Cloud waitlist and get early access!
|
||||
</p>
|
||||
<div id="sib-container" className="!bg-transparent !p-0 !pb-5">
|
||||
<form
|
||||
@@ -47,7 +70,7 @@ export default function NewsletterForm() {
|
||||
>
|
||||
<path d="M460.116 373.846l-20.823-12.022c-5.541-3.199-7.54-10.159-4.663-15.874 30.137-59.886 28.343-131.652-5.386-189.946-33.641-58.394-94.896-95.833-161.827-99.676C261.028 55.961 256 50.751 256 44.352V20.309c0-6.904 5.808-12.337 12.703-11.982 83.556 4.306 160.163 50.864 202.11 123.677 42.063 72.696 44.079 162.316 6.031 236.832-3.14 6.148-10.75 8.461-16.728 5.01z" />
|
||||
</svg>
|
||||
Notify Me
|
||||
Join now
|
||||
</button>
|
||||
<input
|
||||
type="text"
|
||||
@@ -88,37 +111,6 @@ export default function NewsletterForm() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Script
|
||||
id="newsletter-form-validation-message"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
window.REQUIRED_CODE_ERROR_MESSAGE = 'Please choose a country code';
|
||||
window.LOCALE = 'en';
|
||||
window.EMAIL_INVALID_MESSAGE = window.SMS_INVALID_MESSAGE = "The information provided is invalid. Please review the field format and try again.";
|
||||
|
||||
window.REQUIRED_ERROR_MESSAGE = "This field cannot be left blank. ";
|
||||
|
||||
window.GENERIC_INVALID_MESSAGE = "The information provided is invalid. Please review the field format and try again.";
|
||||
|
||||
|
||||
|
||||
|
||||
window.translation = {
|
||||
common: {
|
||||
selectedList: '{quantity} list selected',
|
||||
selectedLists: '{quantity} lists selected'
|
||||
}
|
||||
};
|
||||
|
||||
var AUTOHIDE = Boolean(0);
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
<Script
|
||||
strategy="worker"
|
||||
id="newsletter-submit-form"
|
||||
src="https://sibforms.com/forms/end-form/build/main.js"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ List of available datasets:
|
||||
<Catalog datasets={datasets} facets={['group']}/>
|
||||
```
|
||||
|
||||
You now have a filter in your page with all possible values automatically added to it.
|
||||
Rerun `npm run mddb`. You now have a filter in your page with all possible values automatically added to it.
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
id: anuveyatsu
|
||||
name: Anuar Ustayev
|
||||
avatar: https://avatars.githubusercontent.com/anuveyatsu
|
||||
---
|
||||
---
|
||||
<NextSeo noindex={true} nofollow={true} />
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
id: joaodemenech
|
||||
name: João Demenech
|
||||
avatar: https://avatars.githubusercontent.com/demenech
|
||||
---
|
||||
---
|
||||
<NextSeo noindex={true} nofollow={true} />
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
id: luccasmateus
|
||||
name: Luccas Mateus
|
||||
avatar: https://avatars.githubusercontent.com/luccasmmg
|
||||
---
|
||||
---
|
||||
<NextSeo noindex={true} nofollow={true} />
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
id: mikanebu
|
||||
name: Meiran Zhiyenbayev
|
||||
avatar: https://avatars.githubusercontent.com/mikanebu
|
||||
---
|
||||
---
|
||||
<NextSeo noindex={true} nofollow={true} />
|
||||
|
||||
@@ -3,3 +3,4 @@ id: ola-rubaj
|
||||
name: Ola Rubaj
|
||||
avatar: https://avatars.githubusercontent.com/olayway
|
||||
---
|
||||
<NextSeo noindex={true} nofollow={true} />
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
id: popovayoana
|
||||
name: Yoana Popova
|
||||
avatar: https://avatars.githubusercontent.com/popovayoana
|
||||
---
|
||||
---
|
||||
<NextSeo noindex={true} nofollow={true} />
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
id: rufuspollock
|
||||
name: Rufus Pollock
|
||||
avatar: https://avatars.githubusercontent.com/rufuspollock
|
||||
---
|
||||
---
|
||||
<NextSeo noindex={true} nofollow={true} />
|
||||
|
||||
45
site/lib/loadNewsletterScripts.ts
Normal file
45
site/lib/loadNewsletterScripts.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
|
||||
import { HTMLProps } from "react";
|
||||
|
||||
const loadScript = (
|
||||
props: HTMLProps<HTMLScriptElement> & { textContent?: string }
|
||||
): (() => void) => {
|
||||
const script = document.createElement("script");
|
||||
Object.assign(script, props);
|
||||
document.head.appendChild(script);
|
||||
return () => document.head.removeChild(script);
|
||||
};
|
||||
|
||||
export const loadScripts = () => {
|
||||
const formValidationScript = loadScript({
|
||||
id: "newsletter-form-validation-message",
|
||||
textContent: `
|
||||
window.LOCALE = 'en';
|
||||
window.EMAIL_INVALID_MESSAGE = "The information provided is invalid. Please review the field format and try again.";
|
||||
window.REQUIRED_ERROR_MESSAGE = "This field cannot be left blank. ";
|
||||
window.GENERIC_INVALID_MESSAGE = "The information provided is invalid. Please review the field format and try again.";
|
||||
window.translation = {
|
||||
common: {
|
||||
selectedList: '{quantity} list selected',
|
||||
selectedLists: '{quantity} lists selected'
|
||||
}
|
||||
};
|
||||
var AUTOHIDE = Boolean(0);
|
||||
`,
|
||||
});
|
||||
|
||||
const formSubmitScript = loadScript({
|
||||
id: "newsletter-submit-form",
|
||||
src: "https://sibforms.com/forms/end-form/build/main.js",
|
||||
async: true,
|
||||
defer: true,
|
||||
});
|
||||
|
||||
return {
|
||||
resetElements: () => {
|
||||
formSubmitScript();
|
||||
formValidationScript();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ module.exports = {
|
||||
generateRobotsTxt: true,
|
||||
robotsTxtOptions: {
|
||||
policies: [
|
||||
{ userAgent: '*', disallow: '/people/' },
|
||||
{ userAgent: '*', disallow: '/people' },
|
||||
{ userAgent: '*', disallow: '/?amp=1' },
|
||||
],
|
||||
|
||||
8
site/package-lock.json
generated
8
site/package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.3.0",
|
||||
"@heroicons/react": "^1.0.3",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@mdx-js/loader": "^2.3.0",
|
||||
"@portaljs/core": "^1.0.6",
|
||||
"@portaljs/remark-callouts": "^1.0.5",
|
||||
@@ -367,9 +367,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@heroicons/react": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-1.0.3.tgz",
|
||||
"integrity": "sha512-wdzWbDiFKzeL6xFJsgY2PqvDkx4hFmQDpEFRVj872EA71XOjr8g0DQj5rHWm0y7LwfGOFL0eQmEiMbTyGNOnTQ==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@heroicons/react/-/react-1.0.6.tgz",
|
||||
"integrity": "sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ==",
|
||||
"peerDependencies": {
|
||||
"react": ">= 16"
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.3.0",
|
||||
"@heroicons/react": "^1.0.3",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@mdx-js/loader": "^2.3.0",
|
||||
"@portaljs/core": "^1.0.6",
|
||||
"@portaljs/remark-callouts": "^1.0.5",
|
||||
|
||||
Reference in New Issue
Block a user