From 4ab1cd69b6397543edf7888d6ff210150122a27d Mon Sep 17 00:00:00 2001 From: MAB Date: Fri, 13 Oct 2023 11:12:00 +0200 Subject: [PATCH 01/64] lint --- src/assets/datacite/testLogo.vue | 2 +- src/components/vs-input/vs-input.vue | 34 ++++++++++++---------- vue.config.js | 42 ++++++++++++++-------------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/assets/datacite/testLogo.vue b/src/assets/datacite/testLogo.vue index d0cc6e1..dbc4a1e 100644 --- a/src/assets/datacite/testLogo.vue +++ b/src/assets/datacite/testLogo.vue @@ -1,8 +1,8 @@ + + + + diff --git a/src/components/BaseIcon.vue b/src/components/BaseIcon.vue new file mode 100644 index 0000000..b03588a --- /dev/null +++ b/src/components/BaseIcon.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/components/Pagination.vue b/src/components/PaginationComponent.vue similarity index 100% rename from src/components/Pagination.vue rename to src/components/PaginationComponent.vue diff --git a/src/components/SectionBanner.vue b/src/components/SectionBanner.vue new file mode 100644 index 0000000..17398fb --- /dev/null +++ b/src/components/SectionBanner.vue @@ -0,0 +1,30 @@ + + diff --git a/src/components/SectionBannerStarOnGitea.vue b/src/components/SectionBannerStarOnGitea.vue new file mode 100644 index 0000000..c34c0c8 --- /dev/null +++ b/src/components/SectionBannerStarOnGitea.vue @@ -0,0 +1,13 @@ + + diff --git a/src/components/map/map.component.vue b/src/components/map/map.component.vue index a71f578..163edda 100644 --- a/src/components/map/map.component.vue +++ b/src/components/map/map.component.vue @@ -12,7 +12,7 @@ export default MapComponent; From 00d5bbb8db02adb172acaec8695c6f9fcbaf7a2c Mon Sep 17 00:00:00 2001 From: frankporras Date: Tue, 30 Apr 2024 16:04:34 +0200 Subject: [PATCH 13/64] Logos redistributed. CTS link. Geosphere negative logo --- src/App.vue | 6 +-- src/assets/site/img/base_logo.png | Bin 0 -> 53874 bytes .../img/geosphere-austria-logo-negativ.png | Bin 0 -> 18924 bytes src/views/home-view/home-view-component.vue | 40 ++++++++++++++++-- vue.config.cjs | 1 + 5 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 src/assets/site/img/base_logo.png create mode 100644 src/assets/site/img/geosphere-austria-logo-negativ.png diff --git a/src/App.vue b/src/App.vue index bd0156e..b9d94d2 100644 --- a/src/App.vue +++ b/src/App.vue @@ -7,8 +7,8 @@ diff --git a/src/assets/site/img/base_logo.png b/src/assets/site/img/base_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ab09e10b46a69036a2fdb2b3920f557b45190c5d GIT binary patch literal 53874 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 IIVCg!0OZQ=8UO$Q literal 0 HcmV?d00001 diff --git a/src/assets/site/img/geosphere-austria-logo-negativ.png b/src/assets/site/img/geosphere-austria-logo-negativ.png new file mode 100644 index 0000000000000000000000000000000000000000..e81bfe038524f756c7639ecba073e7715274f8d5 GIT binary patch literal 18924 zcmXtgbzIZm_rF0%cS(c5XkpSNCEZF$NsDxYFpwHBx*H?~B~@V5s1XvPfHVw7Nsg|; z_|5m{_ub>M_~Uh7_q^^s=brOC=Xn;Vud7Bv_?YnCy?Z1Y>MDl!?mg(o{$6;5hy9F> z-J8dL5qPSb`P{oF#QE=iKd?f<|K2^edm1W=F9Qqq3-|pNpwlk`4&L9H8-?c*3Yfh4 z91+O($f)PP4@sJ+x;J}-+9q$>BTD$`t0OuTNJY|U2&{1wo)mUwnH(_d-&2q1j>Nvm z6v8knxp-$Mr8vjucUDqDT_eJ*@$$Q607xkS;>~x1n5EHQ{=Gum2Od8=d9cFW6=HF2 z%&BTXt!j`#wG#On@=5i!Bj=%*=jK(q37d&c&3^+a$L|K}J{%X_93SBhkvH!4;p)$f z$D4U%8e+#$t4euK88ZDO&Uq;OyncG_I>_LDv79jLgsrU0UEclS|6Q}q+(eBQdFcKj zc*S~!f+ETxf0}6jMVoL@Hkq>s>^?@38&4wE!Tg^f)EjRMw2nd@yZz7?KfIR+p{h9E z!c*h%E+2cx#{(b5H#SmwOmERt+o_Jz`u_Q_A+XV<7AsV>hFVi?{a!i4_v| z1g(|bqVM=BOc%!j|A}f~SXO!|=d;pk$D;RKkqpyZ`?QYSgn$l2v}QStbSp9)v^4(j z!d!tJqnjeS6^Ru+_%UPOt9-rOD&4!^FDi$Q;f!6 z2NVOUZG5;yYuFtr6}H)P5&Zd{&-%ZG;3D9I+`c8ZVdP92|G*k6>?!&n`iK>KnYtMU zFLO}LLC@j;?kF+epUO^aXkOK9*}jE2s%wULa1j?`a(2Sev@z`UYq+%Kw#$>~pklsL%+S~7jd`o=+6wTv<(*zLd4V0}!OS%2%=LRA~_qvK)$ffcBYX|orJM*$vV(h>-(x63l`7WJ{ z9ULPYg_Yhznb7>{j;dlh;aReC)B9#FmbyJ+hb?P)h+mPi|5HQq7<*n!zIz1ybkO zj~Pn+$~;>=LUi}c_aLFEJOWz(H)37BQ3o9R#bw1PCggy;YrZ7w1gMhIUb9R@=>~Jb z^;iR(n1^1ORszU^io(n$taD#n$~s7H4iOF|SR+777<5G2AAs|Zg|L98cCLxd=L2j0mi zYV%i2P{PY4LW&<^NXTS)ZI(BDG*vviMcGo5)g?Pqb%`e_hM0o%u0dX#hlXw_VD2Li2cOHP zy0yo=#XCjfi6os-beb1glr)a!jmbMB_XFb$d!{mg__HCl_XM)IHwXBArWILGJDlQl z<0|8%Q#}HS#Xm{DH2s5$aoQi0OdOS@)L>(D-}ehdfhziPRGV3o(ZK2aZztiyvMNfj zkqjy)RgD3Wc-zSBq0m9leBLUs@6lTDVnnCw4kl?VhwY> zRJ?0Ua9M1OPyfT-72@mWK14^jCz;dp$l17)T_nA?NSXfpT4us1?hm(t{P3l{wjMd7{Mz#O&rIB0lb*S= zgMw`eN(M<_BijCk<)|&n0lL%nR@*okN4ug1*=$@1t(UrM>f=V_`Yal=xK_so8A4v zeCeIl(U5jo;-~a-I2os@U&!Xe%JU4$9?H?Iv{vQn2LdoH>hu5#r`4wx@tb{jfbBsR?iv3lk z0{`8pXP@KurzWUZxf8*NH^DS@IsL~rL$-+7X!oh>OnR?Yr6l8e>8wtbWy^%8Leg2a z33`890=4Ebn|OCr`XoWU$26)8;V{)BK@QlvX^c77#Ok`XPwqE(r?2_xOaFa!J>L1s z%RM8b6`oi{yl&pu%j&1f0)I;uQ~Y~hksoXYB?&pPN}H{my+R%{_Fga+C>4JOsEys7 z(&a3@vcEVV5;nOA;s@Hu?S=Nff^P+t-uO_15w$(i&9SB0TB z-|EA|I6}+v0eUf&F|z!<+~6QGKYeP4=ht7U$B&YyJi(7Px;{89dq5fD3DFaC47aAG zJ1obts)RSVM-L~a^NM!7tD>4wG`Cj^5>f32RTY;F1V;`i%0~E$B_kN5R69dnpdYC6 za$q1^R@rf@m_h;!ImOt@zuar~W%LFozfR#99dYzKa7kf^kitYl9tvK(K_m6CH>CM+E~{+m+?OX{X7ZR;5Mh(a?C2AE_QIj}86#MHdje0Vh-PwL&44^ip=GH3@ouPN4Z`8= zEgF+W+%hE5^(C~DlnY&4;_M^ka-rqJik^3-dl6Jwy~I-&w@|Q#B&HZ7>5Ddh-ve9y zXn(Uq5n+8!2Xwd=Xjm0nCmm&_skC5Zooc7K{^rxZ5q-;DC{G8-igSO6dq z^>|yxZsFsPZ#IutiG12XMs)igj9}D^1UjlK_DdK7K^ZG~6M1_E^qb{+=Tq)>7caXt zuAaZ-+ES^LNwD*7;5ba!8$R%b2VT zrO&;nH3P*x?(ddlO(nIY9r9YH%@iEgaRDR?n}igVEyPr9j;D_#`m zcMkwnX1g$I@rdq(Bi4f!CwkHibAug$%E$5o;3W;<^)3E}yn@@SPo_eXh+Pd}iJbB6Dz*TW{4lP-oR# ze@1XTbeMntGut_j?^A})odT&19c4amIquB2Q7AXDSty2DPKO%eh}w*6T} zy2LI_{Qv>Or>$i6C!Hi4*$Xk<5~qF&-^3B@=j#@12*sZbXtK>AxpOYv7KXLl$DBRF zrwpG0St~it2Es;CG-;z0auiHu>_1g*v+L1;%*w=nFl~?B&oo-a1X|~UQHv$y$0U_j zxZYlo#bU=r2M;yI8W;`7)rAv?z*KNB^@V{N=0MH-fMjxB#s3j@LLGT;IYY1Tnq%s? zV@AUchU>pn7E?^0*u?1{Mm2)F*80Ya74U1~=@=$TXrelEU;^R7v(~dQ@QpdEAu0mt z8f>6u*BH8yom_oTt&$~hew6Codx>Y}-q@%#pFx^}iSi}Xm|w@K{yUTAVAo$nDwD!= zgwGUThggf6RA+51KdEP0#T!>GZ6M!FCR4E?>{Bkmd@SA`YH0zi z4XDyCW*ne`vkiQxi-daJ(x=y5{H{=tpoqsf@9KXXe2O;owixG&76LGs92NsH7X^9d z10*Ca#+1t7*4#rG~pDG_|A_7B%VtFQfaTUFA{CfXn<^F@9F#4n@j zjHja4iS{caxJx?*B8!w&iTp^*>~|APPfiKEzFg8#&<^}9-P=r9^OlhLlrNNHXMMy3 z5kgE%4Q)H6I{=F3q77J)ZXItJYaqsQYAf2>3M|CkBu0Ly^2R2BZ zt4JVmP23H?e5fx9e_+3sdD?z8QX7_>Y2;u0_pANgKs}GE!_Z0G5RA1$y(~W+uTd`iq7gC}d;idOX#iTt);Exg;h1GTOg(Pk40671-UrHe2{CSyAx`X!S05GX!?7GNScJ1kKEU zD_d$MY=~4^3A=S(H%#T;yBn}Q>wf)2LM|gaPiA@zDdafh)5UHfP{8ii4Ege!8g@Z7 zN&7QSW>xgR8~Zh7ny_6ka*(!%XesNzw=g2-iDfk%6lvbr{|4#!A+>9iPBv`l3OHQQ zVQx2jlb^OK&`)!I|I_Zkvz@Kzk;dDWn`4pakysb1#Ry58+|_2vFrFpRNhSt>gaT5? zI7aymKhMB>6MYR7gdJn8m*khRh^R)3 zff1Tj62^J3v}k*ws>$HSp}hQ~?q|z4{*kC{b81xH+j8z_j}vznW>u@$#9u~{M6grc z{OVA~Z7gAvoid;CsIF_($>T8UGv>+&H02iMl=LGWziR{fj&ISTcB=`kFCSuaphQ zpCTu0uQTVX@%@>A+bpF(Tp_c1U0(+4`0m{SAiSUcBEYwJKooo`T9OH^_X`vuiJ zk8f)>mksKis*m15TL3|Q{SdtG#Mp~-))Q~*IWBEz8V}TZ{TckAkEwHy4{JYoP(*ya z@S=Df*=LT#OlY?UFTbAtbhXH<-S;e>wR5+N(GaXidcI@amOLq1y*2$#1b#fMBQbj)_OU%!hb9n&pvsb%U`a2e za3pWl()XwF+-G=-;)4LEWdI&#sNpV$P8VsEDL9dCvC#W>V?s&IYoQ*KfFB*9R`#uSU7>~3bfDBe_MV{+w$XKeLYpi964>5f}Vb5V#N1+ZRG{S!jGeLy~b*r zBJ6XHLw#*FU2hgQTs?Z1%5(PJ4Q&x2UP-alImv@(l)JIA0jtM6%gfsg$_MK8GMgTr zg2@ULto2je7HzMYi6xS}wauj78!k7d;93>Gi>?|7vr8NQkcOMl$uV|8c`fi2$HCne zek3?CPDdPYJd1lw>I2>;+QA7bw^-WKlv849-SR7WAoRxv)Pqne*Fk)8&+ z9ZI-6mSiD!n?H0tAQW*e;(M8T5G@X^?GLhF7UF;YIjO;fztM@I+Hp}RAamB+TkSnf zE{Yqtc&67`UY?-G5_n6GS{~$J5dB-u1Xun$atyU+F2-5YbAC#G`@t-I}{?(I^f17q^}sVQ%*@}*4-pOUB=6_ zyJ!0-AQF#(%H8ZjLn;&zKx{H3X?&h?F?%{!na6U%k|%Nb87iitJ}H-|rDV>GlUCiV7y+w!XW&D`*gtf+}EgUd{J*>ybA%$+pl6e&`GPr z2R}4&s|t*^(AfO7ZWf(N$L7#|CF>OVX8vj-s7@~>J`1C3B!Y))!)?1w(+*OMX6fbvg|TFV|u#7eeuhe*lUL1Ui| zdwp|O{b}mKmh8s>Rpj|OygHd+87|@#hm_jR=5h^rf%BT?Xkj3g1$gPtJKjQ^{brx< z36a{ha;d&+1!rgJ!tWIEyrB@~VfuH#v1)yai^A;FcJGP;ZjxO9tpvQO5s2hu<{f_d zcA&012fD~Zm@Ipc0xVN-y%kJh?k>?XQi%2O^SsJ%48Llv(_8I(EjeKX)rAhL{|={v z)&^J_Gl6Fd*7)o+OA;#KxRR?@W<}dnyw( z@p8k!AAp6ht(=`npZkLe)!v)T5U^^6nHb3S2?nBaFnd6s^5Qf=Xm1$RL<+ygu=7*p z>lX`AUn&tg`C_7YQ&Fu(rwqN?1{pr|Ryc}tqn z$_{c9h>=_I@Zn#)zSCzy7X;>mQ!3O@75D*NvP*pIjgjr{qG18vE6EAe_OHJSB>r_j z)MoBGB+0x)JX{i#{$yWK_@HDwSe-qE#B}oDf?5o?LNbqqQGYpD?3 zYCU?0$;yBOZ*%|ME>g?1sjH`CZ2TMM;ReGLwdw4AA8ts~nM>%1o zAoG(HR~n4@nyd-+Y}JEG=Xcm$3Awx-c9=^^ntbJ+ts4jq_C(op)nQ}I+ZT~Tp6Iy> zt7T^a=Ph5lfw}-`8bxs&Kez|jbeRABaLYC?qJ$u>u!!%S`dj>-PGWE=wl!s7!&C zc_VCoK~vrzm-NFgkFX3>-4_5h%VHgHbIX18A;@og){;Wf*tZ3F-q}-k46S@pyU~D6 zf-#?%7~B;7(uYW#F2rq|I@P*7s4w1e{G5Uk%-mJ{`_1!@$afEBWcw%{pf5(&K>qz@ zVtypKC;p2n7W#@}zc}PPHsR>b{9+iqKFnX9x`2nM+lpw%aWUcdN(%1YH3W}r;KJK} z{o#3^4^wrC>{tL5_`II}px;sfyguPCI?IuWBKr`;nyLOA>#GPAbMdWE@25*pNC-xC z_a(O??+(TFPd&eMAF9CHY6czK9Awl5orQcq$@!Q+8*LBA*PD#OM1Em}ndX5yYC?k= z8o(1klU~7j%i9%_&>6#Ua9#V?DYxCf{L`UJ=OBwtnSEOXK!JSEVMjRl!On7%++VR(Rn^W1N4w!$rL{ukHic<#ubYFHsLo6kzjgi`yl~pPF z#bjfL@&+!$NC@Iq%=tRXm9rl7l4&!z`eA(+ccQr!7{T%dZ?Tkqo%1_MQgIw2&`@$h z`Petk7SVC6axVg=Ba1pS0F|G4+ z+ugnu4|5JZz@r$~%0}a;<8MeG9A|lZ6D(H$#pW<6W@8mKN$j$o&O;-`p;dLR&8 zSitFLzYJXb)@+h2?OWnqPRD!_*3)TLjr6@493Dd4enb-^pxVUjvDn2v$-K<0Gc&h} zr5TRlvdQ0Pvr->`exE9uiQXilT>ch&S(q5%scoAe5`ErR97|OqA|wd&3ugaGvWmZi_glyPQ2=WM1`Q@cE}MjR{h1_3@3Rt> zfFkBhDCRMvI6(W}i9b4a0=DO$r{D~hF1pxtp|8MVt5;xq;jc8n7+UMr_;8Ya!lBd$SC(VHv>V3G=Q8px zWus2Se<&t2va;{IX`Wt@>G4$wDOCK$Vm@qPtNq8L0I~ZNtvcOj4sS4E1#$yR@)0Q(|4?ei--r8+By1wII7D}E8LED8ka!m^ZB5IAkYh}CRCv+*+ahig@;VGZk>rl z1pdJcm{SWMF*1RqXC4H^T))WqJH))*owp*ipM# zODKLjxgWm$8Hm9W!upI1iY_TTH)5z`Sg}3_!su-=`B#X%sx2(tXFb<=FRYT`Slgv{ zDGKAV%NmNgVL0x4+(o)Za>XX0z&H6QL|i|FUE6ck-8T9zVgAo^kVJ6jMr`noH42Y!m;0hi*H^5Ju6v6IgH>;iu|tENa} z2dB_i^`YC4N23a=ts-u}0|X9v8QZ!}avB9y{({QxCfE5Upo10fD_IGAi=R?oni>A2 zV4rPh#uK{~tKsRzyKkblF0(M!Kz8i`zoKe~+hPx3#V*E6cTZOF39dW(5S&0&2?+>g zmyT9(?1`Y(5*v*?9Ve{YDYsO5CQd9fm&A3pUD#NV z>RwTyoiQ$=PuXl1##*WOx0l=QcGFD#D>EwPvH+v>z0+X>p<1V<#NRl zPla*@u!!>Y1+*)b{i)Vv;#=`%q>7Fcq9`3cMY2w`+WXD394%cw?rHApk{lxbL+)7M;mJ)hHmke3n)jPs zNCaApYIleUH$z_BU`oxk2kCm}+ve6M+0I6!GvrhUXb1Qw1RUC`=sn0gIL9h$xsK}w z$OlB^tHlW`okTD{y$FVACQMk+m{?Q3fn6$?k43t$@{d5O<-)wlSY(9fsy;g@f){Tv zXY9!eZ8R*X?Lf}4#c5j|^^Qx(%RJ7~uVK|Ln$^4I40a6iuQKsHxvKquAaL2;iru(m z9SGB{4pJ=I`eo}99oymf@tCjN`Irtj!n7-vq`VS&ccXU{Oz@X`*Sbt@2jR&kD$8t&4M5bk|0!XL-!)2A}ID z$}MPs`|_D97bywNA3Ax)Zf)5)q29})KqBYgC5zP)Y~v@4eX$vznmbAsEc!i5kM*vd z`L)*P&fJ_W*-M+o@87VrW;c>%J^fAenPT`rE1@=JNb_;TSTdo=qw`K%hf{;!K2k;> zpA@G40dJRm2GP+Q6tElj2$YiB#hH?GC!rq6fIaeG8Y78YK9KASXkvqE{>G8x91ac@ zEOM3JEQWA}eqn0lS#v#BT6}U?W7ld_sRCPrWpx|JnvR;8$AY50`0l$2tbugy6_FcE zTtIqBR&T!x2Mo1{L^Zri@qpC_&-F8M=z9+U@m{LSXz&gg>WV8bgNB12nf1F-W}1CF zpt|nvz!noj*~i;8UOEEACSp#-g2J8`RW}trHgHu+rC}zlNhMvQbOz{kgi(As@4AhH zNAbsoT}rvL@5*$S`xg#v&uCh#B+&)uTg!_#I;8kNTqB=SZ}(1BqR-b@DUKp2wdf8^xZdWD=MOI}eq!DsskDf%iESm)`Q zUL0(2il$UHFXp1n*-)LD1!2V1+;8h+`vrIkAALSFHxPl1RAbZrOI>OHG<|z6BDYo$ zf)mGLEGipc`BqA}Ej~E#Rb@H#s?tbyQbr})YVAl{;pXPbCn+lZfwQSugyyMEqGcc$ z$1to%NK|=A=G~rOFqa`)6Z`DrJs8}hTNWF}i$1rsQ}BGkt$$1Y@)8#(j4ScZ0_+Qs zcfkBOx}sgk`6e&onj{1HfsJg$L|2c4BwD#@&o4nHo9Z%oYjpf4nHLw5(Ih$yyOYZy z%jvB#!PB28bmPYSvnl*nM)^^8yBBf>)!U)7{bIWpTPFwa%8U0-mc7-kiMAKUh%cb8 zd4zoE^0DdQYn&P2Yf+NyA-7TB*b%x&MsD&SO=~oD?S!}sD9FDeE`{1{CqhtJi}T>1 zFG=oV^499iYskdTPLQ-0_W{<@16+6)1oFQxp5D8F)-E zJ-hVZYrxyXldbWzi^06SL>!}v9(hjE>agggVY+t|wT%JZzq2mIaTXMkMvAb>Nm=f@ zePjb-P^}WJIG%Ei9t9W?+L@Xs)nEO|Q#eCu8f4g1Gi;gKs~Vg)@arDYOrC`aXatlW z5x1<=%AQ0Nf#Qz7Xl36>coCqv4WvMCLP9|y3kk_ysa1QGV=iFRNmhD=kc|JBKP)%N zOVeNEm3QE2t6rwKHiOa&AwJ4VZQyeQi}?ahXOtDFxHOORk?qY3+QgN69hVv$(3aqv zAl?|KMa=>MfIV$);?6_{urp%Ekz>cLT#r73_b|2mC6=q{9V96`8s#rj;P)Cp>!h>? zjtR3Gfv>%<()9#!(&P1QLXuR-d4oSE|M%2X_QmL^5~fm0TF1+Foo7Wsj!Oc<6fdBYm8JvS$kb3%y6fj{+ejoo@tF%3o%-u7yB^~Q6 z)@V^=apE(Dgt#_p>Q-!CH6BvSc6l`aXithNjk|$xh!;+eU}(%!>igKKR9$IOtg(mu zq-KG)&l0a!WRw;WLFPIBSIUy{|44aB8F#C+{!T12<(1taZ^ohDt?Z0lnrhdCVPAZ} z=5N%luCWxZ2g!*aumugO^sY$d6NaP`j?r=Yb(za}KY{7YxDwl#1DcmAWL=j^i< z4op7O;9z?P_9wmz;!f)M==(SEvg4F~jr!DFq}e@Klf-cy(YNk7n|8a3=qb$%t+jK_qhY$W;{fTYENTgXPH`Jh2>7Jlc%$1&tzd2 z)DdoU!qA21{YU2Vj4C(6u_qGCo7BBaybz=sZb;ujUDLaIUi_+Lthu3ezmFW5*NNmO zWW~;QZg%SDH3cy!tb~yxY_e5-(}m$~R(YwIdkI(orc#hO`zj_=ZLZo&t{o;}r5pFy zd61}A8R|y4LsX9y*N6l3H%2Z@o?V(oRRbPVtPpmfmCtF*rqW%>JrFbN86SLNHAF0{ ztkRi?8_q~!&hHg@D;0(%$&RFiQ2kzMPUzxD&oZJ6VGvE_eT0^uLjK2`rE(~)pr4Lm zgdf0By^Nk39c)EwwD1!AHyKH%CP)q+>QnM%L5k=>F~_wH5f9ixrQ$&VSbNd%lKDS+ zrYMKF0rA?SHGGvR|3+D3mYKyB)S6UZXQO~Iv<+_mXHAh==-rLDl{;&A2%!)Sn9!M# zHPvoVIVtHsE~*2^>>`hNF8hP+(!sVGa>YMqZy=OMKFvo_u^?-Aax58@hC-b6`E_kbSkW_ENlo!C;Hgs`ND zr*SXAya;r){3Mngo8onL(z}s%lxHn}4J9Z3LGJ!c`54lH2-f9)5B|@(&3!5Q^X>Po zVLY8Sodrwy@~~EN7E!^nn5VAyus#*H9eR^yEpJ?MMH;0CZCAGIf6W$f=JKET8{O($ zkU_Xa(Q!a;A6Tlk_0sK8u-a|MP(%DaO-drYUvG>QN0KEE9t#Iw%0F>8;GWU;`O-kR zTQ66vbzFSe?zN69ee+^!sDhUw@vbL`C`nis#ejsINFW0&C}?X{{xL5z95nO2fZ;6pi zU(qUY)`3ukxNm=rXC)3)-5MTZNu*i=)B9M4wz4*iiqqvze2olMwtR^w@dBTmTN~*v zXDtL|B=D3czLd-UPpOCRF?|LIePCsoky~jVKIr8U^4P0+s=Ob6y|AnN$3lic6(*v^~k+hFCzV7`TZ9>Yu}60OFtB&mr+d9U{_VCN2FZWQ67KAQtS%8kUG#Lo$|C@CCv-;*E1i# zYWvNG^h?ryk0}rSPPF#gYbP?hKDpz1f*+EgSl3v$*Yz0U{hlcTKq~e6GU=dDb@d+% z@YvnUOA6w5eoG!+a6enUeTUNVAfvVzxHnktQL5DoK}twzH|1eZSv(`Ue)b5-^AAZn zqRC%NYeTU--SnI9+si==*RX=UJF?E!y@=2ae!+^SyA2L=cT@3xoKk>+x z{;s^WZR;lU*|XTd5%S%}k&DZhg8dAuBON;?H6KEN3KAGB#rlGYNPca!8fB!PVU=U6 z-pq8h0uujIK@FFOCC^iwJ;&O{<=JWb;?XxQmqusZp5Px?2ITj3VY8UP5sI+${UHvI zf`c8Ugg+NdL0Ntid4L$WV3%&?&lF6+&!aFsv9HNCh`7(Z7PvI3b3IckUg6e%xlM_X zFO8v#sdaT!1aENi0M+v=})Rt6nnQnV!YyhA%q(xRx>ii2`9Z7 z<~1t8p9c(o)K;V(CvQZ$i0mnoM=lu3M(x5!K|gF7*rV!?PDoJc!0At8*b4u0%7q#B z=mf=0gWY*pS)`-6YL$xaAWQCsPU`K|h9;W-&V+N3W&_hqcR3yTIZCg3=B z*P_85Lj_?%`yh{DuV>?_ui_N&D2G19x@~NPt|367>3k5q>@pEjY;%Wc0x!e^TfnT- zqw#m6!`6Fr|KqSyW�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 -
+
@@ -208,6 +207,39 @@
+ --> + +
+
+
+
+
+ + + re3 data logo + +
+
+
+
+
+
+ + logo geosphere austria + +
+
+
+
+
+
+ + logo base + +
+
+
+
diff --git a/vue.config.cjs b/vue.config.cjs index 539ff81..a15c57a 100644 --- a/vue.config.cjs +++ b/vue.config.cjs @@ -5,6 +5,7 @@ const webpack = require("webpack"); const { VueLoaderPlugin } = require("vue-loader"); module.exports = { + lintOnSave: false, publicPath: "/", chainWebpack: (config) => { const vueRule = config.module.rule("vue"); From 1f855b9629c388592fbb7abf977bd580ff1d73aa Mon Sep 17 00:00:00 2001 From: frankporras Date: Thu, 2 May 2024 11:06:48 +0200 Subject: [PATCH 14/64] Fixing last changes of logos in bottom of main page --- src/App.vue | 6 +++--- src/views/home-view/home-view-component.vue | 13 +++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/App.vue b/src/App.vue index b9d94d2..09d8b43 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,13 +1,13 @@ --> - + + { {{ filterItemsAlias(categoryAlias) }} + {{ getFilterItemsAlias(categoryAlias) }} diff --git a/src/components/vs-input/vs-input.ts b/src/components/vs-input/vs-input.ts index d815ee9..822343a 100644 --- a/src/components/vs-input/vs-input.ts +++ b/src/components/vs-input/vs-input.ts @@ -193,7 +193,26 @@ export default class VsInput extends Vue { const sanitizedValue = DOMPurify.sanitize(result.highlight); // Replacing the predefined format for highlights given by OpenSearch from emphasys to bold const replacedValue = sanitizedValue.replace(//g, '').replace(/<\/em>/g, ''); - return `${replacedValue} | ${result.type}`; + // return `${replacedValue} | ${result.type}`; + return `${replacedValue} | ${this.getTypeAlias(result.type)}`; + } + + /** + * The alias for the result type will be set depending on the name of the type. + * This will allow to display the customised terms instead of the values currently used in the OpenSearch index. + * TODO: This should be corrected directly in the index + */ + getTypeAlias(type: string): string { + switch (type) { + case "author": + return "creator"; + case "subjects": + return "keyword"; + case "doctype": + return "data type"; + default: + return type; + } } /** diff --git a/src/views/search-view/search-view-component.ts b/src/views/search-view/search-view-component.ts index 96e3fe4..d8e666c 100644 --- a/src/views/search-view/search-view-component.ts +++ b/src/views/search-view/search-view-component.ts @@ -74,12 +74,31 @@ export default class SearchViewComponent extends Vue { if (typeof this.searchTerm === "string") { return this.searchTerm; } else if (this.searchTerm instanceof Suggestion) { - return this.searchTerm.value + " (" + this.searchTerm.type + ")"; + return this.searchTerm.value + " (" + this.getTypeAlias(this.searchTerm.type) + ")"; + // return this.searchTerm.value + " (" + this.searchTerm.type + ")"; } else { return ""; } } + /** + * The alias for the search term type will be set depending on the name of the type. + * This will allow to display the customised terms instead of the values currently used in the OpenSearch index. + * TODO: This should be corrected directly in the index + */ + getTypeAlias(type: string): string { + switch (type) { + case "author": + return "creator"; + case "subjects": + return "keyword"; + case "doctype": + return "data type"; + default: + return type; + } + } + // Method to check if a search term is present hasSearchTerm(): boolean { if (typeof this.searchTerm === "string" && this.searchTerm !== "") { From bb7d8eb378a55f2c025775b2ec7a79a23abe3cdd Mon Sep 17 00:00:00 2001 From: frankporras Date: Tue, 3 Sep 2024 16:13:27 +0200 Subject: [PATCH 56/64] - Coverage section reformatted - Keywords section converted in linked elements --- src/models/dataset.ts | 62 ++++++++++++++++--- .../dataset-detail.component.ts | 8 +++ .../dataset-detail.component.vue | 25 +++++++- 3 files changed, 83 insertions(+), 12 deletions(-) diff --git a/src/models/dataset.ts b/src/models/dataset.ts index 16e5271..9e38775 100644 --- a/src/models/dataset.ts +++ b/src/models/dataset.ts @@ -235,17 +235,31 @@ export class DbDataset { const yMax = this.coverage.y_max; // const elevationAbsolut = this.coverage.elevation_absolut; + // let geoLocation = + // "- SOUTH-BOUND LATITUDE: " + + // yMin + + // "\n" + + // "- WEST-BOUND LONGITUDE: " + + // xMin + + // "\n" + + // "- NORTH-BOUND LATITUDE: " + + // yMax + + // "\n" + + // "- EAST-BOUND LONGITUDE: " + + // xMax; + let geoLocation = - "* SOUTH-BOUND LATITUDE: " + + // "- SOUTH-BOUND LATITUDE: " + + "- South-bound Latitude: " + yMin + "\n" + - "* WEST-BOUND LONGITUDE: " + + "- West-bound Longitude: " + xMin + "\n" + - "* NORTH-BOUND LATITUDE: " + + "- North-bound Latitude: " + yMax + "\n" + - "* EAST-BOUND LONGITUDE: " + + "- East-bound Longitude: " + xMax; // geoLocation += elevationAbsolut != null ? ` * ELEVATION ABSOLUT: ${elevationAbsolut}\n` : ""; @@ -254,31 +268,59 @@ export class DbDataset { let elevation = ""; if (this.coverage.elevation_max != null && this.coverage.elevation_min != null) { - elevation += "\n* ELEVATION MIN: " + this.coverage.elevation_min + " *\nELEVATION MAX: " + this.coverage.elevation_max; + // elevation += "\n- ELEVATION MIN: " + this.coverage.elevation_min + " \n- ELEVATION MAX: " + this.coverage.elevation_max; + elevation += "\n- Elevation Min.: " + this.coverage.elevation_min + " m\n- Elevation Max.: " + this.coverage.elevation_max + " m"; } if (this.coverage.elevation_absolut != null) { - elevation += "\n* ELEVATION ABSOLUT: " + this.coverage.elevation_absolut; + elevation += "\n- Elevation Absolut: " + this.coverage.elevation_absolut + " m"; } if (elevation != "") geoLocation += elevation; let depth = ""; if (this.coverage.depth_max != null && this.coverage.depth_min != null) { - depth += "\n* DEPTH MIN: " + this.coverage.depth_min + "\n* DEPTH MAX: " + this.coverage.depth_max; + depth += "\n- Depth Min.: " + this.coverage.depth_min + " m\n- Depth Max.: " + this.coverage.depth_max + " m"; } if (this.coverage.elevation_absolut != null) { - depth += "\n* DEPTH ABSOLUT: " + this.coverage.depth_absolut; + depth += "\n- Depth Absolut: " + this.coverage.depth_absolut + " m"; } if (depth != "") geoLocation += depth; let time = ""; if (this.coverage.time_max != null && this.coverage.time_min != null) { - time += "\n* TIME MIN: " + this.coverage.time_min + "\n* TIME MAX: " + this.coverage.time_max; + time += "\n* Time Min.: " + this.coverage.time_min + "\n* Time Max.: " + this.coverage.time_max; } if (this.coverage.time_absolut != null) { - time += "\n* TIME ABSOLUT: " + this.coverage.time_absolut; + time += "\n* Time Absolut: " + this.coverage.time_absolut; } if (time != "") geoLocation += time; + // let elevation = ""; + // if (this.coverage.elevation_max != null && this.coverage.elevation_min != null) { + // elevation += "\n* ELEVATION MIN: " + this.coverage.elevation_min + " \n* ELEVATION MAX: " + this.coverage.elevation_max; + // } + // if (this.coverage.elevation_absolut != null) { + // elevation += "\n* ELEVATION ABSOLUT: " + this.coverage.elevation_absolut; + // } + // if (elevation != "") geoLocation += elevation; + + // let depth = ""; + // if (this.coverage.depth_max != null && this.coverage.depth_min != null) { + // depth += "\n* DEPTH MIN: " + this.coverage.depth_min + "\n* DEPTH MAX: " + this.coverage.depth_max; + // } + // if (this.coverage.elevation_absolut != null) { + // depth += "\n* DEPTH ABSOLUT: " + this.coverage.depth_absolut; + // } + // if (depth != "") geoLocation += depth; + + // let time = ""; + // if (this.coverage.time_max != null && this.coverage.time_min != null) { + // time += "\n* TIME MIN: " + this.coverage.time_min + "\n* TIME MAX: " + this.coverage.time_max; + // } + // if (this.coverage.time_absolut != null) { + // time += "\n* TIME ABSOLUT: " + this.coverage.time_absolut; + // } + // if (time != "") geoLocation += time; + return geoLocation; } else { return ""; diff --git a/src/views/dataset-detail.component/dataset-detail.component.ts b/src/views/dataset-detail.component/dataset-detail.component.ts index 9b35e58..0a04e1a 100644 --- a/src/views/dataset-detail.component/dataset-detail.component.ts +++ b/src/views/dataset-detail.component/dataset-detail.component.ts @@ -156,6 +156,14 @@ export default class DatasetDetailComponent extends Vue { // return moment(date).format("YYYY"); } + public getLanguage(language: string): string { + if (language === "de") { + return "Deutsch" + } else { + return "English" + } + } + public getCitation(): string { let citation = this.dataset.authors .map((u) => { diff --git a/src/views/dataset-detail.component/dataset-detail.component.vue b/src/views/dataset-detail.component/dataset-detail.component.vue index 0a94183..9818861 100644 --- a/src/views/dataset-detail.component/dataset-detail.component.vue +++ b/src/views/dataset-detail.component/dataset-detail.component.vue @@ -195,7 +195,7 @@

-

-
+ +
+
+

Schlüsselwörter/Keywords

+

+ + + {{ subject.value }} + + + , + +

+

-

+
+ + +

Erstellungsjahr/Year

@@ -224,7 +245,7 @@

Sprache/Language

- {{ dataset.language }} + {{ getLanguage(dataset.language) }}

From 50ab31885417383663ec053010ab105bf760f7f2 Mon Sep 17 00:00:00 2001 From: frankporras Date: Wed, 4 Sep 2024 13:46:09 +0200 Subject: [PATCH 57/64] - Icon and link for licenses added - Listing of authors in list of publications corrected - Coverage section improved - Contributor section moved down --- src/components/vs-result/vs-result.ts | 10 +++ src/components/vs-result/vs-result.vue | 29 ++++++-- src/models/dataset.ts | 18 +++-- .../dataset-detail.component.ts | 2 +- .../dataset-detail.component.vue | 67 +++++++++++++++---- 5 files changed, 103 insertions(+), 23 deletions(-) diff --git a/src/components/vs-result/vs-result.ts b/src/components/vs-result/vs-result.ts index d731acc..39f6514 100644 --- a/src/components/vs-result/vs-result.ts +++ b/src/components/vs-result/vs-result.ts @@ -14,6 +14,16 @@ export default class VsResult extends Vue { return this.datasets; } + public simplifyAuthor(author:string): string { + + if (author.endsWith(" ")) { + return author.substring(0, author.indexOf(",")); + } else { + let firstNameInitial:string = author.charAt(author.indexOf(",") + 2); + return author.substring(0, author.indexOf(",") + 2) + firstNameInitial; + } + } + public getDomainWithoutSubdomain(): string { const urlParts = new URL(window.location.href).hostname.split("."); diff --git a/src/components/vs-result/vs-result.vue b/src/components/vs-result/vs-result.vue index 20c7479..5387123 100644 --- a/src/components/vs-result/vs-result.vue +++ b/src/components/vs-result/vs-result.vue @@ -6,13 +6,34 @@ {{ "https://doi.org/" + document.identifier[0] + " ➤" }}   - {{ document.author[0] }} + + + + + + + {{ simplifyAuthor(document.author[0]) }} + + + + + {{ simplifyAuthor(author) }}; + + + + + + {{ simplifyAuthor(author) }}; + + et al. + +

- {{ - document.title_output - }} + + {{ document.title_output }} +

diff --git a/src/models/dataset.ts b/src/models/dataset.ts index 9e38775..e4f054e 100644 --- a/src/models/dataset.ts +++ b/src/models/dataset.ts @@ -274,7 +274,7 @@ export class DbDataset { if (this.coverage.elevation_absolut != null) { elevation += "\n- Elevation Absolut: " + this.coverage.elevation_absolut + " m"; } - if (elevation != "") geoLocation += elevation; + // if (elevation != "") geoLocation += ("\n---" + elevation); let depth = ""; if (this.coverage.depth_max != null && this.coverage.depth_min != null) { @@ -283,16 +283,16 @@ export class DbDataset { if (this.coverage.elevation_absolut != null) { depth += "\n- Depth Absolut: " + this.coverage.depth_absolut + " m"; } - if (depth != "") geoLocation += depth; + // if (depth != "") geoLocation += depth; let time = ""; if (this.coverage.time_max != null && this.coverage.time_min != null) { - time += "\n* Time Min.: " + this.coverage.time_min + "\n* Time Max.: " + this.coverage.time_max; + time += "\n- Time Min.: " + this.coverage.time_min + "\n- Time Max.: " + this.coverage.time_max; } if (this.coverage.time_absolut != null) { - time += "\n* Time Absolut: " + this.coverage.time_absolut; + time += "\n- Time Absolut: " + this.coverage.time_absolut; } - if (time != "") geoLocation += time; + // if (time != "") geoLocation += time; // let elevation = ""; // if (this.coverage.elevation_max != null && this.coverage.elevation_min != null) { @@ -321,7 +321,13 @@ export class DbDataset { // } // if (time != "") geoLocation += time; - return geoLocation; + if (elevation != "" || depth != "" || time != "" ) { + return geoLocation + "\n ---" + elevation + depth + time; + } else { + return geoLocation + elevation + depth + time; + } + + // return geoLocation; } else { return ""; } diff --git a/src/views/dataset-detail.component/dataset-detail.component.ts b/src/views/dataset-detail.component/dataset-detail.component.ts index 0a04e1a..5185e93 100644 --- a/src/views/dataset-detail.component/dataset-detail.component.ts +++ b/src/views/dataset-detail.component/dataset-detail.component.ts @@ -177,7 +177,7 @@ export default class DatasetDetailComponent extends Vue { .join(", "); citation += " (" + dayjs(this.dataset.server_date_published).format("YYYY") + "): "; citation += this.dataset.MainTitle?.value; - citation += "." + this.dataset.creating_corporation + ", "; + citation += ". " + this.dataset.creating_corporation + ", "; citation += this.dataset.publisher_name; citation += ", Wien"; return citation; diff --git a/src/views/dataset-detail.component/dataset-detail.component.vue b/src/views/dataset-detail.component/dataset-detail.component.vue index 9818861..66068d4 100644 --- a/src/views/dataset-detail.component/dataset-detail.component.vue +++ b/src/views/dataset-detail.component/dataset-detail.component.vue @@ -186,15 +186,7 @@

-
-
-

Beitragende/Contributor

-

- {{ dataset.contributors.map((u) => u.full_name).join(", ") }} -

-

-

-
-
+ +
+
+
+
+ + + re3 data logo + +
+
+
+
+
+
+ + logo geosphere austria + +
+
+
+
+
+
+ + logo base + +
+
+
+
+ + + +
@@ -338,7 +380,8 @@
- + --> + From 013d12e7b31ad6be74e2510ca7427a11edf765db Mon Sep 17 00:00:00 2001 From: frankporras Date: Tue, 10 Sep 2024 16:23:20 +0200 Subject: [PATCH 58/64] Attribution in minimap corrected --- src/components/minimap/Minimap.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/minimap/Minimap.ts b/src/components/minimap/Minimap.ts index 5bdb079..35092db 100644 --- a/src/components/minimap/Minimap.ts +++ b/src/components/minimap/Minimap.ts @@ -24,6 +24,9 @@ export default class Minimap extends Vue { maxBoundsViscosity: 1.0 // Ensure the map cannot be dragged outside the bounds }); + // Remove Leaflet logo and text + map.attributionControl.setPrefix(false); + const basemapAtLayer = L.tileLayer('https://maps{s}.wien.gv.at/basemap/geolandbasemap/normal/google3857/{z}/{y}/{x}.png', { attribution: 'basemap.at', noWrap: true, @@ -31,11 +34,11 @@ export default class Minimap extends Vue { }).addTo(map); const esriImageryLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { - attribution: 'Tiles © Esri' + attribution: 'Tiles © Esri' }); const esriTopoLayer = L.tileLayer('https://server.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', { - attribution: 'Tiles © Esri' + attribution: 'Tiles © Esri' }); const baseMaps = { @@ -52,7 +55,7 @@ export default class Minimap extends Vue { if (southWest[0] === northEast[0] || southWest[1] === northEast[1]) { // If y_min and y_max (and x_min and x_max) are equal, generate a circle const center = [southWest[0], southWest[1]] as [number, number]; -// Using CircleMarker to maintain constant size regardless of zoom level + // Using CircleMarker to maintain constant size regardless of zoom level const circleMarker = L.circleMarker(center, { color: '#30D5C8', // Outline color fillColor: '#336699', // Fill color From 6f1b9f4c5f6ed9600c40865df6ea6e3b365ad129 Mon Sep 17 00:00:00 2001 From: frankporras Date: Thu, 12 Sep 2024 15:54:59 +0200 Subject: [PATCH 59/64] - Code cleaning for OpenSearch - Added comments - Facets menu small change --- .../face-category/facet-category.vue | 6 +- .../dataset.service - Tests with OpenSearch | 161 ++++++++ src/services/dataset.service.ts | 350 +++--------------- .../search-view/search-view-component.ts | 134 +++---- .../search-view/search-view-component.vue | 2 +- 5 files changed, 264 insertions(+), 389 deletions(-) create mode 100644 src/services/dataset.service - Tests with OpenSearch diff --git a/src/components/face-category/facet-category.vue b/src/components/face-category/facet-category.vue index b7c5c1d..bf3620a 100644 --- a/src/components/face-category/facet-category.vue +++ b/src/components/face-category/facet-category.vue @@ -76,7 +76,10 @@ export default FacetCategory; flex-grow: 1; flex-shrink: 0; /* padding: 0.75rem; */ - padding: 0.75em 2em; + padding-top: 0em; + padding-right: 2em; + padding-bottom: 0.75em; + padding-left: 2em; justify-content: left; } @@ -89,6 +92,7 @@ export default FacetCategory; } .panel-body { padding: 0 2em; + padding-bottom: 0.75em; /* Increase padding at the bottom */ } .disabled { diff --git a/src/services/dataset.service - Tests with OpenSearch b/src/services/dataset.service - Tests with OpenSearch new file mode 100644 index 0000000..db453f0 --- /dev/null +++ b/src/services/dataset.service - Tests with OpenSearch @@ -0,0 +1,161 @@ + // public facetedSearchOPEN( + // suggestion: Suggestion | string, + // activeFilterCategories: ActiveFilterCategories, + // openCore: string, + // openHost: string, + // start?: string, // Starting page + // ): Observable { + // // OpenSearch endpoint + // const host = openHost; + // const path = "/" + openCore + "/_search"; + // const base = host + path; + + // // Constructing Filters Based on Active Filter Categories + // const filters = Object.entries(activeFilterCategories).map(([category, values]) => { + // if (category === "language" || category === "year") { + // return { terms: { [category]: values } }; + // } else { + // return { terms: { [`${category}.keyword`]: values } }; + // } + // }); + // console.log("filters:", filters); + + // // Determine search term and query fields based on the suggestion type + // let query; + // if (typeof suggestion === "string") { // If suggestion is a string, append a wildcard (*) for partial matches + // const lowercaseTerm = suggestion.toLowerCase() + // query = { + // bool: { + // should: [ + // { match: { title: { query: suggestion, fuzziness: "AUTO", boost: 3 } } }, + // { match: { author: { query: suggestion, fuzziness: "AUTO", boost: 2 } } }, + // { match: { subjects: { query: suggestion, fuzziness: "AUTO", boost: 1 } } }, + // { wildcard: { title: { value: `${lowercaseTerm}*`, boost: 3 } } }, + // { wildcard: { author: { value: `${lowercaseTerm}*`, boost: 2 } } }, + // { wildcard: { subjects: { value: `${lowercaseTerm}*`, boost: 1 } } } + // ], + // minimum_should_match: 1 + // } + // }; + // } else if (suggestion instanceof Suggestion) { // If suggestion is a Suggestion object, form a specific query + // query = { + // match: { + // [suggestion.type]: { + // query: suggestion.value, + // operator: 'and' // all the terms in the query must be present in the field e.g. if is a title, the complete title + // } + // } + // }; + // } + + // // Set default value for start if not provided + // const startValue = start ? parseInt(start) : 0; + + // // console.log(activeFilterCategories); + // // console.log("mainQuery:", mainQuery); + + // // Construct the body of the OpenSearch query + // const body = { + + // query: { + // bool: { + // must: [ + // mainQuery, // Ensure the main query must be satisfied + // ...filters // Ensure all filters must be satisfied + // ] + // } + // }, + + // // // WORKS // Expected: 12 results + // // query: { + // // bool: { + // // "must": [ + // // { "term": { "language": "en" } }, + // // { "term": { "subjects.keyword": "Lower Austria" } }, + // // { "term": { "subjects.keyword": "counting data" } } + // // ], + // // } + // // }, + + // // // THIS WORKS: // Expected: 19 results + // // query: { + // // bool: { + // // must: [ + // // { "match": { "title": "Blatt" } }, + // // { "term": { "subjects": "bayern" } } + // // ], + // // } + // // }, + + // // // WORKS // Expected: 4 results + // // query: { + // // bool: { + // // "must": [ + // // { "match": { "title": "blatt" } }, + // // { "term": { "subjects": "bayern" } }, + // // { "term": { "subjects": "salzburg" } } + // // ], + // // } + // // }, + + // // // WORKS // Expected: 2 results + // // query: { + // // bool: { + // // "must": [ + // // { "match": { "title": "blatt" } }, + // // { "term": { "subjects": "ungarn" } }, + // // { "term": { "subjects": "steiermark" } } + // // ], + // // } + // // }, + + // // WORKS // Expected: 12 results + // query: { + // bool: { + // "must": [ + // { "term": { "language": "en" } }, + // { "term": { "subjects.keyword": "Lower Austria" } }, + // { "term": { "subjects.keyword": "counting data" } } + // ], + // "should": [ + // { match: { title: { query: "halger", fuzziness: "AUTO", boost: 3 } } }, + // { match: { author: { query: "halger", fuzziness: "AUTO", boost: 2 } } }, + // { match: { subjects: { query: "halger", fuzziness: "AUTO", boost: 1 } } }, + // { wildcard: { title: { value: "halger", boost: 3 } } }, + // { wildcard: { author: { value: "halger", boost: 2 } } }, + // { wildcard: { subjects: { value: "halger", boost: 1 } } } + // ], + // minimum_should_match: 1 + // } + // }, + + // size: 10, + // from: startValue, + // sort: [{ _score: { order: "desc" } }], + // track_scores: true, + + // aggs: { + // subjects: { terms: { field: "subjects.keyword", size: 1000 } }, + // language: { terms: { field: "language" } }, + // author: { terms: { field: "author.keyword", size: 1000 } }, + // year: { terms: { field: "year", size: 100 } } + // }, + + // highlight: { + // fields: { + // title: {}, + // author: {}, + // subjects: {} + // } + // } + // }; + + // console.log("mainQuery:", mainQuery); + // console.log("filters:", filters); + // console.log("body:", body); + + // // Make API call to OpenSearch and return the result + // const stations = api.post(base, body); + + // return stations; + // } diff --git a/src/services/dataset.service.ts b/src/services/dataset.service.ts index a494fba..c897b29 100644 --- a/src/services/dataset.service.ts +++ b/src/services/dataset.service.ts @@ -1,5 +1,4 @@ import api from "../api/api"; -// import { Observable, of } from "rxjs"; import { Observable } from "rxjs"; import { tap, map } from "rxjs/operators"; import { Dataset, DbDataset, Suggestion } from "@/models/dataset"; @@ -10,33 +9,23 @@ import { deserialize } from "class-transformer"; class DatasetService { /** - * Fetch data from the OpenSearch endpoint with fuzzy search enabled. - * This function allows for misspellings in the search term and boosts - * the relevance of matches in the title, author, and subject fields. - * - * @param {string} searchTerm - The search term to query. + * Search datasets with OpenSearch API, allowing for fuzzy search and boosting relevance in title, author, and subject fields. + * @param {string} searchTerm - Search query term + * @param {string} openCore - The OpenSearch core to search in + * @param {string} openHost - The OpenSearch host URL + * @returns {Observable} - Observable emitting datasets and their highlights */ - - /* https://tethys.at/solr/rdr_data/select?&0=fl%3Did%2Clicence%2Cserver_date_published%2Cabstract_output%2Cidentifier%2Ctitle_output%2Ctitle_additional%2Cauthor%2Csubject%2Cdoctype&q=%2A - &q.op=or&defType=edismax&qf=title%5E3%20author%5E2%20subject%5E1&indent=on&wt=json&rows=10&start=0&sort=server_date_published%20desc&facet=on&json.facet.language=%7B%20type%3A%20%22 - terms%22%2C%20field%3A%20%22language%22%20%7D&json.facet.subject=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22subject%22%2C%20limit%3A%20-1%20%7D&json.facet.year=%7B%20type%3A%20%22 - terms%22%2C%20field%3A%20%22year%22%20%7D&json.facet.author=%7B%20type%3A%20%22terms%22%2C%20field%3A%20%22author_facet%22%2C%20limit%3A%20-1%20%7D - */ - - // private openSearchUrl = "http://opensearch.geoinformation.dev/tethys-records/_search"; - // private openSearchUrl = "http://192.168.21.18/tethys-records/_search"; - public searchTerm(term: string, openCore: string, openHost: string): Observable<{ datasets: Dataset[], highlights: HitHighlight[] }> { - // console.log("SEARCHTERM"); - - // OpenSearch endpoint - const host = openHost; // When using local OpenSearch dev endpoint - const path = "/" + openCore + "/_search"; - const base = host + path; + + const host = openHost; // OpenSearch host URL + const path = "/" + openCore + "/_search"; // API endpoint for searching + const base = host + path; // Complete URL for the request /** * The match query used for title, author, and subjects fields is case-insensitive by default. The standard analyzer is typically used, which lowercases the terms. * The wildcard query is case-sensitive by default. To make it case-insensitive, it is needed to use a lowercase filter */ const lowercaseTerm = term.toLowerCase(); // Lowercase the search term + + // Request body defining search query logic const body = { query: { bool: { @@ -50,13 +39,13 @@ class DatasetService { { wildcard: { subjects: { value: `${lowercaseTerm}*`, boost: 1 } } }, // In SOLR is "subject"! { wildcard: { doctype: { value: `${lowercaseTerm}*`, boost: 1 } } } // doctype ], - minimum_should_match: 1 + minimum_should_match: 1 // Require at least one match } }, - size: 10, - from: 0, + size: 10, // Limit to 10 results + from: 0, // Pagination: start from the first result + sort: [{ _score: { order: "desc" } }], // Sort by relevance (_score) // sort: [{ server_date_published: { order: "desc" } }], - sort: [{ _score: { order: "desc" } }], // Sort by _score in descending order track_scores: true, // This ensures "_score" is included even when sorting by other criteria. Otherwise the relevance score is not calculated aggs: { subjects: { terms: { field: "subjects.keyword", size: 1000 } }, // In SOLR is "subject"! @@ -65,37 +54,23 @@ class DatasetService { year: { terms: { field: "year", size: 100 } }, // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS doctype: { terms: { field: "doctype", size: 50 } } // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS }, - // // CONTABO ================================================================================ - // aggs: { - // subjects: { terms: { field: "subjects.keyword", size: 1000 } }, // In SOLR is "subject"! - // language: { terms: { field: "language.keyword" } }, // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS - // author: { terms: { field: "author.keyword", size: 1000 } }, - // year: { terms: { field: "year.keyword", size: 100 } } // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS - // }, - // // =========================================================================================== highlight: { fields: { - title: {}, - author: {}, - subjects: {}, - doctype: {} + title: {}, // Highlight matching terms in title + author: {}, // Highlight matching terms in author + subjects: {}, // Highlight matching terms in subjects + doctype: {} // Highlight matching terms in document type } } }; - // Make API call to OpenSearch and return the result /** + * Make API call to OpenSearch and return the result * When a POST request is made to the OpenSearch server using the api.post method, the response received from OpenSearch is an object that includes various details about the search results. * One of the key properties of this response object is _source, which is an array of documents (datasets) that match the search criteria. * It is used the pipe method to chain RxJS operators to the Observable returned by api.get. The map operator is used to transform the emitted items of the Observable. */ return api.post(base, body).pipe( - // tap(response => console.log("OpenSearchResponse:", response)), // Log the complete response - // tap(response => console.log("Aggre:", response.aggregations?.subjects.buckets[0])), // log the first subject of the array of subjects returned - // tap(response => console.log("Hits:", response.hits)), // log the first subject of the array of subjects returned - - // map(response => response.hits.hits.map(hit => hit._source)) - map(response => ({ datasets: response.hits.hits.map(hit => hit._source), highlights: response.hits.hits.map(hit => hit.highlight) @@ -104,7 +79,7 @@ class DatasetService { } // // For the autocomplete search. Method to perform a search based on a term - // public searchTerm_SOLR(term: string, solrCore: string, solrHost: string): Observable { + // public searchTermSOLR(term: string, solrCore: string, solrHost: string): Observable { // // SOLR endpoint // const host = "https://" + solrHost; // const path = "/solr/" + solrCore + "/select?"; @@ -123,7 +98,6 @@ class DatasetService { // "doctype", // ].toString(); - // const qfFields = "title^3 author^2 subject^1"; // const q_params = { @@ -146,193 +120,33 @@ class DatasetService { // return stations; // } - // public facetedSearchOPEN( - // suggestion: Suggestion | string, - // activeFilterCategories: ActiveFilterCategories, - // openCore: string, - // openHost: string, - // start?: string, // Starting page - // ): Observable { - // // OpenSearch endpoint - // const host = openHost; - // const path = "/" + openCore + "/_search"; - // const base = host + path; - - // // Constructing Filters Based on Active Filter Categories - // const filters = Object.entries(activeFilterCategories).map(([category, values]) => { - // if (category === "language" || category === "year") { - // return { terms: { [category]: values } }; - // } else { - // return { terms: { [`${category}.keyword`]: values } }; - // } - // }); - // console.log("filters:", filters); - // // Determine search term and query fields based on the suggestion type - // let query; - // if (typeof suggestion === "string") { // If suggestion is a string, append a wildcard (*) for partial matches - // const lowercaseTerm = suggestion.toLowerCase() - // query = { - // bool: { - // should: [ - // { match: { title: { query: suggestion, fuzziness: "AUTO", boost: 3 } } }, - // { match: { author: { query: suggestion, fuzziness: "AUTO", boost: 2 } } }, - // { match: { subjects: { query: suggestion, fuzziness: "AUTO", boost: 1 } } }, - // { wildcard: { title: { value: `${lowercaseTerm}*`, boost: 3 } } }, - // { wildcard: { author: { value: `${lowercaseTerm}*`, boost: 2 } } }, - // { wildcard: { subjects: { value: `${lowercaseTerm}*`, boost: 1 } } } - // ], - // minimum_should_match: 1 - // } - // }; - // } else if (suggestion instanceof Suggestion) { // If suggestion is a Suggestion object, form a specific query - // query = { - // match: { - // [suggestion.type]: { - // query: suggestion.value, - // operator: 'and' // all the terms in the query must be present in the field e.g. if is a title, the complete title - // } - // } - // }; - // } - - // // Set default value for start if not provided - // const startValue = start ? parseInt(start) : 0; - - // // console.log(activeFilterCategories); - // // console.log("mainQuery:", mainQuery); - - // // Construct the body of the OpenSearch query - // const body = { - - // query: { - // bool: { - // must: [ - // mainQuery, // Ensure the main query must be satisfied - // ...filters // Ensure all filters must be satisfied - // ] - // } - // }, - - // // // WORKS // Expected: 12 results - // // query: { - // // bool: { - // // "must": [ - // // { "term": { "language": "en" } }, - // // { "term": { "subjects.keyword": "Lower Austria" } }, - // // { "term": { "subjects.keyword": "counting data" } } - // // ], - // // } - // // }, - - // // // THIS WORKS: // Expected: 19 results - // // query: { - // // bool: { - // // must: [ - // // { "match": { "title": "Blatt" } }, - // // { "term": { "subjects": "bayern" } } - // // ], - // // } - // // }, - - // // // WORKS // Expected: 4 results - // // query: { - // // bool: { - // // "must": [ - // // { "match": { "title": "blatt" } }, - // // { "term": { "subjects": "bayern" } }, - // // { "term": { "subjects": "salzburg" } } - // // ], - // // } - // // }, - - // // // WORKS // Expected: 2 results - // // query: { - // // bool: { - // // "must": [ - // // { "match": { "title": "blatt" } }, - // // { "term": { "subjects": "ungarn" } }, - // // { "term": { "subjects": "steiermark" } } - // // ], - // // } - // // }, - - // // WORKS // Expected: 12 results - // query: { - // bool: { - // "must": [ - // { "term": { "language": "en" } }, - // { "term": { "subjects.keyword": "Lower Austria" } }, - // { "term": { "subjects.keyword": "counting data" } } - // ], - // "should": [ - // { match: { title: { query: "halger", fuzziness: "AUTO", boost: 3 } } }, - // { match: { author: { query: "halger", fuzziness: "AUTO", boost: 2 } } }, - // { match: { subjects: { query: "halger", fuzziness: "AUTO", boost: 1 } } }, - // { wildcard: { title: { value: "halger", boost: 3 } } }, - // { wildcard: { author: { value: "halger", boost: 2 } } }, - // { wildcard: { subjects: { value: "halger", boost: 1 } } } - // ], - // minimum_should_match: 1 - // } - // }, - - // size: 10, - // from: startValue, - // sort: [{ _score: { order: "desc" } }], - // track_scores: true, - - // aggs: { - // subjects: { terms: { field: "subjects.keyword", size: 1000 } }, - // language: { terms: { field: "language" } }, - // author: { terms: { field: "author.keyword", size: 1000 } }, - // year: { terms: { field: "year", size: 100 } } - // }, - - // highlight: { - // fields: { - // title: {}, - // author: {}, - // subjects: {} - // } - // } - // }; - - // console.log("mainQuery:", mainQuery); - // console.log("filters:", filters); - // console.log("body:", body); - - // // Make API call to OpenSearch and return the result - // const stations = api.post(base, body); - - // return stations; - // } - - - - public facetedSearchOPEN( + /** + * Perform faceted search with OpenSearch API using filters and suggestions + * @param {Suggestion | string} suggestion - Search term or suggestion + * @param {ActiveFilterCategories} activeFilterCategories - Active filters to apply + * @param {string} openCore - The OpenSearch core to search in + * @param {string} openHost - The OpenSearch host URL + * @param {string} start - Optional: starting page + * @returns {Observable} - Observable emitting search results + */ + public facetedSearch( suggestion: Suggestion | string, activeFilterCategories: ActiveFilterCategories, openCore: string, openHost: string, start?: string, // Starting page ): Observable { - // console.log("FACETEDSEARCH"); - - // OpenSearch endpoint const host = openHost; const path = "/" + openCore + "/_search"; const base = host + path; const lowercaseTerm = typeof suggestion === 'string' ? suggestion.toLowerCase() : suggestion.value; - // console.log("facetedsearchOPEN > suggestion entered:"); - // console.log(suggestion); - // console.log("typeof:", typeof suggestion); - - /** - * The query construction depends on whether the suggestion is a string or a Suggestion object. */ + * The query construction depends on whether the suggestion is a string or a Suggestion object. + * */ + // When suggestion is a string: const mainQuery = typeof suggestion === 'string' ? { @@ -350,7 +164,7 @@ class DatasetService { minimum_should_match: 1 } } - // When suggestion is a suggestion object + // When suggestion is a suggestion object: : { match: { [suggestion.type]: { @@ -360,28 +174,7 @@ class DatasetService { } }; - // CONTABO ==================================================== - // // Constructing Filters Based on Active Filter Categories - // const filters = Object.entries(activeFilterCategories).map(([category, values]) => ({ - // terms: { [`${category}.keyword`]: values } - // })); - // ================================================================ - - // // Constructing Filters Based on Active Filter Categories - // const filters = Object.entries(activeFilterCategories).map(([category, values]) => { - // if (category === "language" || category === "year") { - // return { terms: { [category]: values } }; - // } else { - // return { terms: { [`${category}.keyword`]: values } }; - // } - // }); - - - // const filters = Object.entries(activeFilterCategories).map(([category, values]) => - // values.map(value => ({ term: { [`${category}.keyword`]: value } })) - // ).flat(); - - + // Build filters based on the active filter categories const filters = Object.entries(activeFilterCategories).map(([category, values]) => { if (category === "language" || category === "year" || category === "doctype") { return values.map(value => ({ term: { [category]: value } })); @@ -390,22 +183,8 @@ class DatasetService { } }).flat(); - // console.log(activeFilterCategories); - console.log("mainQuery:", mainQuery); - console.log("filters:", filters); - + // Request body for the faceted search const body = { - // query: { - // bool: { - // must: query, // Contains the main query constructed earlier. - // filter: filters // Contains the filters constructed from activeFilterCategories. - // // filter: [ - // // { "terms": { "subjects.keyword": ["Lower Austria", "counting data"] } }, - // // { "term": { "language": "en" } } - // // ] // Contains the filters constructed from activeFilterCategories. - // } - // }, - query: { bool: { must: [ @@ -415,49 +194,24 @@ class DatasetService { } }, - // // THIS DOESNT WORK // Expected: 12 results, Ouput: 16 - // query: { - // bool: { - // "must": [ - // { "term": { "language": "en" } }, - // { "terms": { "subjects.keyword": ["Lower Austria", "counting data"] } } - // ], - // "should": [ - // { match: { title: { query: "halger", fuzziness: "AUTO", boost: 3 } } }, - // { match: { author: { query: "halger", fuzziness: "AUTO", boost: 2 } } }, - // { match: { subjects: { query: "halger", fuzziness: "AUTO", boost: 1 } } }, - // { wildcard: { title: { value: "halger", boost: 3 } } }, - // { wildcard: { author: { value: "halger", boost: 2 } } }, - // { wildcard: { subjects: { value: "halger", boost: 1 } } } - // ], - // minimum_should_match: 1 - // } - // }, - size: 10, from: start ? parseInt(start) : 0, - // sort: [{ _source: { server_date_published: { order: "desc" } } }], - sort: [{ server_date_published: { order: "desc" } }], + sort: [{ server_date_published: { order: "desc" } }], // Sort by publication date // sort: [{ _score: { order: "desc" } }], // Sort by _score in descending order track_scores: true, - aggs: { // Defines aggregations for facets - // terms: Aggregation type that returns the most common terms in a field. - // !For a large number of terms setting an extremely large size might not be efficient - // If you genuinely need all unique terms and expect a large number of them, consider using a composite aggregation for more efficient pagination of terms. + /** + * Defines aggregations for facets + * terms: Aggregation type that returns the most common terms in a field. + * !For a large number of terms setting an extremely large size might not be efficient + * If you genuinely need all unique terms and expect a large number of them, consider using a composite aggregation for more efficient pagination of terms. + */ + aggs: { subjects: { terms: { field: "subjects.keyword", size: 1000 } }, // In SOLR is "subject"! language: { terms: { field: "language" } }, // ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS author: { terms: { field: "author.keyword", size: 1000 } }, year: { terms: { field: "year", size: 100 } }, // ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS doctype: { terms: { field: "doctype", size: 50 } } // ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS }, - // CONTABO ================================================================================ - // aggs: { - // subjects: { terms: { field: "subjects.keyword", size: 1000 } }, // In SOLR is "subject"! - // language: { terms: { field: "language.keyword" } }, // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS - // author: { terms: { field: "author.keyword", size: 1000 } }, - // year: { terms: { field: "year.keyword", size: 100 } } // << ".keyword" HAS TO BE REMOVED. OTHERWISE BUCKETS ARE NOT OBTAINED FOR THIS - // }, - // =========================================================================================== highlight: { fields: { title: {}, @@ -468,17 +222,15 @@ class DatasetService { } }; - // console.log("body:", body); - + // API call and return observable of search results const stations = api.post(base, body); - return stations; } // /** // * This method performs a faceted search on a Solr core. Faceted search allows the user to filter search results based on various categories (facets) // */ - // public facetedSearch_SOLR( + // public facetedSearchSOLR( // suggestion: Suggestion | string, // activeFilterCategories: ActiveFilterCategories, // solrCore: string, @@ -609,8 +361,8 @@ class DatasetService { const host = VUE_API; const path = "/api/dataset/" + id; const apiUrl = host + path; - const dataset = api.get(apiUrl).pipe(map((res) => this.prepareDataset(res))); + const dataset = api.get(apiUrl).pipe(map((res) => this.prepareDataset(res))); return dataset; } @@ -619,16 +371,16 @@ class DatasetService { const host = VUE_API; const path = "/api/dataset/10.24341/tethys." + doi; const apiUrl = host + path; - const dataset = api.get(apiUrl).pipe(map((res) => this.prepareDataset(res))); + const dataset = api.get(apiUrl).pipe(map((res) => this.prepareDataset(res))); return dataset; } - // Method to prepare dataset object + // Prepare dataset object by deserializing it and adding a URL private prepareDataset(datasetObj: DbDataset): DbDataset { + const dataset = deserialize(DbDataset, JSON.stringify(datasetObj)); dataset.url = document.documentURI; - return dataset; } } diff --git a/src/views/search-view/search-view-component.ts b/src/views/search-view/search-view-component.ts index d8e666c..db7dd56 100644 --- a/src/views/search-view/search-view-component.ts +++ b/src/views/search-view/search-view-component.ts @@ -1,17 +1,18 @@ +// Import necessary modules, components, and models from Vue and the project import { Component, Vue, Prop } from "vue-facing-decorator"; import VsInput from "@/components/vs-input/vs-input.vue"; import VsResult from "@/components/vs-result/vs-result.vue"; import FacetCategory from "@/components/face-category/facet-category.vue"; import ActiveFacetCategory from "@/components/active-facet-category/active-facet-category.vue"; -// import { SolrSettings } from "@/models/solr"; +// Import models and services +// import { SolrSettings } from "@/models/solr"; import { OpenSettings } from "@/models/solr"; -// import { DatasetService } from "@/services/dataset.service"; import DatasetService from "../../services/dataset.service"; import { Suggestion, Dataset, SearchType } from "@/models/dataset"; // import { SolrResponse, FacetFields, FacetItem, FacetResults, FacetInstance } from "@/models/headers"; // import { SolrResponse, FacetFields, FacetItem, FacetResults, FacetInstance, OpenSearchResponse, HitHighlight } from "@/models/headers"; -import { FacetFields, FacetItem, FacetResults, FacetInstance, OpenSearchResponse, HitHighlight } from "@/models/headers"; +import { FacetItem, FacetResults, OpenSearchResponse } from "@/models/headers"; import { ActiveFilterCategories } from "@/models/solr"; // import { SOLR_HOST, SOLR_CORE } from "@/constants"; import { IPagination } from "@/models/pagination"; @@ -19,7 +20,7 @@ import PaginationComponent from "@/components/PaginationComponent.vue"; import { OPEN_HOST, OPEN_CORE } from "@/constants"; -// Decorate the component and define its name and components +// Define the Vue component, its name, and child components @Component({ name: "SearchViewComponent", components: { @@ -31,51 +32,51 @@ import { OPEN_HOST, OPEN_CORE } from "@/constants"; }, }) -// Define the SearchViewComponent class +// Export the default class for the component export default class SearchViewComponent extends Vue { - @Prop() - display!: string; - - @Prop() - type!: string; - - results: Array = []; - - // facets: FacetFields = new FacetFields(); - facets: FacetResults = new FacetResults(); - searchTerm: string | Suggestion = ""; - // activeFilterCategories: Object = {}; - activeFilterCategories: ActiveFilterCategories = new ActiveFilterCategories(); // = new Array(); - pagination: IPagination = { + // Define props passed from the parent component + @Prop() + display!: string; // Search display string + @Prop() + type!: string; // Search type + + // Declare variables used in the component + results: Array = []; // Array to hold search results + facets: FacetResults = new FacetResults(); // Object to hold facet results + searchTerm: string | Suggestion = ""; // The search term input + activeFilterCategories: ActiveFilterCategories = new ActiveFilterCategories(); // Active filter categories for search + pagination: IPagination = { // Pagination data for the results total: 0, perPage: 10, currentPage: 1, - // lastPage: 0, data: [], }; - loaded = false; - numFound!: number; + loaded = false; // Boolean to track whether data has been loaded + numFound!: number; // Number of results found + // private solr: SolrSettings = { // core: SOLR_CORE, //"rdr_data", // SOLR.core; // host: SOLR_HOST, //"tethys.at", // }; + // Define settings for the OpenSearch API (core and host information) private open: OpenSettings = { - core: OPEN_CORE, //"rdr_data", // SOLR.core; - host: OPEN_HOST, //"tethys.at", + core: OPEN_CORE, // + host: OPEN_HOST, // }; private error = ""; // Computed property to get search term as string get stringSearchTerm(): string { - // console.log("stringSearchTerm:", this.searchTerm); - + // If searchTerm is a string, return it directly if (typeof this.searchTerm === "string") { return this.searchTerm; + // If searchTerm is a Suggestion, return its value and type alias } else if (this.searchTerm instanceof Suggestion) { return this.searchTerm.value + " (" + this.getTypeAlias(this.searchTerm.type) + ")"; // return this.searchTerm.value + " (" + this.searchTerm.type + ")"; + // Default to empty string } else { return ""; } @@ -109,9 +110,6 @@ export default class SearchViewComponent extends Vue { return false; } } - // getKeyName(value: string) { - // return Object.entries(Suggestion).find(([key, val]) => val === value)?.[0]; - // } // Method to get enum key by enum value getEnumKeyByEnumValue(myEnum: T, enumValue: string): keyof T | null { @@ -124,7 +122,6 @@ export default class SearchViewComponent extends Vue { beforeMount(): void { // console.log("beforeMount!"); - // this.rdrAPI = new DatasetService(); // Trigger search based on provided display and type props if (this.display != "" && this.type != undefined) { const enumKey: "Title" | "Author" | "Subject" | "Doctype" | null = this.getEnumKeyByEnumValue(SearchType, this.type); @@ -150,64 +147,30 @@ export default class SearchViewComponent extends Vue { this.activeFilterCategories = new ActiveFilterCategories(); this.facets = new FacetResults(); this.searchTerm = suggestion; - // console.log("ONSEARCH > suggestion: ", suggestion); // /* Perform faceted search. The method returns an Observable, and the code subscribes to this Observable to handle the response. If the response is successful, it calls the dataHandler method // with the Solr response as a parameter. If there is an error, it calls the errorHandler method with the error message as a parameter */ - // DatasetService.facetedSearch(suggestion, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe({ + // DatasetService.facetedSearchSOLR(suggestion, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe({ // next: (res: SolrResponse) => this.dataHandler(res), // error: (error: string) => this.errorHandler(error), // }); - DatasetService.facetedSearchOPEN(suggestion, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({ - // next: (res: { datasets: Dataset[], highlights: HitHighlight[] }) => this.dataHandlerOpen(res.datasets, res.highlights), - next: (res: OpenSearchResponse) => this.dataHandlerOPEN(res), + DatasetService.facetedSearch(suggestion, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({ + next: (res: OpenSearchResponse) => this.dataHandler(res), error: (error: string) => this.errorHandler(error), }); } // Handle the search results - private dataHandlerOPEN(res: OpenSearchResponse, filterItem?: FacetItem): void { + private dataHandler(res: OpenSearchResponse, filterItem?: FacetItem): void { this.results = res.hits.hits.map(hit => hit._source); this.numFound = res.hits.total.value; - - // console.log("dataHandlerOPEN (results, numFound):"); - // console.log(this.results); - // console.log(this.numFound); - // console.log(res.hits.hits); - // console.log(res.hits.total.value); console.log(res); - // console.log("results:"); - // console.log(res); - - // for (const key in this.results) { - // if (Object.prototype.hasOwnProperty.call(this.results, key)) { - // const element = this.results[key]; - // // console.log(element.abstract[0]); - // // console.log(element.language); - // console.log(element.server_date_published); - // } - // } - this.pagination.total = res.hits.total.value; this.pagination.perPage = 10; this.pagination.data = this.results; this.pagination.lastPage = Math.ceil(this.pagination.total / this.pagination.perPage); - // if (res.aggregations) { - // const facet_fields = res.aggregations; - - // let prop: keyof typeof facet_fields; - - // for (prop in facet_fields) { - // const facetCategory = facet_fields[prop]; - // if (facetCategory.buckets) { - // const facetItems = facetCategory.buckets.map(bucket => new FacetItem(bucket.key, bucket.doc_count)); - // this.facets[prop] = facetItems.filter(el => el.count > 0); - // } - // } - // } - if (res.aggregations) { const facet_fields = res.aggregations; @@ -244,7 +207,7 @@ export default class SearchViewComponent extends Vue { } // // Method to handle search response - // private dataHandler(res: SolrResponse, filterItem?: FacetItem): void { + // private dataHandlerSOLR(res: SolrResponse, filterItem?: FacetItem): void { // // console.log("dataHandlerSOLR (docs, numFound):"); // // console.log(res.response.docs); // // console.log(res.response.numFound); @@ -315,13 +278,13 @@ export default class SearchViewComponent extends Vue { const start = page * this.pagination.perPage - this.pagination.perPage; // // Trigger new search with updated pagination parameters - // DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, start.toString()).subscribe( + // DatasetService.facetedSearchSOLR(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, start.toString()).subscribe( // (res: SolrResponse) => this.dataHandler(res), // (error: string) => this.errorHandler(error), // ); - DatasetService.facetedSearchOPEN(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, start.toString()).subscribe({ - next: (res: OpenSearchResponse) => this.dataHandlerOPEN(res), + DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, start.toString()).subscribe({ + next: (res: OpenSearchResponse) => this.dataHandler(res), error: (error: string) => this.errorHandler(error), }); } @@ -332,37 +295,32 @@ export default class SearchViewComponent extends Vue { // Reset current page this.pagination.currentPage = 1; - // console.log(facetItem.val); - // console.log(facetItem.category); - - // if (!this.activeFilterCategories.hasOwnProperty(facetItem.category)) { - + // Check if filter item already exists if (!Object.prototype.hasOwnProperty.call(this.activeFilterCategories, facetItem.category)) { this.activeFilterCategories[facetItem.category] = new Array(); - // console.log(this.activeFilterCategories); } - // if (!this.activeFilterCategories[facetItem.category].some((e) => e === facetItem.val)) { // Check if filter item is not already applied if (!this.activeFilterCategories[facetItem.category].some((e) => e === facetItem.val)) { // Add filter item to active filter categories this.activeFilterCategories[facetItem.category].push(facetItem.val); - // Trigger new search with updated filter - // DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe( + + // DatasetService.facetedSearchSOLR(this.searchTerm, this.activeFilterCategories, this.solr.core, this.solr.host, undefined).subscribe( // (res: SolrResponse) => this.dataHandler(res, facetItem), // (error: string) => this.errorHandler(error), // ); - // console.log(this.activeFilterCategories); - DatasetService.facetedSearchOPEN(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({ - next: (res: OpenSearchResponse) => this.dataHandlerOPEN(res, facetItem), + + // Trigger new search with updated filter + DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({ + next: (res: OpenSearchResponse) => this.dataHandler(res, facetItem), error: (error: string) => this.errorHandler(error), }); } } // // // Method to clear facet category filter - // onClearFacetCategory(categoryName: string): void { + // onClearFacetCategorySOLR(categoryName: string): void { // console.log("onClearFacetCategory"); // delete this.activeFilterCategories[categoryName]; @@ -416,12 +374,12 @@ export default class SearchViewComponent extends Vue { // } // Method to clear facet category filter - onClearFacetCategoryOPEN(categoryName: string): void { - console.log("onClearFacetCategory"); + onClearFacetCategory(categoryName: string): void { + // console.log("onClearFacetCategory"); delete this.activeFilterCategories[categoryName]; // Trigger new search with updated filter - DatasetService.facetedSearchOPEN(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({ + DatasetService.facetedSearch(this.searchTerm, this.activeFilterCategories, this.open.core, this.open.host, undefined).subscribe({ next: (res: OpenSearchResponse) => { this.results = res.hits.hits.map(hit => hit._source); this.numFound = res.hits.total.value; diff --git a/src/views/search-view/search-view-component.vue b/src/views/search-view/search-view-component.vue index f2eeb8f..5fe366c 100644 --- a/src/views/search-view/search-view-component.vue +++ b/src/views/search-view/search-view-component.vue @@ -105,7 +105,7 @@ From fef92c392ded43c83bee283f025caa728975fa45 Mon Sep 17 00:00:00 2001 From: frankporras Date: Thu, 12 Sep 2024 16:31:24 +0200 Subject: [PATCH 60/64] - Minimap code commented - Code cleaning --- src/app.ts | 56 +-- src/components/minimap/Minimap.ts | 57 ++- src/constants.ts | 6 - src/search_page.html | 698 ------------------------------ 4 files changed, 54 insertions(+), 763 deletions(-) delete mode 100644 src/search_page.html diff --git a/src/app.ts b/src/app.ts index bdcca89..5afe4a2 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,5 +1,4 @@ import { Component, Vue, Watch } from "vue-facing-decorator"; -// import { RouteLocation } from "vue-router"; import HomeViewComponent from "./views/home-view/home-view-component.vue"; import HelpViewComponent from "./views/help-view/help-view-component.vue"; import MapViewComponent from "./views/map-view/map-view.component.vue"; @@ -11,27 +10,10 @@ import ContactViewComponent from "./views/contact-view/contact-view-component.vu import SitelinkViewComponent from "./views/sitelink-view/sitelink-view-component.vue"; import ImprintViewComponent from "./views/imprint-view/imprint-view-component.vue"; import TermsViewComponent from "./views/terms-view/terms-view-component"; -// import { VUE_API } from "./constants"; -// import VsInput from "./components/vs-input/vs-input.vue"; -// import VsResult from "./components/vs-result/vs-result.vue"; -// import FacetCategory from "./components/face-category/facet-category.vue"; -// import ActiveFacetCategory from "./components/active-facet-category/active-facet-category.vue"; -// import { SolrSettings } from "@/models/solr"; -// import { DatasetService } from "./services/dataset.service"; -// import { Suggestion } from "./models/dataset"; -// import { SolrResponse, FacetFields, FacetItem, FacetResults, FacetInstance } from "./models/headers"; -// import { ActiveFilterCategories } from "@/models/solr"; - -// https://devsoniq.com/how-to-toggle-bulma-css-navbar-in-your-vue-js-project/ @Component({ components: { - // HelloWorld, HomeViewComponent, - // VsInput, - // VsResult, - // FacetCategory, - // ActiveFacetCategory, HelpViewComponent, MapViewComponent, SearchViewComponent, @@ -48,38 +30,40 @@ export default class App extends Vue { public active = false; public portal = "https://data.tethys.at/login"; // VUE_API + "/login"; + /** + * Computed property that returns the current year. + * @returns {number} The current year as a number. + */ get currentYear() { return new Date().getFullYear(); } + /** + * Lifecycle hook called when the component is mounted. + * Currently empty, but can be used to add setup logic when the component is mounted. + */ mounted(): void { - // const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll(".navbar-burger"), 0); - // // Check if there are any navbar burgers - // if ($navbarBurgers.length > 0) { - // // Add a click event on each of them - // $navbarBurgers.forEach((elNavBurger) => { - // elNavBurger.addEventListener("click", () => { - // // Get the target from the "data-target" attribute - // const targetNavbar = elNavBurger.dataset.target; - // const $target = document.getElementById(targetNavbar); - // // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu" - // elNavBurger.classList.toggle("is-active"); - // $target?.classList.toggle("is-active"); - // }); - // }); - // } + } + /** + * Toggles the visibility of the mobile menu. + * @param {MouseEvent} event - The mouse event triggered by the user's interaction. + */ public showMobilemenu(event: MouseEvent): void { - // Don't follow the link + // Prevent the default behavior of the event (e.g., following a link) event.preventDefault(); + // Toggle the active state of the mobile menu this.active = !this.active; } + /** + * Watcher that triggers when the route changes. + * It deactivates the mobile menu by setting `active` to false. + */ @Watch("$route") protected oRouteChangedChanged(): void { - //(to: RouteLocation, from: RouteLocation): void { - // console.log("setting " + from.path + " to " + to.path); + // Close the mobile menu when the route changes this.active = false; } } diff --git a/src/components/minimap/Minimap.ts b/src/components/minimap/Minimap.ts index 35092db..5ec7c65 100644 --- a/src/components/minimap/Minimap.ts +++ b/src/components/minimap/Minimap.ts @@ -11,36 +11,46 @@ export default class Minimap extends Vue { // private originalCenter: L.LatLngExpression = [47.71, 13.55]; // Original center // private originalZoom: number = 6; // Original zoom level + /** + * Lifecycle hook called when the component is mounted. + * Initializes the Leaflet map, sets up base layers, and adds either a circle or rectangle + * based on the `bounds` prop passed to the component. + */ mounted() { + // Initialize the map with specific center and zoom const map = L.map('map', { - center: [47.71, 13.55], - zoomControl: true, - zoom: 6, - minZoom: 5, + center: [47.71, 13.55], // Initial center coordinates + zoomControl: true, // Enable zoom controls + zoom: 6, // Initial zoom level + minZoom: 5, // Minimum zoom level allowed maxBounds: [ - [44.0, 9.0], // Southwest corner of the bounds - [51.0, 18.0] // Northeast corner of the bounds + [44.0, 9.0], // Southwest corner of the bounding box + [51.0, 18.0] // Northeast corner of the bounding box ], - maxBoundsViscosity: 1.0 // Ensure the map cannot be dragged outside the bounds + maxBoundsViscosity: 1.0 // Prevent map from being dragged outside the defined bounds }); // Remove Leaflet logo and text map.attributionControl.setPrefix(false); + // Add basemap.at tile layer to the map const basemapAtLayer = L.tileLayer('https://maps{s}.wien.gv.at/basemap/geolandbasemap/normal/google3857/{z}/{y}/{x}.png', { attribution: 'basemap.at', noWrap: true, subdomains: ['', '1', '2', '3', '4'] }).addTo(map); + // Add Esri imagery tile layer const esriImageryLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri' }); + // Add Esri topo map tile layer const esriTopoLayer = L.tileLayer('https://server.arcgisonline.com/arcgis/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri' }); + // Define available base maps for the user to toggle between const baseMaps = { // "OpenStreetMap": openStreetMapLayer, "basemap.at": basemapAtLayer, @@ -48,6 +58,7 @@ export default class Minimap extends Vue { "ESRI Topo": esriTopoLayer }; + // Define available base maps for the user to toggle between L.control.layers(baseMaps).addTo(map); const [southWest, northEast] = this.bounds; @@ -55,45 +66,45 @@ export default class Minimap extends Vue { if (southWest[0] === northEast[0] || southWest[1] === northEast[1]) { // If y_min and y_max (and x_min and x_max) are equal, generate a circle const center = [southWest[0], southWest[1]] as [number, number]; - // Using CircleMarker to maintain constant size regardless of zoom level + // Add a CircleMarker to the map at the center of the bounds. This kind of marker is used to maintain constant size regardless of zoom level const circleMarker = L.circleMarker(center, { color: '#30D5C8', // Outline color fillColor: '#336699', // Fill color fillOpacity: 1, // Opacity of the fill opacity: 0.5, // Outline opacity - weight: 10, // Outline weight + weight: 10, // Outline weight (thickness) radius: 10 // Radius in pixels }).addTo(map); // Manually create a small bounding box around the marker's center to fit bounds - const buffer = 0.01; // Adjust this value to control the area around the marker + const buffer = 0.01; // Buffer size around the marker. Adjust this value to control the area around the marker const markerBounds = L.latLngBounds( - [center[0] - buffer, center[1] - buffer], // Southwest corner - [center[0] + buffer, center[1] + buffer] // Northeast corner + [center[0] - buffer, center[1] - buffer], // Southwest corner of the bounding box + [center[0] + buffer, center[1] + buffer] // Northeast corner of the bounding box ); - - // Add a click event to the CircleMarker + // Add a click event handler to the CircleMarker circleMarker.on('click', () => { - map.fitBounds(markerBounds, { padding: [10, 10] }); + map.fitBounds(markerBounds, { padding: [10, 10] }); // Adjust map to fit within marker bounds }); + // Automatically adjust the map's view to fit the marker's bounds map.fitBounds(markerBounds, { padding: [10, 10] }); } else { - // Otherwise, generate a rectangle + // If bounds are not equal, draw a rectangle const rectangle = L.rectangle(this.bounds, { - color: '#30D5C8', - weight: 2, - opacity: 1 - }).addTo(map); //336699 + color: '#30D5C8', // Rectangle outline color //Alternative color: 336699 + weight: 2, // Outline thickness + opacity: 1 // Opacity of the rectangle outline + }).addTo(map); - // Add a click event to the Rectangle + // Add a click event handler to the Rectangle rectangle.on('click', () => { - map.fitBounds(this.bounds, { padding: [18, 18] }); + map.fitBounds(this.bounds, { padding: [18, 18] }); // Adjust map to fit within rectangle bounds }); - // Fit the map's view to the rectangle's bounds with padding + // Automatically adjust the map's view to fit the rectangle's bounds with padding map.fitBounds(this.bounds, { padding: [18, 18] }); } } diff --git a/src/constants.ts b/src/constants.ts index acd7381..f689273 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,19 +1,13 @@ -// declare const POINT_URL: string; -// declare const EDGE_URL: string; declare const APP_URL: string; declare const VUE_API: string; declare const SOLR_HOST: string; declare const SOLR_CORE: string; -// const _EDGE_URL = EDGE_URL; -// const _POINT_URL = POINT_URL; const _APP_URL = APP_URL; const _VUE_API = VUE_API; const _SOLR_HOST = SOLR_HOST; const _SOLR_CORE = SOLR_CORE; -// export { _EDGE_URL as EDGE_URL }; -// export { _POINT_URL as POINT_URL }; export { _APP_URL as APP_URL }; export { _VUE_API as VUE_API }; export { _SOLR_HOST as SOLR_HOST }; diff --git a/src/search_page.html b/src/search_page.html deleted file mode 100644 index 0941616..0000000 --- a/src/search_page.html +++ /dev/null @@ -1,698 +0,0 @@ -
- -
- -
-
-
-
-
- It looks like you're not logged in right now. you will need to - login to Pro or become a - Coil Member - to access the results. -
- -
-
-
-
-
- -
- - - - - - -
\ No newline at end of file From 8e3f4fa88e66f5dc04e1ca26b200e759e16cecbf Mon Sep 17 00:00:00 2001 From: frankporras Date: Mon, 16 Sep 2024 12:57:26 +0200 Subject: [PATCH 61/64] Code commenting --- .../dataset-detail.component.ts | 148 +++++++++++------ .../dataset-detail.component.vue | 151 ++++++------------ .../search-view/search-view-component.ts | 14 +- .../search-view/search-view-component.vue | 88 ++-------- 4 files changed, 161 insertions(+), 240 deletions(-) diff --git a/src/views/dataset-detail.component/dataset-detail.component.ts b/src/views/dataset-detail.component/dataset-detail.component.ts index 5185e93..c314e1f 100644 --- a/src/views/dataset-detail.component/dataset-detail.component.ts +++ b/src/views/dataset-detail.component/dataset-detail.component.ts @@ -14,56 +14,64 @@ import { VUE_API } from "@/constants"; name: "DatasetDetailComponent", components: { VsInput, - // DataMetricsBadge, + // DataMetricsBadge, // Commented out but prepared for future use }, }) export default class DatasetDetailComponent extends Vue { @Prop() - datasetId!: string; + datasetId!: string; // datasetId is passed as a prop and is required. - // @Prop() - // identifier!: string; + searchTerm: string | Suggestion = ""; // Search term used in the search functionality. + private subscriptions: Array = []; // Subscriptions to RxJS observables to prevent memory leaks. + public dataset = {} as DbDataset; // Holds dataset details. + private error: string = ""; // Stores error messages, if any. + public loaded = false; // Indicates whether the dataset is fully loaded. + public openAccessLicences: Array = ["CC-BY-4.0", "CC-BY-SA-4.0"]; // Available open-access licenses. + public portal = VUE_API + "/api/file/download/"; // Portal URL for file downloads. - searchTerm: string | Suggestion = ""; - - private subscriptions: Array = []; - public dataset = {} as DbDataset; - private error: string = ""; - public loaded = false; - public openAccessLicences: Array = ["CC-BY-4.0", "CC-BY-SA-4.0"]; - public portal = VUE_API + "/api/file/download/"; - - public post = { - views: 25, - downloads: 1262, - citations: 2424, - }; + // If needed for stats + // public post = { + // views: 25, // Number of views for the dataset + // downloads: 1262, // Number of downloads + // citations: 2424, // Number of citations + // }; + /** + * Lifecycle hook: Called when the component is created. + * Extends dayjs with advanced format plugin and determines whether to + * fetch dataset by ID or by DOI. + */ created(): void { - dayjs.extend(advancedFormat); + dayjs.extend(advancedFormat); // Adds advanced date formatting options to dayjs. if (!this.datasetId.includes(".")) { - // get datset by publish_id + // Fetch dataset by publish_id (numeric ID) this.getDataset(Number(this.datasetId)); } else { - // get datset by doi_value + // Fetch dataset by DOI (alphanumeric ID) this.getDatasetByIdentifier(this.datasetId); } } + /** + * Lifecycle hook: Called before the component is unmounted. + * Unsubscribes from all subscriptions to prevent memory leaks. + */ beforeUnmount(): void { - //unsunscribe to ensure no memory leaks - // this.subscription.unsubscribe(); for (const subs of this.subscriptions) { subs.unsubscribe(); } } - onSearch(suggestion: Suggestion | string): void { - console.log("onSearch (dataset-detail.component)"); - + /** + * Handles search functionality based on user input or suggestion selection. + * Opens a new window or navigates internally based on the host's domain. + * @param suggestion - The suggestion or search term entered by the user. + */ + onSearch(suggestion: Suggestion | string): void { const host = window.location.host; const parts = host.split("."); if (parts[0] === "doi") { + // If in DOI subdomain, open external search in a new window let term; if (typeof suggestion === "string") { term = suggestion; @@ -74,6 +82,7 @@ export default class DatasetDetailComponent extends Vue { window.open("https://tethys.at/search/" + term + "/" + type, "_self"); } } else { + // Otherwise, route internally to search page let term; if (typeof suggestion === "string") { term = suggestion; @@ -83,87 +92,125 @@ export default class DatasetDetailComponent extends Vue { this.$router.push({ name: "Search", params: { display: term, type: suggestion.type } }); } } - - // this.searchTerm = suggestion; - // this.$router.push({ name: "Search", params: { display: term, suggestion instanceof Suggestion ? ty} }); } + /** + * Fetches the dataset details by ID from the service and updates the component state. + * @param id - The dataset's numeric ID. + */ private getDataset(id: number): void { const newSub = DatasetService.getDataset(id).subscribe({ next: (res: DbDataset) => { - this.dataset = res; - this.loaded = true; + this.dataset = res; // Store dataset in component state. + this.loaded = true; // Mark as loaded. }, - // error: (error: string) => this.errorHandler(error), error: (error: string) => { - this.error = error; + this.error = error; // Capture any errors during fetch. }, }); - this.subscriptions.push(newSub); + this.subscriptions.push(newSub); // Add subscription to array to manage unsubscribing later. } + /** + * Fetches the dataset details by DOI from the service and updates the component state. + * @param id - The dataset's DOI (Digital Object Identifier). + */ private getDatasetByIdentifier(id: string): void { const newSub = DatasetService.getDatasetByDoi(id).subscribe({ next: (res: DbDataset) => { - this.dataset = res; - this.loaded = true; + this.dataset = res; // Store dataset in component state. + this.loaded = true; // Mark as loaded. }, error: (error: string) => this.errorHandler(error), }); - this.subscriptions.push(newSub); + this.subscriptions.push(newSub); // Add subscription to array. } + /** + * Handles errors and updates the error message in the component. + * @param err - Error message. + */ private errorHandler(err: string): void { - this.error = err; - // this.loading = false; + this.error = err; // Update error message. } + /** + * Navigates back by one page in the router history, similar to browser back. + */ public goBack(): void { - // go back by one record, the same as history.back() - // router.go(-1); - this.$router.go(-1); + this.$router.go(-1); // Go back one step in the browser history. } + /** + * Extracts the file extension from a given filename. + * @param filename - The name of the file. + * @returns The file extension as a string. + */ public getExtension(filename: string): string { return filename.substring(filename.lastIndexOf(".") + 1, filename.length) || filename; } + /** + * Formats the file size into a human-readable string with appropriate units. + * @param file_size - The size of the file in bytes. + * @returns The formatted file size string. + */ public formatSize(file_size: number): string { let size = file_size; - const unit = ["Byte", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]; + const unit = ["Byte", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"]; // Units for size. let i; for (i = 0; size >= 1024 && i < unit.length - 1; i++) { - size = size / 1024; + size = size / 1024; // Convert size to appropriate unit. } - // return Math.round((size * precision) / precision) + " " + unit[i]; return Math.round((size + Number.EPSILON) * 100) / 100 + " " + unit[i]; } + /** + * Formats a given date into a human-readable string with the full day, month, and year. + * @param date - The date string to format. + * @returns The formatted date string. + */ public getPublishedDate(date: string): string { - // return moment(date).format("ddd, MMMM Do, YYYY h:mm a"); return dayjs(date).format("ddd, MMMM Do, YYYY h:mm a"); } + /** + * Formats a given date into a simpler "DD.MM.YYYY HH:mm" format. + * @param date - The date string to format. + * @returns The formatted date string. + */ public getHumanDate(date: string): string { - // return moment(date).format("DD.MM.YYYY HH:mm"); return dayjs(date).format("DD.MM.YYYY HH:mm"); } + /** + * Extracts the year from a given date string. + * @param date - The date string to extract the year from. + * @returns The year as a string. + */ public getYear(date: string): string { return dayjs(date).format("YYYY"); - // return moment(date).format("YYYY"); } + /** + * Returns the human-readable language string based on the language code. + * @param language - The language code (e.g., "de" for German). + * @returns The language name as a string. + */ public getLanguage(language: string): string { if (language === "de") { - return "Deutsch" + return "Deutsch"; } else { - return "English" + return "English"; } } + /** + * Generates a citation string for the dataset based on its authors and publication details. + * @returns The citation as a string. + */ public getCitation(): string { let citation = this.dataset.authors .map((u) => { @@ -172,7 +219,6 @@ export default class DatasetDetailComponent extends Vue { name += ", " + u.first_name?.substring(0, 1).toUpperCase() + "."; } return name; - // u.last_name + ", " + u.first_name?.substring(0, 1).toUpperCase() + "." }) .join(", "); citation += " (" + dayjs(this.dataset.server_date_published).format("YYYY") + "): "; diff --git a/src/views/dataset-detail.component/dataset-detail.component.vue b/src/views/dataset-detail.component/dataset-detail.component.vue index 66068d4..4c64dea 100644 --- a/src/views/dataset-detail.component/dataset-detail.component.vue +++ b/src/views/dataset-detail.component/dataset-detail.component.vue @@ -1,81 +1,54 @@ @@ -395,26 +353,32 @@ export default DatasetDetailComponent; font-size: 0.8rem; padding: 0; } + .card { border-radius: 0; - /* rempve box-shadow */ + /* Remove box-shadow for a flat design */ box-shadow: none; } + .link-label { color: #33cccc; } + .label { /* color: #363636; */ display: block; font-size: 0.8rem; font-weight: 700; } + .label.uppercase { text-transform: uppercase; } + .normal.label { font-weight: 400; } + .column p span i { color: #336699; } @@ -425,27 +389,4 @@ export default DatasetDetailComponent; font-weight: 700; background-color: #ccddf1; } -// input { -// height: 2em; -// font-size: 1em; -// padding-left: 0.4em; -// } -// button { -// margin-top: 20px; -// font-family: Arial; -// background-color: #eee; -// border: none; -// padding: 5px 10px; -// border-radius: 4px; -// cursor: pointer; -// cursor: hand; -// } -// button:hover { -// background-color: #cfd8dc; -// } -// button:disabled { -// background-color: #eee; -// color: #ccc; -// cursor: auto; -// } diff --git a/src/views/search-view/search-view-component.ts b/src/views/search-view/search-view-component.ts index d8e666c..93ad30e 100644 --- a/src/views/search-view/search-view-component.ts +++ b/src/views/search-view/search-view-component.ts @@ -61,16 +61,14 @@ export default class SearchViewComponent extends Vue { // }; private open: OpenSettings = { - core: OPEN_CORE, //"rdr_data", // SOLR.core; - host: OPEN_HOST, //"tethys.at", + core: OPEN_CORE, + host: OPEN_HOST, //"https://catalog.geosphere.at", }; private error = ""; // Computed property to get search term as string - get stringSearchTerm(): string { - // console.log("stringSearchTerm:", this.searchTerm); - + get stringSearchTerm(): string { if (typeof this.searchTerm === "string") { return this.searchTerm; } else if (this.searchTerm instanceof Suggestion) { @@ -109,9 +107,6 @@ export default class SearchViewComponent extends Vue { return false; } } - // getKeyName(value: string) { - // return Object.entries(Suggestion).find(([key, val]) => val === value)?.[0]; - // } // Method to get enum key by enum value getEnumKeyByEnumValue(myEnum: T, enumValue: string): keyof T | null { @@ -122,9 +117,6 @@ export default class SearchViewComponent extends Vue { // Lifecycle hook: executed before the component is mounted beforeMount(): void { - // console.log("beforeMount!"); - - // this.rdrAPI = new DatasetService(); // Trigger search based on provided display and type props if (this.display != "" && this.type != undefined) { const enumKey: "Title" | "Author" | "Subject" | "Doctype" | null = this.getEnumKeyByEnumValue(SearchType, this.type); diff --git a/src/views/search-view/search-view-component.vue b/src/views/search-view/search-view-component.vue index f2eeb8f..3c22d1e 100644 --- a/src/views/search-view/search-view-component.vue +++ b/src/views/search-view/search-view-component.vue @@ -1,95 +1,37 @@