[example][m] - start of ckan-example

This commit is contained in:
Luccas Mateus de Medeiros Gomes 2023-04-19 12:35:37 -03:00
parent 83bffccf52
commit 234bbcec49
26 changed files with 688 additions and 0 deletions

View File

@ -0,0 +1,10 @@
{
"extends": ["plugin:cypress/recommended", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
}
]
}

View File

@ -0,0 +1,6 @@
import { defineConfig } from 'cypress';
import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';
export default defineConfig({
e2e: nxE2EPreset(__dirname),
});

View File

@ -0,0 +1,30 @@
{
"name": "ckan-example-e2e",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "examples/ckan-example-e2e/src",
"projectType": "application",
"targets": {
"e2e": {
"executor": "@nrwl/cypress:cypress",
"options": {
"cypressConfig": "examples/ckan-example-e2e/cypress.config.ts",
"devServerTarget": "ckan-example:serve:development",
"testingType": "e2e"
},
"configurations": {
"production": {
"devServerTarget": "ckan-example:serve:production"
}
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["examples/ckan-example-e2e/**/*.{js,ts}"]
}
}
},
"tags": [],
"implicitDependencies": ["ckan-example"]
}

View File

@ -0,0 +1,13 @@
import { getGreeting } from '../support/app.po';
describe('ckan-example', () => {
beforeEach(() => cy.visit('/'));
it('should display welcome message', () => {
// Custom command example, see `../support/commands.ts` file
cy.login('my-email@something.com', 'myPassword');
// Function helper example, see `../support/app.po.ts` file
getGreeting().contains('Welcome ckan-example');
});
});

View File

@ -0,0 +1,4 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io"
}

View File

@ -0,0 +1 @@
export const getGreeting = () => cy.get('h1');

View File

@ -0,0 +1,33 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace Cypress {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chainable<Subject> {
login(email: string, password: string): void;
}
}
//
// -- This is a parent command --
Cypress.Commands.add('login', (email, password) => {
console.log('Custom command example: Login', email, password);
});
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })

View File

@ -0,0 +1,17 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands';

View File

@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"sourceMap": false,
"outDir": "../../dist/out-tsc",
"allowJs": true,
"types": ["cypress", "node"]
},
"include": ["src/**/*.ts", "src/**/*.js", "cypress.config.ts"]
}

View File

@ -0,0 +1 @@
DMS=https://demo.dev.datopian.com

View File

@ -0,0 +1,34 @@
{
"extends": [
"plugin:@nrwl/nx/react-typescript",
"next",
"next/core-web-vitals",
"../../.eslintrc.json"
],
"ignorePatterns": ["!**/*", ".next/**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {
"@next/next/no-html-link-for-pages": [
"error",
"examples/ckan-example/pages"
]
}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
],
"rules": {
"@next/next/no-html-link-for-pages": "off"
},
"env": {
"jest": true
}
}

6
examples/ckan-example/index.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
declare module '*.svg' {
const content: any;
export const ReactComponent: any;
export default content;
}

View File

@ -0,0 +1,11 @@
/* eslint-disable */
export default {
displayName: 'ckan-example',
preset: '../../jest.preset.js',
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/examples/ckan-example',
};

5
examples/ckan-example/next-env.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@ -0,0 +1,28 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { withNx } = require('@nrwl/next/plugins/with-nx');
/**
* @type {import('@nrwl/next/plugins/with-nx').WithNxOptions}
**/
const nextConfig = {
publicRuntimeConfig: {
DMS: process.env.DMS ? process.env.DMS : '',
},
async rewrites() {
return {
beforeFiles: [
{
source: '/@:org/:project*',
destination: '/@org/:org/:project*',
},
],
};
},
nx: {
// Set this to true if you would like to use SVGR
// See: https://github.com/gregberge/svgr
svgr: false,
},
};
module.exports = withNx(nextConfig);

View File

