Query for users to populate the users page
This commit is contained in:
parent
1f9f1ae166
commit
e59794f5e0
4 changed files with 120 additions and 43 deletions
22
api/user.go
22
api/user.go
|
|
@ -16,6 +16,7 @@ type contentURLAPI struct {
|
|||
ReviewTask string `json:"review_task"`
|
||||
Signal string `json:"signal"`
|
||||
Upload string `json:"upload"`
|
||||
Users string `json:"users"`
|
||||
}
|
||||
type contentURLs struct {
|
||||
API contentURLAPI `json:"api"`
|
||||
|
|
@ -48,6 +49,7 @@ func getUserSelf(ctx context.Context, r *http.Request, user platform.User, query
|
|||
ReviewTask: config.MakeURLNidus("/api/review-task"),
|
||||
Signal: config.MakeURLNidus("/api/signal"),
|
||||
Upload: config.MakeURLNidus("/api/upload"),
|
||||
Users: config.MakeURLNidus("/api/user"),
|
||||
},
|
||||
Tegola: urls.Tegola,
|
||||
Tile: config.MakeURLNidus("/api/tile/{z}/{y}/{x}"),
|
||||
|
|
@ -56,20 +58,30 @@ func getUserSelf(ctx context.Context, r *http.Request, user platform.User, query
|
|||
}
|
||||
|
||||
type responseListUser struct {
|
||||
Users []platform.User `json:"users"`
|
||||
Users []*platform.User `json:"users"`
|
||||
}
|
||||
|
||||
func listUser(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*responseListUser, *nhttp.ErrorWithStatus) {
|
||||
users, err := platform.UsersByOrg(ctx, user.Organization)
|
||||
if err != nil {
|
||||
return nil, nhttp.NewError("list users: %w", err)
|
||||
}
|
||||
results := make([]*platform.User, len(users))
|
||||
i := 0
|
||||
for _, v := range users {
|
||||
results[i] = v
|
||||
i++
|
||||
}
|
||||
return &responseListUser{
|
||||
Users: []platform.User{},
|
||||
Users: results,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type responseListUserSuggestion struct {
|
||||
Users []platform.User `json:"users"`
|
||||
Users []*platform.User `json:"users"`
|
||||
}
|
||||
|
||||
func listUserSuggestion(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*responseListUser, *nhttp.ErrorWithStatus) {
|
||||
func listUserSuggestion(ctx context.Context, r *http.Request, user platform.User, query queryParams) (*responseListUserSuggestion, *nhttp.ErrorWithStatus) {
|
||||
if query.Query == nil {
|
||||
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "you need to include a query")
|
||||
}
|
||||
|
|
@ -77,7 +89,7 @@ func listUserSuggestion(ctx context.Context, r *http.Request, user platform.User
|
|||
if err != nil {
|
||||
return nil, nhttp.NewError("query suggestions: %w", err)
|
||||
}
|
||||
return &responseListUser{
|
||||
return &responseListUserSuggestion{
|
||||
Users: users,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ func UsersByOrg(ctx context.Context, org Organization) (map[int32]*User, error)
|
|||
}
|
||||
return results, nil
|
||||
}
|
||||
func UserSuggestion(ctx context.Context, user User, query string) ([]User, error) {
|
||||
func UserSuggestion(ctx context.Context, user User, query string) ([]*User, error) {
|
||||
query_arg := "%" + query + "%"
|
||||
if user.HasRoot() {
|
||||
return userSuggestionRoot(ctx, user, query_arg)
|
||||
|
|
@ -122,7 +122,7 @@ func UserSuggestion(ctx context.Context, user User, query string) ([]User, error
|
|||
return userSuggestionNonRoot(ctx, user, query_arg)
|
||||
}
|
||||
}
|
||||
func userSuggestionNonRoot(ctx context.Context, user User, query_arg string) ([]User, error) {
|
||||
func userSuggestionNonRoot(ctx context.Context, user User, query_arg string) ([]*User, error) {
|
||||
users, err := models.Users.Query(
|
||||
sm.Where(
|
||||
psql.Or(
|
||||
|
|
@ -137,13 +137,14 @@ func userSuggestionNonRoot(ctx context.Context, user User, query_arg string) ([]
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("query users: %w", err)
|
||||
}
|
||||
results := make([]User, len(users))
|
||||
results := make([]*User, len(users))
|
||||
for i, user := range users {
|
||||
results[i] = toUser(user)
|
||||
u := toUser(user)
|
||||
results[i] = &u
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
func userSuggestionRoot(ctx context.Context, user User, query_arg string) ([]User, error) {
|
||||
func userSuggestionRoot(ctx context.Context, user User, query_arg string) ([]*User, error) {
|
||||
users, err := models.Users.Query(
|
||||
sm.Where(
|
||||
psql.Or(
|
||||
|
|
@ -171,14 +172,14 @@ func userSuggestionRoot(ctx context.Context, user User, query_arg string) ([]Use
|
|||
for _, org := range orgs {
|
||||
org_map[org.ID] = org
|
||||
}
|
||||
results := make([]User, len(users))
|
||||
results := make([]*User, len(users))
|
||||
for i, user := range users {
|
||||
u := toUser(user)
|
||||
org := org_map[user.OrganizationID]
|
||||
u.Organization = Organization{
|
||||
model: org,
|
||||
}
|
||||
results[i] = u
|
||||
results[i] = &u
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
|
|
|||
83
ts/store/users.ts
Normal file
83
ts/store/users.ts
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import { User } from "../types";
|
||||
import { SSEManager } from "../SSEManager";
|
||||
import { useUserStore } from "./user";
|
||||
|
||||
export const useUsersStore = defineStore("users", () => {
|
||||
// State
|
||||
const _byID = ref<Map<int, User>>(new Map());
|
||||
const all = ref<User[] | null>(null);
|
||||
const loading = ref(false);
|
||||
const error = ref(null);
|
||||
|
||||
// Subscription
|
||||
SSEManager.subscribe("*", (e) => {
|
||||
if (e.resource.startsWith("users")) {
|
||||
fetchAll();
|
||||
}
|
||||
});
|
||||
// Actions
|
||||
function byID(id: int) {
|
||||
return _byID.value.get(id);
|
||||
}
|
||||
async function fetchAll() {
|
||||
const userStore = useUserStore();
|
||||
if (userStore.urls == null) {
|
||||
throw new Error("can't fetch without user URL data");
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append("sort", "-created");
|
||||
//if (typeFilter.value) params.append("type", typeFilter.value);
|
||||
|
||||
const response = await fetch(`${userStore.urls.api.users}?${params}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
all.value = data.users;
|
||||
for (const u of data.users) {
|
||||
_byID.value.set(u.id, u);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error loading users:", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
async function fetchOne(id: int) {
|
||||
const userStore = useUserStore();
|
||||
if (userStore.urls == null) {
|
||||
throw new Error("can't fetch without user URL data");
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
try {
|
||||
const response = await fetch(`${userStore.urls.api.user}/${id}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
_byID.value.set(data.id, data);
|
||||
return data;
|
||||
} catch (err) {
|
||||
console.error("Error loading users:", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
all,
|
||||
// Actions
|
||||
byID,
|
||||
fetchAll,
|
||||
fetchOne,
|
||||
};
|
||||
});
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.tech-photo {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<div v-if="users" class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
|
|
@ -100,13 +100,17 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { useUsersStore } from "@/store/users";
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
|
|
@ -127,33 +131,10 @@ interface URLConfiguration {
|
|||
// }>()
|
||||
|
||||
// Reactive state
|
||||
const users = ref<User[]>([
|
||||
{
|
||||
id: 1,
|
||||
name: "John Davis",
|
||||
avatar: "https://randomuser.me/api/portraits/men/32.jpg",
|
||||
role: "Tech I",
|
||||
status: "Active",
|
||||
tags: [],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Sarah Johnson",
|
||||
avatar: "https://randomuser.me/api/portraits/women/65.jpg",
|
||||
role: "Tech III",
|
||||
status: "Active",
|
||||
tags: ["warrant service", "drone pilot"],
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Michael Chen",
|
||||
avatar: "https://randomuser.me/api/portraits/men/44.jpg",
|
||||
role: "Tech I",
|
||||
status: "Active",
|
||||
tags: ["drone pilot"],
|
||||
},
|
||||
]);
|
||||
|
||||
const usersStore = useUsersStore();
|
||||
const users = computed(() => {
|
||||
return usersStore.all;
|
||||
});
|
||||
const urlConfiguration = ref<URLConfiguration>({
|
||||
userAdd: "/configuration/user/add", // Update with your actual route
|
||||
});
|
||||
|
|
@ -181,7 +162,7 @@ const deactivateUser = (userId: number): void => {
|
|||
// Lifecycle hooks
|
||||
onMounted(() => {
|
||||
// Fetch users from API if needed
|
||||
// fetchUsers()
|
||||
usersStore.fetchAll();
|
||||
});
|
||||
|
||||
// Optional: API call example
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue