Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS-based validation with results / remove stacLint #412

Merged
merged 3 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ You need to provide a field `stac_browser` and then you can set any of the follo
- `defaultThumbnailSize`
- `displayGeoTiffByDefault`
- `showThumbnailsAsAssets`
- `stacLint` (can only be disabled)

### Custom extensions

Expand Down
1 change: 0 additions & 1 deletion config.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ module.exports = {
showKeywordsInItemCards: false,
showKeywordsInCatalogCards: false,
showThumbnailsAsAssets: false,
stacLint: true,
geoTiffResolution: 128,
redirectLegacyUrls: false,
itemsPerPage: 12,
Expand Down
5 changes: 0 additions & 5 deletions config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,6 @@
"boolean"
]
},
"stacLint": {
"type": [
"boolean"
]
},
"geoTiffResolution": {
"type": [
"integer"
Expand Down
13 changes: 0 additions & 13 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ The following ways to set config options are possible:
* [locale](#locale)
* [fallbackLocale](#fallbacklocale)
* [supportedLocales](#supportedlocales)
* [stacLint](#staclint)
* [historyMode](#historymode)
* [pathPrefix](#pathprefix)
* [stacProxyUrl](#stacproxyurl)
Expand Down Expand Up @@ -115,18 +114,6 @@ In CLI, please provide the languages separated by a space, e.g. `--supportedLoca
Please note that only left-to-right languages have been tested.
I'd need help to test support for right-to-left languages.

## stacLint

**deprecated**

Enables or disables a feature that validates the STAC catalog when opening the "Source Data" popup.
Validation uses the external service [staclint.com](https://staclint.com).

Validation is automatically disabled in the following cases:
- the host of a catalog is `localhost`, `127.0.0.1` or `::1`
- [private query parameters](../README.md#private-query-parameters) have been set
- `stacProxyUrl` is set

## historyMode

***build-only option***
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"node-polyfill-webpack-plugin": "^2.0.0",
"remove-markdown": "^0.5.0",
"stac-layer": "^0.15.0",
"stac-node-validator": "^2.0.0-beta.6",
"urijs": "^1.19.11",
"v-clipboard": "^3.0.0-next.1",
"vue": "^2.6.12",
Expand Down
12 changes: 3 additions & 9 deletions src/StacBrowser.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<b-container id="stac-browser">
<Authentication v-if="doAuth.length > 0" />
<ErrorAlert class="global-error" v-if="globalError" v-bind="globalError" @close="hideError" />
<ErrorAlert v-if="globalError" dismissible class="global-error" v-bind="globalError" @close="hideError" />
<Sidebar v-if="sidebar" />
<!-- Header -->
<header>
Expand Down Expand Up @@ -227,8 +227,7 @@ export default {
'crossOriginMedia',
'defaultThumbnailSize',
'displayGeoTiffByDefault',
'showThumbnailsAsAssets',
'stacLint' // can only be disabled
'showThumbnailsAsAssets'
];

let doReset = !root || (oldRoot && Utils.isObject(oldRoot['stac_browser']));
Expand All @@ -242,11 +241,6 @@ export default {
if (doSet && typeof root['stac_browser'][key] !== 'undefined') {
value = root['stac_browser'][key]; // Custom value from root
}

// Don't enable stacLint if it has been disabled by default
if (key === 'stacLint' && !CONFIG.stacLint) {
continue;
}

// Commit config
if (typeof value !== 'undefined') {
Expand Down Expand Up @@ -392,4 +386,4 @@ export default {
@import '~bootstrap-vue/src/index.scss';
@import "./theme/page.scss";
@import "./theme/custom.scss";
</style>
</style>
4 changes: 2 additions & 2 deletions src/components/ErrorAlert.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default {
},
dismissible: {
type: Boolean,
default: true
default: false
}
}
};
Expand All @@ -72,4 +72,4 @@ export default {
dl {
font-size: 0.9em;
}
</style>
</style>
4 changes: 2 additions & 2 deletions src/components/SearchFilter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,8 @@ export default {
},
andOrOptions() {
return [
{ value: 'and', text: this.$i18n.t('search.logical.and') },
{ value: 'or', text: this.$i18n.t('search.logical.or') },
{ value: 'and', text: this.$t('search.logical.and') },
{ value: 'or', text: this.$t('search.logical.or') },
];
},
showAdditionalFilters() {
Expand Down
43 changes: 7 additions & 36 deletions src/components/Source.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@

<b-popover
v-if="stacUrl" id="popover-link" target="popover-link-btn" triggers="focus"
placement="bottom" container="stac-browser" :title="$t('source.title')"
@show="validate"
placement="bottom" container="stac-browser" :title="$t('source.title')"
>
<template v-if="stac">
<b-row v-if="stacId" class="stac-id">
Expand All @@ -53,13 +52,10 @@
<b-col cols="4">{{ $t('source.stacVersion') }}</b-col>
<b-col>{{ stacVersion }}</b-col>
</b-row>
<b-row v-if="canValidate" class="validation">
<b-row class="stac-valid">
<b-col cols="4">{{ $t('source.valid') }}</b-col>
<b-col>
<b-spinner v-if="valid === null" :label="$t('source.validating')" small />
<template v-else-if="valid === true">✔️</template>
<template v-else-if="valid === false">❌</template>
<template v-else>{{ $t('source.validationNA') }}</template>
<Validation :data="stac" />
</b-col>
</b-row>
<hr>
Expand All @@ -84,7 +80,6 @@ import { mapActions, mapGetters, mapState } from 'vuex';

import Url from './Url.vue';

import URI from 'urijs';
import Utils from '../utils';
import { getBest, prepareSupported } from '../locale-id';
import CopyButton from './CopyButton.vue';
Expand All @@ -109,6 +104,7 @@ export default {
RootStats: () => import('./RootStats.vue'),
Url,
CopyButton,
Validation: () => import('./Validation.vue')
},
props: {
title: {
Expand All @@ -125,7 +121,7 @@ export default {
}
},
computed: {
...mapState(['conformsTo', 'dataLanguages', 'locale', 'privateQueryParameters', 'supportedLocales', 'stacLint', 'stacProxyUrl', 'uiLanguage', 'valid']),
...mapState(['conformsTo', 'dataLanguages', 'locale', 'supportedLocales', 'uiLanguage', 'valid']),
...mapGetters(['supportsExtension', 'root']),
stacVersion() {
return this.stac?.stac_version;
Expand Down Expand Up @@ -154,26 +150,6 @@ export default {
return '-';
}
},
canValidate() {
if (!this.stacLint || typeof this.stacUrl !== 'string') {
return false;
}
else if (Utils.size(this.privateQueryParameters) > 0) {
// Don't expose private query parameters to externals
return false;
}
else if (Array.isArray(this.stacProxyUrl)) {
// Don't validate if a proxy has been set
return false;
}
let uri = URI(this.stacUrl);
let host = uri.hostname().toLowerCase();
if (host === 'localhost' || host.startsWith('127.') || host === '::1') {
// Can't validate localhost
return false;
}
return true;
},
message() {
return this.$t('source.share.message', {title: this.title, url: this.browserUrl()});
},
Expand Down Expand Up @@ -235,12 +211,6 @@ export default {
},
methods: {
...mapActions(['switchLocale']),
async validate() {
if (!this.canValidate) {
return;
}
await this.$store.dispatch('validate', this.stacUrl);
},
browserUrl() {
return window.location.toString();
}
Expand All @@ -260,7 +230,8 @@ export default {
}
}

#popover-link .stac-id .copy-button {
#popover-link .stac-id .btn-sm,
#popover-link .stac-valid .btn-sm {
padding-top: 0.1rem;
padding-bottom: 0.1rem;
font-size: 0.7rem;
Expand Down
29 changes: 28 additions & 1 deletion src/components/StacHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
<template #catalog><StacLink :data="containerLink" /></template>
</i18n>
<b-button-group>
<b-button v-if="back" :to="selfBrowserLink" :title="$t('goBack.description', {type})" variant="outline-primary" size="sm">
<b-icon-arrow-left /> <span class="button-label prio">{{ $t('goBack.label') }}</span>
</b-button>
<b-button v-if="parentLink" :to="toBrowserPath(parentLink.href)" :title="parentLinkTitle" variant="outline-primary" size="sm">
<b-icon-arrow-90deg-up /> <span class="button-label prio">{{ $t('goToParent.label') }}</span>
</b-button>
Expand Down Expand Up @@ -43,14 +46,15 @@
import { mapState, mapGetters } from 'vuex';
import Source from './Source.vue';
import StacLink from './StacLink.vue';
import { BIconArrow90degUp, BIconBook, BIconFolderSymlink, BIconSearch, BIconLock, BIconUnlock } from "bootstrap-vue";
import { BIconArrow90degUp, BIconArrowLeft, BIconBook, BIconFolderSymlink, BIconSearch, BIconLock, BIconUnlock } from "bootstrap-vue";
import STAC from '../models/stac';
import Utils from '../utils';

export default {
name: 'StacHeader',
components: {
BIconArrow90degUp,
BIconArrowLeft,
BIconBook,
BIconFolderSymlink,
BIconSearch,
Expand All @@ -62,6 +66,29 @@ export default {
computed: {
...mapState(['allowSelectCatalog', 'authConfig', 'authData', 'catalogUrl', 'data', 'url', 'title']),
...mapGetters(['canSearch', 'root', 'parentLink', 'collectionLink', 'toBrowserPath']),
back() {
return this.$route.name === 'validation';
},
selfBrowserLink() {
return this.toBrowserPath(this.url);
},
type() {
if (this.data instanceof STAC) {
if (this.data.isItem()) {
return this.$tc('stacItem');
}
else if (this.data.isCollection()) {
return this.$tc(`stacCollection`);
}
else if (this.data.isCatalog()) {
return this.$tc(`stacCatalog`);
}
else {
return this.data.type;
}
}
return null;
},
collectionLinkTitle() {
if (this.collectionLink && Utils.hasText(this.collectionLink.title)) {
return this.$t('goToCollection.descriptionWithTitle', this.collectionLink);
Expand Down
73 changes: 73 additions & 0 deletions src/components/Validation.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<template>
<div class="valid">
<b-spinner v-if="working" :label="$t('source.validating')" small />
<b-button v-else-if="valid === true" variant="success" :size="size" :to="validationLink"><b-icon-check /> {{ $t('checkbox.true') }}</b-button>
<b-button v-else-if="valid === false" variant="danger" :size="size" :to="validationLink"><b-icon-x /> {{ $t('checkbox.false') }}</b-button>
<template v-else>{{ $t('source.validationNA') }}</template>
</div>
</template>

<script>
import STAC from '../models/stac.js';
import validateSTAC from 'stac-node-validator';
import { BIconCheck, BIconX } from 'bootstrap-vue';
import { mapGetters } from 'vuex';

export default {
name: "Validation",
components: {
BIconCheck,
BIconX
},
props: {
data: {
type: Object,
default: null
},
size: {
type: String,
default: "sm"
}
},
data() {
return {
working: true,
valid: null
};
},
computed: {
...mapGetters(['toBrowserPath']),
validationLink() {
if (this.data instanceof STAC) {
return '/validation' + this.toBrowserPath(this.data.getAbsoluteUrl());
}
else {
return null;
}
}
},
async created() {
await this.validate();
},
methods: {
async validate() {
this.working = true;
this.valid = null;
try {
if (this.data instanceof STAC) {
const report = await validateSTAC(this.data);
this.valid = report.valid;
}
} catch (error) {
console.error(error);
} finally {
this.working = false;
}
}
}
};
</script>

<style>

</style>
Loading