@ -0,0 +1,188 @@
import { GetServerSideProps } from 'next';
import getConfig from 'next/config';
import React from 'react';
import {
CalendarIcon,
CloudArrowUpIcon,
FolderOpenIcon,
LockClosedIcon,
MapPinIcon,
PaperClipIcon,
ServerIcon,
UserIcon,
} from '@heroicons/react/20/solid';
const dms = getConfig().publicRuntimeConfig.DMS;
const formatter = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
timeZone: 'UTC',
});
export const getServerSideProps: GetServerSideProps = async (context) => {
const { dataset } = context.query;
const response = await fetch(
`${dms}/api/3/action/package_show?id=${dataset}`
);
const _dataset = await response.json();
return {
props: {
dataset: _dataset.result,
},
};
};
const positions = [
{
id: 1,
title: 'Back End Developer',
type: 'Full-time',
location: 'Remote',
department: 'Engineering',
closeDate: '2020-01-07',
closeDateFull: 'January 7, 2020',
},
{
id: 2,
title: 'Front End Developer',
type: 'Full-time',
location: 'Remote',
department: 'Engineering',
closeDate: '2020-01-07',
closeDateFull: 'January 7, 2020',
},
{
id: 3,
title: 'User Interface Designer',
type: 'Full-time',
location: 'Remote',
department: 'Design',
closeDate: '2020-01-14',
closeDateFull: 'January 14, 2020',
},
];
export default function DatasetPage({ dataset }) {
return (
<div className="overflow-hidden bg-white py-24 sm:py-32">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto grid max-w-2xl grid-cols-1 gap-x-8 gap-y-16 sm:gap-y-20 lg:mx-0 lg:max-w-none lg:grid-cols-2">
<div className="lg:pr-8 lg:pt-4">
<div className="lg:max-w-lg">
<h2 className="text-base font-semibold leading-7 text-indigo-600">
{dataset.organization.title
? dataset.organization.title
: dataset.organization.name}
</h2>
<p className="mt-2 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
{dataset.title ? dataset.title : dataset.name}
</p>
<p className="mt-6 leading-8 text-gray-600">
{dataset.notes ? dataset.notes : 'No description'}
</p>
<div className="mt-6 border-t border-gray-100">
<dl className="divide-y divide-gray-100">
{dataset.tags.length > 0 && (
<div className="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
<dt className="text-sm font-medium leading-6 text-gray-900">
Tags
</dt>
<dd className="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
{dataset.tags.map((tag) => tag.display_name).join(', ')}
</dd>
</div>
)}
{dataset.url && (
<div className="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
<dt className="text-sm font-medium leading-6 text-gray-900">
Url
</dt>
<dd className="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
{dataset.url}
</dd>
</div>
)}
<div className="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
<dt className="text-sm font-medium leading-6 text-gray-900">
Created
</dt>
<dd className="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
{formatter.format(new Date(dataset.metadata_created))}
</dd>
</div>
<div className="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
<dt className="text-sm font-medium leading-6 text-gray-900">
Modified
</dt>
<dd className="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
{formatter.format(new Date(dataset.metadata_modified))}
</dd>
</div>
</dl>
</div>
</div>
</div>
<div className="lg:pr-8 lg:pt-4">
<h2 className="text-base font-semibold leading-7 text-indigo-600">
Resources
</h2>
<div className="overflow-hidden bg-white shadow sm:rounded-md mt-2">
<ul role="list" className="divide-y divide-gray-200">
{dataset.resources.map((resource) => (
<li key={resource.id}>
<a href={resource.url} className="block hover:bg-gray-50">
<div className="px-4 py-4 sm:px-6">
<div className="flex items-center justify-between">
<p className="truncate text-sm font-medium text-indigo-600">
{resource.name}
</p>
{resource.datastore_active && (
<div className="ml-2 flex flex-shrink-0">
<p className="inline-flex rounded-full bg-green-100 px-2 text-xs font-semibold leading-5 text-green-800">
Datastore active
</p>
</div>
)}
</div>
<div className="mt-2 sm:flex sm:justify-between">
<div className="sm:flex">
<p className="flex items-center text-sm text-gray-500">
<FolderOpenIcon
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400"
aria-hidden="true"
/>
{resource.format}
</p>
</div>
<div className="mt-2 flex items-center text-sm text-gray-500 sm:mt-0">
<CalendarIcon
className="mr-1.5 h-5 w-5 flex-shrink-0 text-gray-400"
aria-hidden="true"
/>
<p>
Last modified:{' '}
<time dateTime={resource.metadata_modified}>
{formatter.format(
new Date(resource.metadata_modified)
)}
</time>
</p>
</div>
</div>
</div>
</a>
</li>
))}
</ul>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,18 @@
import { AppProps } from 'next/app';
import Head from 'next/head';
import './styles.css'
function CustomApp({ Component, pageProps }: AppProps) {
return (
<>
<Head>
<title>Welcome to ckan-example!</title>
</Head>
<main className="app">
<Component {...pageProps} />
</main>
</>
);
}
export default CustomApp;

View File

@ -0,0 +1,114 @@
import getConfig from 'next/config';
import styles from './index.module.css';
const dms = getConfig().publicRuntimeConfig.DMS
const formatter = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
timeZone: 'UTC',
});
export async function getServerSideProps() {
const response = await fetch(`${dms}/api/3/action/package_search`)
const datasets = await response.json()
const datasetsWithDetails = await Promise.all(datasets.result.results.map(async (dataset) => {
const response = await fetch(`${dms}/api/3/action/package_show?id=` + dataset.name)
const json = await response.json()
return json.result
}))
return {
props: {
datasets: datasetsWithDetails
}
}
}
export function Index({ datasets }) {
return (
<div className="bg-white">
<div className="mx-auto max-w-7xl px-6 py-16 sm:py-24 lg:px-8">
<h2 className="text-2xl font-bold leading-10 tracking-tight text-indigo-500">
My Datasets
</h2>
<p className="mt-6 max-w-2xl text-base leading-7 text-gray-600">
Here is a list of all my datasets for easy access and sharing, they
are all available in the following{' '}
<a
href="#"
className="font-semibold text-indigo-600 hover:text-indigo-500"
>
CKAN Instance
</a>
</p>
<div className="mt-20">
<div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
<table className="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th
scope="col"
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Title
</th>
<th
scope="col"
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Description
</th>
<th
scope="col"
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Last updated
</th>
<th
scope="col"
className="relative py-3.5 pl-3 pr-4 sm:pr-0"
></th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
{datasets.map((dataset) => (
<tr>
<td className="px-3 py-4 text-sm text-gray-500">
{dataset.title}
</td>
<td className="px-3 py-4 text-sm text-gray-500">
{dataset.notes}
</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{formatter.format(
new Date(dataset.metadata_modified)
)}
</td>
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<a
href={`/@${dataset.organization.name}/${dataset.name}`}
className="text-indigo-600 hover:text-indigo-900"
>
More info
</a>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
);
}
export default Index;

View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -0,0 +1,15 @@
const { join } = require('path');
// Note: If you use library-specific PostCSS/Tailwind configuration then you should remove the `postcssConfig` build
// option from your application's configuration (i.e. project.json).
//
// See: https://nx.dev/guides/using-tailwind-css-in-react#step-4:-applying-configuration-to-libraries
module.exports = {
plugins: {
tailwindcss: {
config: join(__dirname, 'tailwind.config.js'),
},
autoprefixer: {},
},
};

View File

@ -0,0 +1,69 @@
{
"name": "ckan-example",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "examples/ckan-example",
"projectType": "application",
"targets": {
"build": {
"executor": "@nrwl/next:build",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"root": "examples/ckan-example",
"outputPath": "dist/examples/ckan-example"
},
"configurations": {
"development": {
"outputPath": "examples/ckan-example"
},
"production": {}
}
},
"serve": {
"executor": "@nrwl/next:server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "ckan-example:build",
"dev": true
},
"configurations": {
"development": {
"buildTarget": "ckan-example:build:development",
"dev": true
},
"production": {
"buildTarget": "ckan-example:build:production",
"dev": false
}
}
},
"export": {
"executor": "@nrwl/next:export",
"options": {
"buildTarget": "ckan-example:build:production"
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "examples/ckan-example/jest.config.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["examples/ckan-example/**/*.{ts,tsx,js,jsx}"]
}
}
},
"tags": []
}

View File

View File

@ -0,0 +1,11 @@
import React from 'react';
import { render } from '@testing-library/react';
import Index from '../pages/index';
describe('Index', () => {
it('should render successfully', () => {
const { baseElement } = render(<Index />);
expect(baseElement).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
const { createGlobPatternsForDependencies } = require('@nrwl/react/tailwind');
const { join } = require('path');
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
join(
__dirname,
'{src,pages,components}/**/*!(*.stories|*.spec).{ts,tsx,html}'
),
...createGlobPatternsForDependencies(__dirname),
],
theme: {
extend: {},
},
plugins: [],
};

View File

@ -0,0 +1,23 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"jsx": "preserve",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"resolveJsonModule": true,
"isolatedModules": true,
"incremental": true,
"types": ["jest", "node"]
},
"include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "next-env.d.ts"],
"exclude": [
"node_modules",
"jest.config.ts",
"src/**/*.spec.ts",
"src/**/*.test.ts"
]
}

View File

@ -0,0 +1,21 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"],
"jsx": "react"
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
]
}