Env swap #21
|
@ -188,6 +188,11 @@ let withReconn (conn : IConnection) =
|
||||||
(conn :?> Connection).Reconnect()
|
(conn :?> Connection).Reconnect()
|
||||||
| false -> ()))
|
| false -> ()))
|
||||||
|
|
||||||
|
/// Sanitize user input, and create a "contains" pattern for use with RethinkDB queries
|
||||||
|
let regexContains (it : string) =
|
||||||
|
System.Text.RegularExpressions.Regex.Escape it
|
||||||
|
|> sprintf "(?i).*%s.*"
|
||||||
|
|
||||||
open JobsJobsJobs.Domain.SharedTypes
|
open JobsJobsJobs.Domain.SharedTypes
|
||||||
open RethinkDb.Driver.Ast
|
open RethinkDb.Driver.Ast
|
||||||
|
|
||||||
|
@ -251,14 +256,14 @@ module Profile =
|
||||||
match srch.skill with
|
match srch.skill with
|
||||||
| Some skl ->
|
| Some skl ->
|
||||||
yield (fun q -> q.Filter(ReqlFunction1(fun it ->
|
yield (fun q -> q.Filter(ReqlFunction1(fun it ->
|
||||||
upcast it.G("skills.description").Downcase().Match(skl.ToLowerInvariant ()))) :> ReqlExpr)
|
upcast it.G("skills").Contains(ReqlFunction1(fun s ->
|
||||||
|
upcast s.G("description").Match(regexContains skl))))) :> ReqlExpr)
|
||||||
| None -> ()
|
| None -> ()
|
||||||
match srch.bioExperience with
|
match srch.bioExperience with
|
||||||
| Some text ->
|
| Some text ->
|
||||||
let txt = text.ToLowerInvariant ()
|
let txt = regexContains text
|
||||||
yield (fun q -> q.Filter(ReqlFunction1(fun it ->
|
yield (fun q -> q.Filter(ReqlFunction1(fun it ->
|
||||||
upcast it.G("biography" ).Downcase().Match(txt)
|
upcast it.G("biography").Match(txt).Or(it.G("experience").Match(txt)))) :> ReqlExpr)
|
||||||
.Or(it.G("experience").Downcase().Match(txt)))) :> ReqlExpr)
|
|
||||||
| None -> ()
|
| None -> ()
|
||||||
}
|
}
|
||||||
|> Seq.toList
|
|> Seq.toList
|
||||||
|
@ -290,8 +295,7 @@ module Profile =
|
||||||
match srch.region with
|
match srch.region with
|
||||||
| Some reg ->
|
| Some reg ->
|
||||||
yield (fun q ->
|
yield (fun q ->
|
||||||
q.Filter(ReqlFunction1(fun it ->
|
q.Filter(ReqlFunction1(fun it -> upcast it.G("region").Match(regexContains reg))) :> ReqlExpr)
|
||||||
upcast it.G("region").Downcase().Match(reg.ToLowerInvariant ()))) :> ReqlExpr)
|
|
||||||
| None -> ()
|
| None -> ()
|
||||||
match srch.remoteWork with
|
match srch.remoteWork with
|
||||||
| "" -> ()
|
| "" -> ()
|
||||||
|
@ -299,7 +303,8 @@ module Profile =
|
||||||
match srch.skill with
|
match srch.skill with
|
||||||
| Some skl ->
|
| Some skl ->
|
||||||
yield (fun q -> q.Filter(ReqlFunction1(fun it ->
|
yield (fun q -> q.Filter(ReqlFunction1(fun it ->
|
||||||
upcast it.G("skills.description").Downcase().Match(skl.ToLowerInvariant ()))) :> ReqlExpr)
|
upcast it.G("skills").Contains(ReqlFunction1(fun s ->
|
||||||
|
upcast s.G("description").Match(regexContains skl))))) :> ReqlExpr)
|
||||||
| None -> ()
|
| None -> ()
|
||||||
}
|
}
|
||||||
|> Seq.toList
|
|> Seq.toList
|
||||||
|
@ -315,7 +320,7 @@ module Profile =
|
||||||
.HashMap("skills",
|
.HashMap("skills",
|
||||||
it.G("skills").Map(ReqlFunction1(fun skill ->
|
it.G("skills").Map(ReqlFunction1(fun skill ->
|
||||||
upcast r.Branch(skill.G("notes").Default_("").Eq(""), skill.G("description"),
|
upcast r.Branch(skill.G("notes").Default_("").Eq(""), skill.G("description"),
|
||||||
sprintf "%O (%O)" (skill.G("description")) (skill.G("notes"))))))
|
skill.G("description").Add(" (").Add(skill.G("notes")).Add(")")))))
|
||||||
.With("continent", it.G("name"))))
|
.With("continent", it.G("name"))))
|
||||||
.Pluck("continent", "region", "skills", "remoteWork")
|
.Pluck("continent", "region", "skills", "remoteWork")
|
||||||
.RunResultAsync<PublicSearchResult list> conn)
|
.RunResultAsync<PublicSearchResult list> conn)
|
||||||
|
|
|
@ -146,7 +146,7 @@ export default {
|
||||||
publicSearch: async (query : PublicSearch) : Promise<PublicSearchResult[] | string | undefined> => {
|
publicSearch: async (query : PublicSearch) : Promise<PublicSearchResult[] | string | undefined> => {
|
||||||
const params = new URLSearchParams()
|
const params = new URLSearchParams()
|
||||||
if (query.continentId) params.append('continentId', query.continentId)
|
if (query.continentId) params.append('continentId', query.continentId)
|
||||||
if (query.region) params.append('bioExperience', query.region)
|
if (query.region) params.append('region', query.region)
|
||||||
if (query.skill) params.append('skill', query.skill)
|
if (query.skill) params.append('skill', query.skill)
|
||||||
params.append('remoteWork', query.remoteWork)
|
params.append('remoteWork', query.remoteWork)
|
||||||
return apiResult<PublicSearchResult[]>(
|
return apiResult<PublicSearchResult[]>(
|
||||||
|
|
|
@ -2,17 +2,19 @@
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h6 class="card-title">
|
<h6 class="card-title">
|
||||||
<a href="#" :class="{ 'cp-c': isCollapsed, 'cp-o': !isCollapsed }" @click.prevent="toggle">{{headerText}}</a>
|
<a href="#" :class="{ 'cp-c': collapsed, 'cp-o': !collapsed }" @click.prevent="toggle">{{headerText}}</a>
|
||||||
</h6>
|
</h6>
|
||||||
<slot v-if="!isCollapsed"></slot>
|
<slot v-if="!collapsed"></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, ref } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'CollapsePanel',
|
name: 'CollapsePanel',
|
||||||
|
emits: ['toggle'],
|
||||||
props: {
|
props: {
|
||||||
headerText: {
|
headerText: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -23,13 +25,9 @@ export default defineComponent({
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup (props) {
|
setup (props, { emit }) {
|
||||||
/** Whether the panel is collapsed or not */
|
|
||||||
const isCollapsed = ref(props.collapsed)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isCollapsed,
|
toggle: () => emit('toggle', !props.collapsed)
|
||||||
toggle: () => { isCollapsed.value = !isCollapsed.value }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<article>
|
<article>
|
||||||
<page-title title="Search Profiles" />
|
<page-title title="Search Profiles" />
|
||||||
<h3>Search Profiles</h3>
|
<h3 class="pb-3">Search Profiles</h3>
|
||||||
|
|
||||||
<error-list :errors="errors">
|
|
||||||
<p v-if="searching">Searching profiles...</p>
|
|
||||||
<template v-else>
|
|
||||||
<p v-if="!searched">
|
<p v-if="!searched">
|
||||||
Enter one or more criteria to filter results, or just click “Search” to list all profiles.
|
Enter one or more criteria to filter results, or just click “Search” to list all profiles.
|
||||||
</p>
|
</p>
|
||||||
<collapse-panel headerText="Search Criteria" :collapsed="searched && results.length > 0">
|
<collapse-panel headerText="Search Criteria" :collapsed="isCollapsed" @toggle="toggleCollapse">
|
||||||
<profile-search-form v-model="criteria" @search="doSearch" />
|
<profile-search-form v-model="criteria" @search="doSearch" />
|
||||||
</collapse-panel>
|
</collapse-panel>
|
||||||
<br>
|
<error-list :errors="errors">
|
||||||
<table v-if="results.length > 0" class="table table-sm table-hover">
|
<p v-if="searching" class="pt-3">Searching profiles...</p>
|
||||||
|
<template v-else>
|
||||||
|
<table v-if="results.length > 0" class="table table-sm table-hover pt-3">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Profile</th>
|
<th scope="col">Profile</th>
|
||||||
|
@ -35,7 +34,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p v-else-if="searched">No results found for the specified criteria</p>
|
<p v-else-if="searched" class="pt-3">No results found for the specified criteria</p>
|
||||||
</template>
|
</template>
|
||||||
</error-list>
|
</error-list>
|
||||||
</article>
|
</article>
|
||||||
|
@ -90,6 +89,9 @@ export default defineComponent({
|
||||||
/** The current search results */
|
/** The current search results */
|
||||||
const results : Ref<ProfileSearchResult[]> = ref([])
|
const results : Ref<ProfileSearchResult[]> = ref([])
|
||||||
|
|
||||||
|
/** Whether the search criteria should be collapsed */
|
||||||
|
const isCollapsed = ref(searched.value && results.value.length > 0)
|
||||||
|
|
||||||
/** Set up the page to match its requested state */
|
/** Set up the page to match its requested state */
|
||||||
const setUpPage = async () => {
|
const setUpPage = async () => {
|
||||||
if (queryValue(route, 'searched') === 'true') {
|
if (queryValue(route, 'searched') === 'true') {
|
||||||
|
@ -114,6 +116,7 @@ export default defineComponent({
|
||||||
} finally {
|
} finally {
|
||||||
searching.value = false
|
searching.value = false
|
||||||
}
|
}
|
||||||
|
isCollapsed.value = searched.value && results.value.length > 0
|
||||||
} else {
|
} else {
|
||||||
searched.value = false
|
searched.value = false
|
||||||
criteria.value = emptyCriteria
|
criteria.value = emptyCriteria
|
||||||
|
@ -127,6 +130,8 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
errors,
|
errors,
|
||||||
criteria,
|
criteria,
|
||||||
|
isCollapsed,
|
||||||
|
toggleCollapse: (it : boolean) => { isCollapsed.value = it },
|
||||||
doSearch: () => router.push({ query: { searched: 'true', ...criteria.value } }),
|
doSearch: () => router.push({ query: { searched: 'true', ...criteria.value } }),
|
||||||
searching,
|
searching,
|
||||||
searched,
|
searched,
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<article>
|
<article>
|
||||||
<page-title title="People Seeking Work" />
|
<page-title title="People Seeking Work" />
|
||||||
<h3>People Seeking Work</h3>
|
<h3 class="pb-3">People Seeking Work</h3>
|
||||||
|
|
||||||
<error-list :errors="errors">
|
|
||||||
<p v-if="searching">Searching profiles...</p>
|
|
||||||
<template v-else>
|
|
||||||
<p v-if="!searched">
|
<p v-if="!searched">
|
||||||
Enter one or more criteria to filter results, or just click “Search” to list all profiles.
|
Enter one or more criteria to filter results, or just click “Search” to list all profiles.
|
||||||
</p>
|
</p>
|
||||||
<collapse-panel headerText="Search Criteria" :collapsed="searched && results.length > 0">
|
<collapse-panel headerText="Search Criteria" :collapsed="isCollapsed" @toggle="toggleCollapse">
|
||||||
<profile-public-search-form v-model="criteria" @search="doSearch" />
|
<profile-public-search-form v-model="criteria" @search="doSearch" />
|
||||||
</collapse-panel>
|
</collapse-panel>
|
||||||
<br>
|
<error-list :errors="errors">
|
||||||
|
<p v-if="searching">Searching profiles...</p>
|
||||||
|
<template v-else>
|
||||||
<template v-if="results.length > 0">
|
<template v-if="results.length > 0">
|
||||||
<p>
|
<p class="pb-3 pt-3">
|
||||||
These profiles match your search criteria. To learn more about these people, join the merry band of human
|
These profiles match your search criteria. To learn more about these people, join the merry band of human
|
||||||
resources in the <a href="https://noagendashow.net" target="_blank">No Agenda</a> tribe!
|
resources in the <a href="https://noagendashow.net" target="_blank">No Agenda</a> tribe!
|
||||||
</p>
|
</p>
|
||||||
|
@ -39,9 +38,7 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<p v-else-if="searched" class="pt-3">No results found for the specified criteria</p>
|
||||||
<p v-if="searched">No results found for the specified criteria</p>
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
</error-list>
|
</error-list>
|
||||||
</article>
|
</article>
|
||||||
|
@ -91,6 +88,9 @@ export default defineComponent({
|
||||||
/** The search results */
|
/** The search results */
|
||||||
const results : Ref<PublicSearchResult[]> = ref([])
|
const results : Ref<PublicSearchResult[]> = ref([])
|
||||||
|
|
||||||
|
/** Whether the search results are collapsed */
|
||||||
|
const isCollapsed = ref(searched.value && results.value.length > 0)
|
||||||
|
|
||||||
/** Set up the page to match its requested state */
|
/** Set up the page to match its requested state */
|
||||||
const setUpPage = async () => {
|
const setUpPage = async () => {
|
||||||
if (queryValue(route, 'searched') === 'true') {
|
if (queryValue(route, 'searched') === 'true') {
|
||||||
|
@ -115,6 +115,7 @@ export default defineComponent({
|
||||||
} finally {
|
} finally {
|
||||||
searching.value = false
|
searching.value = false
|
||||||
}
|
}
|
||||||
|
isCollapsed.value = searched.value && results.value.length > 0
|
||||||
} else {
|
} else {
|
||||||
searched.value = false
|
searched.value = false
|
||||||
criteria.value = emptyCriteria
|
criteria.value = emptyCriteria
|
||||||
|
@ -128,6 +129,8 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
errors,
|
errors,
|
||||||
criteria,
|
criteria,
|
||||||
|
isCollapsed,
|
||||||
|
toggleCollapse: (it : boolean) => { isCollapsed.value = it },
|
||||||
doSearch: () => router.push({ query: { searched: 'true', ...criteria.value } }),
|
doSearch: () => router.push({ query: { searched: 'true', ...criteria.value } }),
|
||||||
searching,
|
searching,
|
||||||
searched,
|
searched,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user