Commit 16636348 authored by Emmanuel Raviart's avatar Emmanuel Raviart
Browse files

0.3

parents 104a35cc d2838016
Pipeline #223246 failed with stage
in 2 minutes and 59 seconds
This diff is collapsed.
......@@ -6,7 +6,7 @@
"type": "git",
"url": "https://git.nomics.world/progedo/data-catalogue.git"
},
"version": "0.2",
"version": "0.3",
"author": "DBnomics Team",
"scripts": {
"build": "sapper build --legacy",
......@@ -94,7 +94,6 @@
"pg-native": "^3.0.0",
"pg-promise": "^10.7.5",
"postcss": "^8.1.6",
"postcss-each": "^0.10.0",
"postcss-import": "^14.0.0",
"postcss-load-config": "^3.0.1",
"prettier": "^2.2.1",
......@@ -111,6 +110,7 @@
"svelte-check": "^1.1.17",
"svelte-json-tree": "github:eraviart/svelte-json-tree",
"svelte-preprocess": "^4.6.1",
"svelte-range-slider-pips": "github:eraviart/svelte-range-slider-pips",
"tailwindcss": "^2.0.1",
"tslib": "^2.0.1",
"typescript": "^4.1.2",
......
import {
Organization,
Series,
Study,
StudyOrganizationRelation,
StudyTermRelation,
......@@ -28,6 +29,20 @@ export function extractCodeBookText(
: element["#text"]
}
export function getCodeBookProductionYear(
codeBook: CodeBook,
): string | undefined {
const prodDate = codeBook.stdyDscr.citation.prodStmt?.prodDate
if (prodDate === undefined) {
return undefined
}
const date = prodDate["@date"] ?? prodDate["#text"]
if (date === undefined) {
return undefined
}
return /\d{4}/.exec(date)?.[0]
}
export function getCodeBookSeries(codeBook: CodeBook): SerStmt | undefined {
const series = codeBook.stdyDscr.citation.serStmt
return series?.serName === undefined ? undefined : series
......@@ -59,6 +74,32 @@ export function getCodeBookVariable(
return undefined
}
export function getCodeBookYear(codeBook: CodeBook): string | undefined {
const year = getCodeBookProductionYear(codeBook)
if (year !== undefined) {
return year
}
const dates = [...iterCodeBookTimePrdDates(codeBook)]
if (dates.length > 0) {
return /\d{4}/.exec(dates[0]!)?.[0]
}
return undefined
}
export function* iterCodeBookCollDates(
codeBook: CodeBook,
): Generator<string, void, void> {
let collDates = codeBook.stdyDscr.stdyInfo.sumDscr?.collDate
if (collDates === undefined) {
collDates = []
} else if (!Array.isArray(collDates)) {
collDates = [collDates]
}
for (const instant of collDates) {
yield instant["@date"]
}
}
export function* iterCodeBookDataKinds(
codeBook: CodeBook,
): Generator<string, void, void> {
......@@ -157,6 +198,14 @@ export function* iterCodeBookProducers(
yield* iterCodeBookOrganizations(codeBook.stdyDscr.citation.prodStmt.producer)
}
export function* iterCodeBookTimePrdDates(
codeBook: CodeBook,
): Generator<string, void, void> {
for (const instant of codeBook.stdyDscr.stdyInfo.sumDscr?.timePrd ?? []) {
yield instant["@date"]
}
}
export function* iterCodeBookTopicsClass(
codeBook: CodeBook,
): Generator<string, void, void> {
......@@ -172,14 +221,6 @@ export function* iterCodeBookTopicsClass(
}
}
export function* iterCodeBookYears(
codeBook: CodeBook,
): Generator<string, void, void> {
for (const instant of codeBook.stdyDscr.stdyInfo.sumDscr?.timePrd ?? []) {
yield instant["@date"]
}
}
export function* iterCodeBookVariables(
codeBook: CodeBook,
): Generator<Var, void, void> {
......@@ -191,6 +232,73 @@ export function* iterCodeBookVariables(
}
}
export function* iterSeriesDataKinds(
series: Series,
): Generator<string, void, undefined> {
const dataKinds = series.termsLabelByRelation?.[StudyTermRelation.DataKind]
if (dataKinds !== undefined) {
yield* dataKinds
}
}
export function* iterSeriesDepositors(
series: Series,
): Generator<Organization, void, undefined> {
const depositors =
series.organizationsByRelation?.[StudyOrganizationRelation.Depositor]
if (depositors !== undefined) {
yield* depositors
}
}
export function* iterSeriesDistributors(
series: Series,
): Generator<Organization, void, undefined> {
const distributors =
series.organizationsByRelation?.[StudyOrganizationRelation.Distributor]
if (distributors !== undefined) {
yield* distributors
}
}
export function* iterSeriesKeywords(
series: Series,
): Generator<string, void, undefined> {
const keywords = series.termsLabelByRelation?.[StudyTermRelation.Keyword]
if (keywords !== undefined) {
yield* keywords
}
}
export function* iterSeriesProducers(
series: Series,
): Generator<Organization, void, undefined> {
const producers =
series.organizationsByRelation?.[StudyOrganizationRelation.Producer]
if (producers !== undefined) {
yield* producers
}
}
export function* iterSeriesTopicsClass(
series: Series,
): Generator<string, void, undefined> {
const topicsClass =
series.termsLabelByRelation?.[StudyTermRelation.TopicClass]
if (topicsClass !== undefined) {
yield* topicsClass
}
}
export function* iterSeriesYears(
series: Series,
): Generator<string, void, undefined> {
const years = series.termsLabelByRelation?.[StudyTermRelation.Year]
if (years !== undefined) {
yield* years
}
}
export function* iterStudyDataKinds(
study: Study,
): Generator<string, void, undefined> {
......
......@@ -6,6 +6,33 @@ import {
strictAudit,
} from "@auditors/core"
export function auditSeriesParameters(audit: Audit, data: any): [any, any] {
if (data == null) {
return [data, null]
}
if (typeof data !== "object") {
return audit.unexpectedType(data, "object")
}
data = {
...data,
}
const errors: { [key: string]: any } = {}
const remainingKeys = new Set(Object.keys(data))
audit.attribute(
data,
"segments",
true,
errors,
remainingKeys,
auditArray(auditTrimString, auditRequire),
auditRequire,
)
return audit.reduceRemaining(data, errors, remainingKeys)
}
export function auditStudyParameters(audit: Audit, data: any): [any, any] {
if (data == null) {
return [data, null]
......@@ -60,6 +87,10 @@ export function auditVariableParameters(audit: Audit, data: any): [any, any] {
return audit.reduceRemaining(data, errors, remainingKeys)
}
export function validateSeriesParameters(data: any): [any, any] {
return auditSeriesParameters(strictAudit, data)
}
export function validateStudyParameters(data: any): [any, any] {
return auditStudyParameters(strictAudit, data)
}
......
......@@ -112,6 +112,32 @@ export function auditApiSearchQuery(audit: Audit, data: any): [any, any] {
return audit.reduceRemaining(data, errors, remainingKeys)
}
export function auditApiSeriesQuery(audit: Audit, data: any): [any, any] {
if (data == null) {
return [data, null]
}
if (typeof data !== "object") {
return audit.unexpectedType(data, "object")
}
data = {
...data,
}
const errors: { [key: string]: any } = {}
const remainingKeys = new Set(Object.keys(data))
audit.attribute(
data,
"follow",
true,
errors,
remainingKeys,
auditQueryOptionsSet(allFollows),
)
return audit.reduceRemaining(data, errors, remainingKeys)
}
export function auditApiStudyQuery(audit: Audit, data: any): [any, any] {
if (data == null) {
return [data, null]
......@@ -389,12 +415,16 @@ export function validateApiSearchQuery(data: any): [any, any] {
return auditApiSearchQuery(cleanAudit, data)
}
export function validateApiSeriesQuery(data: any): [any, any] {
return auditApiSeriesQuery(cleanAudit, data)
}
export function validateApiStudyQuery(data: any): [any, any] {
return auditApiStudyQuery(cleanAudit, data)
}
export function validateApiVariableQuery(data: any): [any, any] {
return auditApiStudyQuery(cleanAudit, data)
return auditApiVariableQuery(cleanAudit, data)
}
export function validateApiWordsQuery(data: any): [any, any] {
......
<script lang="ts">
import { goto, stores } from "@sapper/app"
import { goto } from "@sapper/app"
import Autocomplete from "../components/Autocomplete.svelte"
import type { ValidSearchQuery, WordAutocompletion } from "../data"
import { retrieveWords } from "../data_retrievers"
import { localize } from "../stores"
import { newSearchUrl } from "../urls"
......@@ -11,83 +10,11 @@
export let searchPath = ""
let autocompletions: WordAutocompletion[] = []
const { session } = stores()
$: _ = $localize
$: language = $session.language
$: term = query.q ?? ""
async function autocompleteWords({
detail: target,
}: {
detail: HTMLInputElement
}) {
const term = target.value
// Find word enclosing caret in term.
let word = term
let wordStart = target.selectionStart
let wordEnd = target.selectionEnd
if (wordStart != null) {
wordStart--
while (wordStart >= 0) {
if (term[wordStart] === " ") {
break
}
wordStart--
}
wordStart++
if (wordEnd != null) {
while (wordEnd < term.length) {
if (term[wordEnd] === " ") {
break
}
wordEnd++
}
word = wordStart < wordEnd ? term.substring(wordStart, wordEnd) : ""
}
}
// Autocomplete found word.
const wordsAutocompletion: WordAutocompletion[] = await retrieveWords(
fetch,
"/api/words",
{
language,
limit: 10,
location: "SearchForm",
term: word,
},
)
if (wordStart == null || wordEnd == null) {
autocompletions = wordsAutocompletion
} else {
const prefix = term.substring(0, wordStart)
const suffix = term.substring(wordEnd)
const wordRegExp = RegExp(regExpEscape(word), "i")
autocompletions = wordsAutocompletion.map(
(autocompletion: WordAutocompletion) => {
const itemTerm: string = autocompletion.autocomplete ?? ""
const itemTermHiglighted =
word === ""
? itemTerm
: itemTerm.replace(wordRegExp, '<b class="font-semibold">$&</b>')
return {
...autocompletion,
autocomplete: `${prefix}${itemTerm}${suffix}`,
label: `${prefix}${itemTermHiglighted}${suffix}`,
}
},
)
}
}
function regExpEscape(s: string) {
return s.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&")
}
function search() {
goto(
newSearchUrl(searchPath, {
......@@ -108,7 +35,6 @@
inputClass="input ~neutral !normal"
items={autocompletions}
itemTermKey="autocomplete"
on:input={autocompleteWords}
{placeholder}
type="text"
bind:term
......
<div
class=" flex flex-wrap w-full border-gray-100 content-center align-middle justify-center h-60 px20 py-10 text-5xl font-bold text-gray-300 text-opacity-50 my-30 mx-30"
>
<p>TO DO Series</p>
</div>
<div
class=" flex flex-wrap w-full border-gray-100 content-center align-middle justify-center h-60 px20 py-10 text-5xl font-bold text-gray-300 text-opacity-50 my-30 mx-30"
>
<p>TO DO Series</p>
</div>
<div
class=" flex flex-wrap w-full border-gray-100 content-center align-middle justify-center h-60 px20 py-10 text-5xl font-bold text-gray-300 text-opacity-50 my-30 mx-30"
>
<p>TO DO Series</p>
<script lang="ts">
import SeriesSingleListItem from "./SeriesSingleListItem.svelte"
import Pagination from "./Pagination.svelte"
import type { Series, ValidSearchQuery } from "../data"
export let count: number | undefined = undefined
export let query: ValidSearchQuery
export let series: Series[]
</script>
<div class="flex flex-col overflow-hidden my-2 text-gray-600">
{#each series as seriesSingle}
<SeriesSingleListItem series={seriesSingle} />
{/each}
</div>
<Pagination
{count}
currentPageCount={series.length}
limit={20}
{query}
url="series"
/>
<script lang="ts">
import {
iterSeriesDistributors,
iterSeriesProducers,
iterSeriesTopicsClass,
iterSeriesYears,
} from "../accessors"
import type { Series } from "../data"
import OrganizationName from "./OrganizationName.svelte"
export let series: Series
$: distributors = [...iterSeriesDistributors(series)]
$: producers = [...iterSeriesProducers(series)]
$: topics = [...iterSeriesTopicsClass(series)]
$: years = [...iterSeriesYears(series)].map((year) => parseInt(year))
</script>
<section
class="h-auto w-auto border bg-white border-gray-100 mb-2 rounded shadow"
>
<div
class=" flex flex-col h-auto w-auto px-4 py-2 border-l-4 border-red-300 rounded"
>
<!-- zone top blanche avec le titre en bold-->
<div
class="flex flex-row h-auto w-auto px-0 py-4 text-sm text-gray-500 font-bold text-left"
>
<div class="flex-shrink-0 h-auto mx-2">Série :</div>
<div class="w-auto h-auto mx-2">
<a href="series/{series.path}" target="_blank">
{series.title}
</a>
</div>
</div>
<!-- zone middle grise avec une icone et les identifiants en rouge-->
<div
class=" flex flex-row h-14 w-auto mx-10 px-2 py-2 bg-white rounded-sm"
>
<div>
<img class="h-10 w-10" src="img/reseau-red.png" alt="project icon" />
</div>
<div class="h-10 w-auto pl-2 text-sm text-red-400">
{#if topics.length > 0}
<p class="pr-1">
Topic class :
{#each topics as topic, index}
{#if index > 0}—{/if}
<span class="px-1">{topic}</span>
{/each}
</p>
{/if}
{#if years.length > 0}
<p>
Années:
<span>{Math.min(...years)}</span>
-
<span>{Math.max(...years)}</span>
</p>
{/if}
</div>
</div>
<!-- Zone bottom blanche avec producer-->
<div
class="flex flex-wrap h-auto w-auto mx-10 px-2 py-2 text-xs text-gray-500"
>
{#if producers.length > 0}
<p class="pr-1">
Producer(s) :
{#each producers as producer, index}
{#if index > 0}—{/if}
<span class="px-1">
<OrganizationName organization={producer} />
</span>{/each}
</p>
{/if}
{#if distributors.length > 0}
<p class="pr-1">
Diffuseur(s) :
{#each distributors as distributor, index}
{#if index > 0}—{/if}
<span class="px-1"
><OrganizationName organization={distributor} />
</span>
{/each}
</p>
{/if}
</div>
</div>
</section>
<script lang="ts">
import JsonTree from "svelte-json-tree"
import Drawer from "./Drawer.svelte"
import StudiesList from "./StudiesList.svelte"
import VariableBody from "./VariableBody.svelte"
import type { Series } from "../data"
import {
extractCodeBookText,
iterCodeBookDepositors,
iterCodeBookDistributors,
iterCodeBookProducers,
iterCodeBookKeywords,
iterCodeBookVariables,
iterCodeBookTopicsClass,
iterCodeBookDataKinds,
} from "../accessors"
import { localize } from "../stores"
import OrganizationName from "./OrganizationName.svelte"
//import type { CodeBookVersion } from "../raw_types/codebooks"
export let series: Series
$: _ = $localize
// CodeBook Fields
$: codeBook = series.latestStudy?.codeBook
$: subTitle = codeBook?.stdyDscr.citation.titlStmt.subTitl
// $: topic = codeBook?.docDscr.controlledVocabUsed?[1].["usage"].specificElements.authorizedCodeValue
$: topic =
codeBook === undefined ? [] : [...iterCodeBookTopicsClass(codeBook)]
$: keywords =
codeBook === undefined ? [] : [...iterCodeBookKeywords(codeBook)]
$: method = extractCodeBookText(codeBook?.stdyDscr.method?.dataColl.collMode)
// $: datatype = codeBook?.stdyDscr?.stdyInfo?.sumDscr?.dataKind
$: datatype =
codeBook === undefined ? [] : [...iterCodeBookDataKinds(codeBook)]
$: producers =
codeBook === undefined ? [] : [...iterCodeBookProducers(codeBook)]
$: distributors =
codeBook === undefined ? [] : [...iterCodeBookDistributors(codeBook)]
$: depositors =
codeBook === undefined ? [] : [...iterCodeBookDepositors(codeBook)]
$: variables =
codeBook === undefined ? [] : [...iterCodeBookVariables(codeBook)]
$: yearsRange =
series.termsLabelByRelation?.yearsRange === undefined
? []
: series.termsLabelByRelation?.yearsRange
$: methodology = {
"Methode de collecte (collMode)": extractCodeBookText(
codeBook?.stdyDscr.method?.dataColl.collMode,
),
"Methode de collecte (resInstru)": extractCodeBookText(
codeBook?.stdyDscr.method?.dataColl.resInstru,
),
"Temps de collecte": extractCodeBookText(
codeBook?.stdyDscr.method?.dataColl?.timeMeth,
),
Frequency: extractCodeBookText(
codeBook?.stdyDscr.method?.dataColl?.frequenc,
),
Sampling: extractCodeBookText(
codeBook?.stdyDscr.method?.dataColl?.sampProc,
),
Situation: extractCodeBookText(
codeBook?.stdyDscr.method?.dataColl?.collSitu,
),
Deviat: extractCodeBookText(codeBook?.stdyDscr.method?.dataColl?.deviat),
Notes: extractCodeBookText(codeBook?.stdyDscr.method?.notes),
"Les poids et le calage": extractCodeBookText(
Array.isArray(codeBook?.stdyDscr.method?.dataColl?.weight)
? "tableau"
: codeBook?.stdyDscr.method?.dataColl?.weight,
),
}
$: tab = "studies"
</script>
<!-- grid-->
<div class="flex flex-wrap -mx-4 text-gray-800">
<!-- grid: top left element with level or image -->
<div
class="mb-1 py-6 px-4 overflow-hidden h-40 w-1/4 bg-gray-100 rounded shadow"
>
<h1 class="text-2xl font-bold text-gray-500">
{_("Project")}{_("colon")}
</h1>